示例#1
0
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;
}
示例#2
0
文件: qhasharr.c 项目: Zengwn/qhttpd
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;
}
示例#3
0
/**
 * Put an object into table.
 *
 * @param tbl       qhasharr_t container pointer.
 * @param key       key string
 * @param value     value object data
 * @param size      size of value
 *
 * @return true if successful, otherwise returns false
 * @retval errno will be set in error condition.
 *  - ENOBUFS   : Table doesn't have enough space to store the object.
 *  - EINVAL    : Invalid argument.
 *  - EFAULT    : Unexpected error. Data structure is not constant.
*/
bool qhasharr_put(qhasharr_t *tbl, const char *key, size_t key_size, const void *value, size_t val_size)
{
    if (NULL == tbl || NULL == key || NULL == value)
    {
        errno = EINVAL;
        return false;
    }

    qhasharr_slot_t *_tbl_slots = NULL;
    qhasharr_init(tbl, &_tbl_slots);
    
    if (tbl->maxslots == 0)
    {
        return false;  
    }
    // check full
    if (tbl->usedslots >= tbl->maxslots)
    {
        errno = ENOBUFS;
        return false;
    }

    // get hash integer
    unsigned int hash = qhashmurmur3_32(key, key_size) % tbl->maxslots;

    // check, is slot empty
    if (_tbl_slots[hash].count == 0)   // empty slot
    {
        // put data
        if (_put_data(tbl, hash, hash, key, key_size, value, val_size, 1) == false)
        {
            return false;
        }
    }
    else if (_tbl_slots[hash].count > 0)     // same key or hash collision
    {
        // check same key;
        int idx = _get_idx(tbl, key, key_size, hash);
        if (idx >= 0)   // same key
        {
            // remove and recall
            if (!qhasharr_remove(tbl, key, key_size))
                return false;
            return qhasharr_put(tbl, key, key_size, value, val_size);
        }
        else     // no same key, just hash collision
        {
            // find empty slot
            int idx = _find_empty(tbl, hash);
            if (idx < 0)
            {
                errno = ENOBUFS;
                return false;
            }

            // put data. -1 is used for collision resolution (idx != hash);
            if (_put_data(tbl, idx, hash, key, key_size, value, val_size, -1) == false)
            {
                return false;
            }

            // increase counter from leading slot
            _tbl_slots[hash].count++;

            //      key, idx, hash, tbl->usedslots);
        }
    }
    else
    {
        // in case of -1 or -2, move it. -1 used for collision resolution,
        // -2 used for oversized value data.

        // find empty slot
        int idx = _find_empty(tbl, hash + 1);
        if (idx < 0)
        {
            errno = ENOBUFS;
            return false;
        }

        // move dup slot to empty
        _copy_slot(tbl, idx, hash);

        _remove_slot(tbl, hash);

        // in case of -2, adjust link of mother
        if (_tbl_slots[idx].count == -2)
        {
            _tbl_slots[ _tbl_slots[idx].hash ].link = idx;
            if (_tbl_slots[idx].link != -1)
            {
                _tbl_slots[ _tbl_slots[idx].link ].hash = idx;
            }
        }
        else if (_tbl_slots[idx].count == -1)
        {
            if (_tbl_slots[idx].link != -1)
            {
                _tbl_slots[ _tbl_slots[idx].link ].hash = idx;
            }
        }

        // store data
        if (_put_data(tbl, hash, hash, key, key_size, value, val_size, 1) == false)
        {
            return false;
        }
    }

    return true;
}
示例#4
0
文件: qhasharr.c 项目: Zengwn/qhttpd
/**
 * qhasharr->put(): Put an object into this table.
 *
 * @param tbl       qhasharr_t container pointer.
 * @param key       key string
 * @param value     value object data
 * @param size      size of value
 *
 * @return true if successful, otherwise returns false
 * @retval errno will be set in error condition.
 *  - ENOBUFS   : Table doesn't have enough space to store the object.
 *  - EINVAL    : Invalid argument.
 *  - EFAULT    : Unexpected error. Data structure is not constant.
*/
static bool put(qhasharr_t *tbl, const char *key, const void *value,
                size_t size)
{
    if (key == NULL || value == NULL) {
        errno = EINVAL;
        return false;
    }

    // check full
    if (tbl->usedslots >= tbl->maxslots) {
        DEBUG("hasharr: put %s - FULL", key);
        errno = ENOBUFS;
        return false;
    }

    // get hash integer
    unsigned int hash = qhashmurmur3_32(key, strlen(key)) % tbl->maxslots;

    // check, is slot empty
    if (tbl->slots[hash].count == 0) { // empty slot
        // put data
        if (_put_data(tbl, hash, hash, key, value, size, 1) == false) {
            DEBUG("hasharr: FAILED put(new) %s", key);
            return false;
        }
        DEBUG("hasharr: put(new) %s (idx=%d,hash=%u,tot=%d)",
              key, hash, hash, tbl->usedslots);
    } else if (tbl->slots[hash].count > 0) { // same key or hash collision
        // check same key;
        int idx = _get_idx(tbl, key, hash);
        if (idx >= 0) { // same key
            // remove and recall
            remove_(tbl, key);
            return put(tbl, key, value, size);
        } else { // no same key, just hash collision
            // find empty slot
            int idx = _find_empty(tbl, hash);
            if (idx < 0) {
                errno = ENOBUFS;
                return false;
            }

            // put data. -1 is used for collision resolution (idx != hash);
            if (_put_data(tbl, idx, hash, key, value, size, -1) == false) {
                DEBUG("hasharr: FAILED put(col) %s", key);
                return false;
            }

            // increase counter from leading slot
            tbl->slots[hash].count++;

            DEBUG("hasharr: put(col) %s (idx=%d,hash=%u,tot=%d)",
                  key, idx, hash, tbl->usedslots);
        }
    } else {
        // in case of -1 or -2, move it. -1 used for collision resolution,
        // -2 used for oversized value data.

        // find empty slot
        int idx = _find_empty(tbl, hash + 1);
        if (idx < 0) {
            errno = ENOBUFS;
            return false;
        }

        // move dup slot to empty
        _copy_slot(tbl, idx, hash);
        _remove_slot(tbl, hash);

        // in case of -2, adjust link of mother
        if (tbl->slots[idx].count == -2) {
            tbl->slots[ tbl->slots[idx].hash ].link = idx;
            if (tbl->slots[idx].link != -1) {
                tbl->slots[ tbl->slots[idx].link ].hash = idx;
            }
        }

        // store data
        if (_put_data(tbl, hash, hash, key, value, size, 1) == false) {
            DEBUG("hasharr: FAILED put(swp) %s", key);
            return false;
        }

        DEBUG("hasharr: put(swp) %s (idx=%u,hash=%u,tot=%d)",
              key, hash, hash, tbl->usedslots);
    }

    return true;
}