예제 #1
0
파일: qhasharr.c 프로젝트: stgrandet/QConf
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
파일: qhasharr.c 프로젝트: stgrandet/QConf
/**
 * Remove an object from this table.
 *
 * @param tbl       qhasharr_t container pointer.
 * @param key       key string
 *
 * @return true if successful, otherwise(not found) returns false
 * @retval errno will be set in error condition.
 *  - ENOENT    : No such key found.
 *  - EINVAL    : Invald argument.
 *  - EFAULT        : Unexpected error. Data structure is not constant.
 */
bool qhasharr_remove(qhasharr_t *tbl, const char *key, size_t key_size)
{
    if (NULL == tbl || NULL == key)
    {
        errno = EINVAL;
        return false;
    }

    qhasharr_slot_t *_tbl_slots = NULL;
    qhasharr_init(tbl, &_tbl_slots);

    if (tbl->maxslots == 0)
    {
        return false;  
    }

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

    int idx = _get_idx(tbl, key, key_size, hash);
    if (idx < 0)
    {
        errno = ENOENT;
        return false;
    }

    if (_tbl_slots[idx].count == 1)
    {
        // just remove
        _remove_data(tbl, idx);
    }
    else if (_tbl_slots[idx].count > 1)     // leading slot and has dup
    {
        // find dup
        int idx2;
        for (idx2 = idx + 1; ; idx2++)
        {
            if (idx2 >= tbl->maxslots) idx2 = 0;
            if (idx2 == idx)
            {
                errno = EFAULT;
                return false;
            }
            if (_tbl_slots[idx2].count == -1 && _tbl_slots[idx2].hash == hash)
            {
                break;
            }
        }

        // move to leading slot
        int backupcount = _tbl_slots[idx].count;

        _remove_data(tbl, idx); // remove leading data

        _copy_slot(tbl, idx, idx2); // copy slot
        _remove_slot(tbl, idx2); // remove moved slot

        _tbl_slots[idx].count = backupcount - 1; // adjust collision counter
        if (_tbl_slots[idx].link != -1)
        {
            _tbl_slots[_tbl_slots[idx].link].hash = idx;
        }
    }
    else if (_tbl_slots[idx].count == -1)   // in case of -1. used for collision resolution
    {
          // decrease counter from leading slot
          if (_tbl_slots[ _tbl_slots[idx].hash ].count <= 1)
          {
              errno = EFAULT;
              return false;
          }
          _tbl_slots[ _tbl_slots[idx].hash ].count--;

          // remove data
          _remove_data(tbl, idx);
    }
    else 
    {
        errno = ENOENT;
        return false;
    }

    return true;
}
예제 #4
0
파일: qhasharr.c 프로젝트: Zengwn/qhttpd
/**
 * qhasharr->remove(): Remove an object from this table.
 *
 * @param tbl       qhasharr_t container pointer.
 * @param key       key string
 *
 * @return true if successful, otherwise(not found) returns false
 * @retval errno will be set in error condition.
 *  - ENOENT    : No such key found.
 *  - EINVAL    : Invald argument.
 *  - EFAULT        : Unexpected error. Data structure is not constant.
 */
static bool remove_(qhasharr_t *tbl, const char *key)
{
    if (key == NULL) {
        errno = EINVAL;
        return false;
    }

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

    int idx = _get_idx(tbl, key, hash);
    if (idx < 0) {
        DEBUG("not found %s", key);
        errno = ENOENT;
        return false;
    }

    if (tbl->slots[idx].count == 1) {
        // just remove
        _remove_data(tbl, idx);
        DEBUG("hasharr: rem %s (idx=%d,tot=%d)", key, idx, tbl->usedslots);
    } else if (tbl->slots[idx].count > 1) { // leading slot and has dup
        // find dup
        int idx2;
        for (idx2 = idx + 1; ; idx2++) {
            if (idx2 >= tbl->maxslots) idx2 = 0;
            if (idx2 == idx) {
                DEBUG("hasharr: [BUG] failed to remove dup key %s.", key);
                errno = EFAULT;
                return false;
            }
            if (tbl->slots[idx2].count == -1 && tbl->slots[idx2].hash == hash) {
                break;
            }
        }

        // move to leading slot
        int backupcount = tbl->slots[idx].count;
        _remove_data(tbl, idx); // remove leading data
        _copy_slot(tbl, idx, idx2); // copy slot
        _remove_slot(tbl, idx2); // remove moved slot

        tbl->slots[idx].count = backupcount - 1; // adjust collision counter
        if (tbl->slots[idx].link != -1) {
            tbl->slots[tbl->slots[idx].link].hash = idx;
        }

        DEBUG("hasharr: rem(lead) %s (idx=%d,tot=%d)",
              key, idx, tbl->usedslots);
    } else { // in case of -1. used for collision resolution
        // decrease counter from leading slot
        if (tbl->slots[ tbl->slots[idx].hash ].count <= 1) {
            DEBUG("hasharr: [BUG] failed to remove  %s. "
                  "counter of leading slot mismatch.", key);
            errno = EFAULT;
            return false;
        }
        tbl->slots[ tbl->slots[idx].hash ].count--;

        // remove data
        _remove_data(tbl, idx);
        DEBUG("hasharr: rem(dup) %s (idx=%d,tot=%d)", key, idx, tbl->usedslots);
    }

    return true;
}