/* * Copyright (c) 2002, 2004, 2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * */ #include "sm/generic.h" SM_RCSID("@(#)$Id: t-rsct-0.c,v 1.15 2005/09/29 17:17:49 ca Exp $") #include #include "sm/memops.h" #include "sm/assert.h" #include "sm/rpool.h" #include "sm/rsct.h" #include "sm/test.h" #define CSIZE 13 #define HTSIZE 25 #define CHARS 64 #define NH 61 /* must be less than CHARS */ #define HLEN 12 #define KLEN (HLEN - 2) #define TYPES (2u) int Verbose = 0; char hashes[NH][HLEN]; typedef struct cdctx_S cdctx_T, *cdctx_P; struct cdctx_S { sm_rpool_P ctx_rpool; }; static bool chktype(const char *str, uint type) { uint i; for (i = 0; i < NH; i++) { if (strcmp(str, hashes[i]) == 0) return (type == (i % TYPES)); } return false; } static void * create(const char *key, uint len, void *value, void *ctx, uint type) { char *n; cdctx_P cdctx; sm_rpool_P rpool; cdctx = (cdctx_P) ctx; rpool = cdctx->ctx_rpool; n = sm_rpool_strdup(rpool, value); SM_TEST(chktype(key, type)); if (Verbose > 1) fprintf(stderr, "create(%s, %u)=%s\n", key, type, n == NULL ? "" : n); return n; } static sm_ret_T delete(void *data, void *ctx, uint type) { cdctx_P cdctx; sm_rpool_P rpool; cdctx = (cdctx_P) ctx; rpool = cdctx->ctx_rpool; SM_TEST(chktype((char *) data, type)); if (Verbose > 1) fprintf(stderr, "delete(%s, %u)\n", (char *)data, type); sm_rpool_free(rpool, data); return SM_SUCCESS; } static int cnt = 0; static void action(const char *key, const void *value, void *ctx, void *walk_ctx, uint type) { if (Verbose > 1) fprintf(stderr, "action(%s, %d)=%s\n", key, type, (char *) value); ++cnt; } static void testh(uint csize, uint htsize) { int i, j, k; rsct_P ct; void *ctx; char *res; sm_ret_T ret; #if SM_BHTABLE_PERF char buf[1024]; #endif cdctx_T cdctx; cdctx.ctx_rpool = NULL; ctx = (void *) &cdctx; ct = rsct_new(csize, htsize, create, delete, ctx); SM_TEST(ct != NULL); if (ct == NULL) return; for (i = 0; i < NH; i++) { for (j = 0; j < HLEN; j++) { hashes[i][j] = 'A' + ((i + j) % CHARS); } hashes[i][HLEN - 1] = '\0'; } /* add CSIZE entries to RSC */ for (j = 0; j < CSIZE; j++) { i = j % NH; ret = rsct_add(ct, false, i % TYPES, hashes[i], KLEN, hashes[i], (void **)&res, THR_LOCK_UNLOCK); SM_TEST(!sm_is_err(ret)); SM_TEST(strcmp(res, hashes[i]) == 0); cnt = 0; rsct_walk(ct, action, (void *) 0, THR_LOCK_UNLOCK); SM_TEST(cnt == j + 1); k = rsct_usage(ct); SM_TEST(k == (int) ((j + 1) * 100 / CSIZE)); } /* make sure the rest isn't in the RSC */ for (k = CSIZE; k < NH; k++) { res = (char *) rsct_lookup(ct, hashes[k], KLEN, THR_LOCK_UNLOCK); SM_TEST(res == NULL); if (Verbose > 0 && res != NULL) fprintf(stderr, "j=%d, k=%d, res=%s\n", j, k, res); k = rsct_usage(ct); SM_TEST(k == 100); } /* check entries in RSC */ for (j = 0; j < CSIZE; j++) { i = j % NH; res = (char *) rsct_lookup(ct, hashes[i], KLEN, THR_LOCK_UNLOCK); SM_TEST(strcmp(res, hashes[i]) == 0); } for (j = 0; j < CSIZE * 3; j++) { i = j % NH; ret = rsct_add(ct, true, i % TYPES, hashes[i], KLEN, hashes[i], (void **)&res, THR_LOCK_UNLOCK); SM_TEST(!sm_is_err(ret)); SM_TEST(strcmp(res, hashes[i]) == 0); cnt = 0; rsct_walk(ct, action, (void *) 0, THR_LOCK_UNLOCK); SM_TEST(cnt == CSIZE); /* make sure that the other entries are not in the cache */ if (j > CSIZE) { for (k = j + 1; k < NH; k++) { res = (char *) rsct_lookup(ct, hashes[k], KLEN, THR_LOCK_UNLOCK); SM_TEST(res == NULL); if (Verbose > 0 && res != NULL) fprintf(stderr, "j=%d, k=%d, res=%s\n", j, k, res); } } k = rsct_usage(ct); SM_TEST(k == 100); } /* XXX need a better test that shows the MRU feature */ #if SM_BHTABLE_PERF if (Verbose > 0) { rsct_stats(ct, buf, sizeof(buf)); printf("%s", buf); } #endif /* SM_BHTABLE_PERF */ rsct_free(ct); } int main(int argc, char *argv[]) { int c; uint csize, htsize; csize = CSIZE; htsize = HTSIZE; while ((c = getopt(argc, argv, "c:h:V")) != -1) { switch (c) { case 'c': csize = (uint) atoi(optarg); break; case 'h': htsize = (uint) atoi(optarg); break; case 'V': ++Verbose; break; default: return(1); } } sm_test_begin(argc, argv, "test rsct 0"); testh(csize, htsize); return sm_test_end(); }