/** * Generate unique id * * @param seed additional seed string. this can be NULL * * @return a pointer of malloced string * * @note * The length of returned string is 32+1 bytes long including terminating NULL * character. It's a good idea to call srand() once before calling this because * it uses rand(). */ char *qstrunique(const char *seed) { long int usec; #ifdef _WIN32 FILETIME ft; GetSystemTimeAsFileTime(&ft); usec = ft.dwLowDateTime % 1000000; #else struct timeval tv; gettimeofday(&tv, NULL); usec = tv.tv_usec; #endif char uniquestr[128]; snprintf(uniquestr, sizeof(uniquestr), "%u%d%lu%ld%s", getpid(), rand(), (unsigned long int)time(NULL), usec, (seed != NULL) ? seed : ""); unsigned char md5hash[16]; qhashmd5(uniquestr, strlen(uniquestr), md5hash); char *md5ascii = qhex_encode(md5hash, 16); return md5ascii; }
static int _get_idx(qhasharr_t *tbl, const char *key, size_t key_size, unsigned int hash) { if (NULL == tbl || NULL == key) return -1; qhasharr_slot_t *_tbl_slots = NULL; qhasharr_init(tbl, &_tbl_slots); if (_tbl_slots[hash].count > 0) { unsigned int idx; int count = 0; for (count = 0, idx = hash; count < _tbl_slots[hash].count; ) { if (_tbl_slots[idx].hash == hash && (_tbl_slots[idx].count > 0 || _tbl_slots[idx].count == -1)) { // same hash count++; // first check key length if (key_size == _tbl_slots[idx].data.pair.keylen) { if (key_size <= _Q_HASHARR_KEYSIZE) { // original key is stored if (!memcmp(key, _tbl_slots[idx].data.pair.key, key_size)) { return idx; } } else { // key is truncated, compare MD5 also. unsigned char keymd5[16]; qhashmd5(key, key_size, keymd5); if (!memcmp(key, _tbl_slots[idx].data.pair.key, _Q_HASHARR_KEYSIZE) && !memcmp(keymd5, _tbl_slots[idx].data.pair.keymd5, 16)) { return idx; } } } } // increase idx idx++; if (idx >= (unsigned int)tbl->maxslots) idx = 0; // check loop if (idx == hash) break; continue; } } return -1; }
static int get_idx(qhasharr_t *tbl, const void *name, size_t namesize, uint32_t hash) { qhasharr_data_t *tbldata = tbl->data; qhasharr_slot_t *tblslots = get_slots(tbl); if (tblslots[hash].count > 0) { int count, idx; for (count = 0, idx = hash; count < tblslots[hash].count;) { if (tblslots[idx].hash == hash && (tblslots[idx].count > 0 || tblslots[idx].count == COLLISION_MARK)) { // same hash count++; // is same key? // first check key length if (namesize == tblslots[idx].data.pair.namesize) { if (namesize <= Q_HASHARR_NAMESIZE) { // original key is stored if (!memcmp(name, tblslots[idx].data.pair.name, namesize)) { return idx; } } else { // key is truncated, compare MD5 also. unsigned char namemd5[16]; qhashmd5(name, namesize, namemd5); if (!memcmp(name, tblslots[idx].data.pair.name, Q_HASHARR_NAMESIZE) && !memcmp(namemd5, tblslots[idx].data.pair.namemd5, 16)) { return idx; } } } } // increase idx idx++; if (idx >= tbldata->maxslots) idx = 0; // check loop if (idx == hash) break; continue; } } return -1; }
static int _get_idx(qhasharr_t *tbl, const char *key, unsigned int hash) { qhasharr_data_t *data = tbl->data; if (data->slots[hash].count > 0) { int count, idx; for (count = 0, idx = hash; count < data->slots[hash].count;) { if (data->slots[idx].hash == hash && (data->slots[idx].count > 0 || data->slots[idx].count == -1)) { // same hash count++; // is same key? size_t keylen = strlen(key); // first check key length if (keylen == data->slots[idx].data.pair.keylen) { if (keylen <= _Q_HASHARR_KEYSIZE) { // original key is stored if (!memcmp(key, data->slots[idx].data.pair.key, keylen)) { return idx; } } else { // key is truncated, compare MD5 also. unsigned char keymd5[16]; qhashmd5(key, keylen, keymd5); if (!memcmp(key, data->slots[idx].data.pair.key, _Q_HASHARR_KEYSIZE) && !memcmp(keymd5, data->slots[idx].data.pair.keymd5, 16)) { return idx; } } } } // increase idx idx++; if (idx >= data->maxslots) idx = 0; // check loop if (idx == hash) break; continue; } } return -1; }
static bool _put_data(qhasharr_t *tbl, int idx, unsigned int hash, const char *key, size_t key_size, const void *value, size_t val_size, int count) { size_t tmp_size = 0; qhasharr_slot_t *_tbl_slots = NULL; qhasharr_init(tbl, &_tbl_slots); // check if used if (_tbl_slots[idx].count != 0) { errno = EFAULT; return false; } unsigned char keymd5[16]; qhashmd5(key, key_size, keymd5); // store key _tbl_slots[idx].count = count; _tbl_slots[idx].hash = hash; tmp_size = (key_size <= _Q_HASHARR_KEYSIZE) ? key_size : _Q_HASHARR_KEYSIZE; memcpy(_tbl_slots[idx].data.pair.key, key, tmp_size); memcpy((char *)_tbl_slots[idx].data.pair.keymd5, (char *)keymd5, 16); _tbl_slots[idx].data.pair.keylen = key_size; _tbl_slots[idx].link = -1; // store value int newidx; size_t savesize; for (newidx = idx, savesize = 0; savesize < val_size;) { if (savesize > 0) // find next empty slot { int tmpidx = _find_empty(tbl, newidx + 1); if (tmpidx < 0) { _remove_data(tbl, idx); errno = ENOBUFS; return false; } // clear & set memset((void *)(&_tbl_slots[tmpidx]), '\0', sizeof(qhasharr_slot_t)); _tbl_slots[tmpidx].count = -2; // extended data block _tbl_slots[tmpidx].hash = newidx; // prev link _tbl_slots[tmpidx].link = -1; // end block mark _tbl_slots[tmpidx].size = 0; _tbl_slots[newidx].link = tmpidx; // link chain newidx = tmpidx; } // copy data size_t copysize = val_size - savesize; if (_tbl_slots[newidx].count == -2) { // extended value //if (copysize > sizeof(struct _Q_HASHARR_SLOT_EXT)) { // copysize = sizeof(struct _Q_HASHARR_SLOT_EXT); //} if (copysize > sizeof(union _slot_data)) { copysize = sizeof(union _slot_data); } memcpy(_tbl_slots[newidx].data.ext.value, (char*)value + savesize, copysize); } else { // first slot if (copysize > _Q_HASHARR_VALUESIZE) { copysize = _Q_HASHARR_VALUESIZE; } memcpy(_tbl_slots[newidx].data.pair.value, (char*)value + savesize, copysize); // increase stored key counter tbl->num++; } _tbl_slots[newidx].size = copysize; savesize += copysize; // increase used slot counter tbl->usedslots++; } return true; }
static bool _put_data(qhasharr_t *tbl, int idx, unsigned int hash, const char *key, const void *value, size_t size, int count) { // check if used if (tbl->slots[idx].count != 0) { DEBUG("hasharr: BUG found."); errno = EFAULT; return false; } size_t keylen = strlen(key); unsigned char keymd5[16]; qhashmd5(key, keylen, keymd5); // store key tbl->slots[idx].count = count; tbl->slots[idx].hash = hash; strncpy(tbl->slots[idx].data.pair.key, key, _Q_HASHARR_KEYSIZE); memcpy((char *)tbl->slots[idx].data.pair.keymd5, (char *)keymd5, 16); tbl->slots[idx].data.pair.keylen = keylen; tbl->slots[idx].link = -1; // store value int newidx; size_t savesize; for (newidx = idx, savesize = 0; savesize < size;) { if (savesize > 0) { // find next empty slot int tmpidx = _find_empty(tbl, newidx + 1); if (tmpidx < 0) { DEBUG("hasharr: Can't expand slot for key %s.", key); _remove_data(tbl, idx); errno = ENOBUFS; return false; } // clear & set memset((void *)(&tbl->slots[tmpidx]), '\0', sizeof(qhasharr_slot_t)); tbl->slots[tmpidx].count = -2; // extended data block tbl->slots[tmpidx].hash = newidx; // prev link tbl->slots[tmpidx].link = -1; // end block mark tbl->slots[tmpidx].size = 0; tbl->slots[newidx].link = tmpidx; // link chain DEBUG("hasharr: slot %d is linked to slot %d for key %s.", tmpidx, newidx, key); newidx = tmpidx; } // copy data size_t copysize = size - savesize; if (tbl->slots[newidx].count == -2) { // extended value if (copysize > sizeof(struct _Q_HASHARR_SLOT_EXT)) { copysize = sizeof(struct _Q_HASHARR_SLOT_EXT); } memcpy(tbl->slots[newidx].data.ext.value, value + savesize, copysize); } else { // first slot if (copysize > _Q_HASHARR_VALUESIZE) { copysize = _Q_HASHARR_VALUESIZE; } memcpy(tbl->slots[newidx].data.pair.value, value + savesize, copysize); // increase stored key counter tbl->num++; } tbl->slots[newidx].size = copysize; savesize += copysize; // increase used slot counter tbl->usedslots++; } return true; }
static bool put_data(qhasharr_t *tbl, int idx, uint32_t hash, const void *name, size_t namesize, const void *data, size_t datasize, int count) { qhasharr_data_t *tbldata = tbl->data; qhasharr_slot_t *tblslots = get_slots(tbl); assert(tblslots[idx].count == 0); unsigned char namemd5[16]; qhashmd5(name, namesize, namemd5); // store name tblslots[idx].count = count; tblslots[idx].hash = hash; memcpy(tblslots[idx].data.pair.name, name, (namesize < Q_HASHARR_NAMESIZE) ? namesize : Q_HASHARR_NAMESIZE); memcpy((char *) tblslots[idx].data.pair.namemd5, (char *) namemd5, 16); tblslots[idx].data.pair.namesize = namesize; tblslots[idx].link = -1; // store data int newidx; size_t savesize; for (newidx = idx, savesize = 0; savesize < datasize;) { if (savesize > 0) { // find next empty slot int tmpidx = find_avail(tbl, newidx + 1); if (tmpidx < 0) { remove_data(tbl, idx); errno = ENOBUFS; return false; } // clear & set memset((void *) (&tblslots[tmpidx]), '\0', sizeof(qhasharr_slot_t)); tblslots[tmpidx].count = EXTBLOCK_MARK; // extended data block tblslots[tmpidx].hash = newidx; // previous link tblslots[tmpidx].link = -1; // end block mark tblslots[tmpidx].datasize = 0; tblslots[newidx].link = tmpidx; // link chain newidx = tmpidx; } // copy data size_t copysize = datasize - savesize; if (tblslots[newidx].count == EXTBLOCK_MARK) { // extended value if (copysize > sizeof(struct Q_HASHARR_SLOT_EXT)) { copysize = sizeof(struct Q_HASHARR_SLOT_EXT); } memcpy(tblslots[newidx].data.ext.data, data + savesize, copysize); } else { // first slot if (copysize > Q_HASHARR_DATASIZE) { copysize = Q_HASHARR_DATASIZE; } memcpy(tblslots[newidx].data.pair.data, data + savesize, copysize); // increase stored key counter tbldata->num++; } tblslots[newidx].datasize = copysize; savesize += copysize; // increase used slot counter tbldata->usedslots++; } #ifdef QHASHARR_TIMESTAMP time(&tblslots[idx].timestamp); #endif return true; }