⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 assoc.c

📁 memcached是一个高性能的分布式的内存对象缓存系统
💻 C
📖 第 1 页 / 共 2 页
字号:
  final(a,b,c);  return c;             /* zero length strings require no mixing */}#elif HASH_BIG_ENDIAN == 1/* * hashbig(): * This is the same as hashword() on big-endian machines.  It is different * from hashlittle() on all machines.  hashbig() takes advantage of * big-endian byte ordering. */uint32_t hash( const void *key, size_t length, const uint32_t initval){  uint32_t a,b,c;  union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */  /* Set up the internal state */  a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;  u.ptr = key;  if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) {    const uint32_t *k = key;                           /* read 32-bit chunks */#ifdef VALGRIND    const uint8_t  *k8;#endif // ifdef VALGRIND    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */    while (length > 12)    {      a += k[0];      b += k[1];      c += k[2];      mix(a,b,c);      length -= 12;      k += 3;    }    /*----------------------------- handle the last (probably partial) block */    /*     * "k[2]<<8" actually reads beyond the end of the string, but     * then shifts out the part it's not allowed to read.  Because the     * string is aligned, the illegal read is in the same word as the     * rest of the string.  Every machine with memory protection I've seen     * does it on word boundaries, so is OK with this.  But VALGRIND will     * still catch it and complain.  The masking trick does make the hash     * noticably faster for short strings (like English words).     */#ifndef VALGRIND    switch(length)    {    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;    case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;    case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;    case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break;    case 8 : b+=k[1]; a+=k[0]; break;    case 7 : b+=k[1]&0xffffff00; a+=k[0]; break;    case 6 : b+=k[1]&0xffff0000; a+=k[0]; break;    case 5 : b+=k[1]&0xff000000; a+=k[0]; break;    case 4 : a+=k[0]; break;    case 3 : a+=k[0]&0xffffff00; break;    case 2 : a+=k[0]&0xffff0000; break;    case 1 : a+=k[0]&0xff000000; break;    case 0 : return c;              /* zero length strings require no mixing */    }#else  /* make valgrind happy */    k8 = (const uint8_t *)k;    switch(length)                   /* all the case statements fall through */    {    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;    case 11: c+=((uint32_t)k8[10])<<8;  /* fall through */    case 10: c+=((uint32_t)k8[9])<<16;  /* fall through */    case 9 : c+=((uint32_t)k8[8])<<24;  /* fall through */    case 8 : b+=k[1]; a+=k[0]; break;    case 7 : b+=((uint32_t)k8[6])<<8;   /* fall through */    case 6 : b+=((uint32_t)k8[5])<<16;  /* fall through */    case 5 : b+=((uint32_t)k8[4])<<24;  /* fall through */    case 4 : a+=k[0]; break;    case 3 : a+=((uint32_t)k8[2])<<8;   /* fall through */    case 2 : a+=((uint32_t)k8[1])<<16;  /* fall through */    case 1 : a+=((uint32_t)k8[0])<<24; break;    case 0 : return c;    }#endif /* !VALGRIND */  } else {                        /* need to read the key one byte at a time */    const uint8_t *k = key;    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */    while (length > 12)    {      a += ((uint32_t)k[0])<<24;      a += ((uint32_t)k[1])<<16;      a += ((uint32_t)k[2])<<8;      a += ((uint32_t)k[3]);      b += ((uint32_t)k[4])<<24;      b += ((uint32_t)k[5])<<16;      b += ((uint32_t)k[6])<<8;      b += ((uint32_t)k[7]);      c += ((uint32_t)k[8])<<24;      c += ((uint32_t)k[9])<<16;      c += ((uint32_t)k[10])<<8;      c += ((uint32_t)k[11]);      mix(a,b,c);      length -= 12;      k += 12;    }    /*-------------------------------- last block: affect all 32 bits of (c) */    switch(length)                   /* all the case statements fall through */    {    case 12: c+=k[11];    case 11: c+=((uint32_t)k[10])<<8;    case 10: c+=((uint32_t)k[9])<<16;    case 9 : c+=((uint32_t)k[8])<<24;    case 8 : b+=k[7];    case 7 : b+=((uint32_t)k[6])<<8;    case 6 : b+=((uint32_t)k[5])<<16;    case 5 : b+=((uint32_t)k[4])<<24;    case 4 : a+=k[3];    case 3 : a+=((uint32_t)k[2])<<8;    case 2 : a+=((uint32_t)k[1])<<16;    case 1 : a+=((uint32_t)k[0])<<24;             break;    case 0 : return c;    }  }  final(a,b,c);  return c;}#else // HASH_XXX_ENDIAN == 1#error Must define HASH_BIG_ENDIAN or HASH_LITTLE_ENDIAN#endif // hash_XXX_ENDIAN == 1typedef  unsigned long  int  ub4;   /* unsigned 4-byte quantities */typedef  unsigned       char ub1;   /* unsigned 1-byte quantities *//* how many powers of 2's worth of buckets we use */static int hashpower = 16;#define hashsize(n) ((ub4)1<<(n))#define hashmask(n) (hashsize(n)-1)/* Main hash table. This is where we look except during expansion. */static item** primary_hashtable = 0;/* * Previous hash table. During expansion, we look here for keys that haven't * been moved over to the primary yet. */static item** old_hashtable = 0;/* Number of items in the hash table. */static int hash_items = 0;/* Flag: Are we in the middle of expanding now? */static int expanding = 0;/* * During expansion we migrate values with bucket granularity; this is how * far we've gotten so far. Ranges from 0 .. hashsize(hashpower - 1) - 1. */static int expand_bucket = 0;void assoc_init(void) {    unsigned int hash_size = hashsize(hashpower) * sizeof(void*);    primary_hashtable = malloc(hash_size);    if (! primary_hashtable) {        fprintf(stderr, "Failed to init hashtable.\n");        exit(EXIT_FAILURE);    }    memset(primary_hashtable, 0, hash_size);}item *assoc_find(const char *key, const size_t nkey) {    uint32_t hv = hash(key, nkey, 0);    item *it;    int oldbucket;    if (expanding &&        (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket)    {        it = old_hashtable[oldbucket];    } else {        it = primary_hashtable[hv & hashmask(hashpower)];    }    while (it) {        if ((nkey == it->nkey) &&            (memcmp(key, ITEM_key(it), nkey) == 0)) {            return it;        }        it = it->h_next;    }    return 0;}/* returns the address of the item pointer before the key.  if *item == 0,   the item wasn't found */static item** _hashitem_before (const char *key, const size_t nkey) {    uint32_t hv = hash(key, nkey, 0);    item **pos;    int oldbucket;    if (expanding &&        (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket)    {        pos = &old_hashtable[oldbucket];    } else {        pos = &primary_hashtable[hv & hashmask(hashpower)];    }    while (*pos && ((nkey != (*pos)->nkey) || memcmp(key, ITEM_key(*pos), nkey))) {        pos = &(*pos)->h_next;    }    return pos;}/* grows the hashtable to the next power of 2. */static void assoc_expand(void) {    old_hashtable = primary_hashtable;    primary_hashtable = calloc(hashsize(hashpower + 1), sizeof(void *));    if (primary_hashtable) {        if (settings.verbose > 1)            fprintf(stderr, "Hash table expansion starting\n");        hashpower++;        expanding = 1;        expand_bucket = 0;        do_assoc_move_next_bucket();    } else {        primary_hashtable = old_hashtable;        /* Bad news, but we can keep running. */    }}/* migrates the next bucket to the primary hashtable if we're expanding. */void do_assoc_move_next_bucket(void) {    item *it, *next;    int bucket;    if (expanding) {        for (it = old_hashtable[expand_bucket]; NULL != it; it = next) {            next = it->h_next;            bucket = hash(ITEM_key(it), it->nkey, 0) & hashmask(hashpower);            it->h_next = primary_hashtable[bucket];            primary_hashtable[bucket] = it;        }        old_hashtable[expand_bucket] = NULL;        expand_bucket++;        if (expand_bucket == hashsize(hashpower - 1)) {            expanding = 0;            free(old_hashtable);            if (settings.verbose > 1)                fprintf(stderr, "Hash table expansion done\n");        }    }}/* Note: this isn't an assoc_update.  The key must not already exist to call this */int assoc_insert(item *it) {    uint32_t hv;    int oldbucket;    assert(assoc_find(ITEM_key(it), it->nkey) == 0);  /* shouldn't have duplicately named things defined */    hv = hash(ITEM_key(it), it->nkey, 0);    if (expanding &&        (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket)    {        it->h_next = old_hashtable[oldbucket];        old_hashtable[oldbucket] = it;    } else {        it->h_next = primary_hashtable[hv & hashmask(hashpower)];        primary_hashtable[hv & hashmask(hashpower)] = it;    }    hash_items++;    if (! expanding && hash_items > (hashsize(hashpower) * 3) / 2) {        assoc_expand();    }    return 1;}void assoc_delete(const char *key, const size_t nkey) {    item **before = _hashitem_before(key, nkey);    if (*before) {        item *nxt = (*before)->h_next;        (*before)->h_next = 0;   /* probably pointless, but whatever. */        *before = nxt;        hash_items--;        return;    }    /* Note:  we never actually get here.  the callers don't delete things       they can't find. */    assert(*before != 0);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -