Exemple #1
0
static bool _remove_data(qhasharr_t *tbl, int idx)
{
    if (tbl->slots[idx].count == 0) {
        DEBUG("hasharr: BUG found.");
        errno = EFAULT;
        return false;
    }

    while (true) {
        int link = tbl->slots[idx].link;
        _remove_slot(tbl, idx);

        if (link == -1) break;

        idx = link;
    }

    // decrease stored key counter
    tbl->num--;

    return true;
}
Exemple #2
0
static bool _remove_data(qhasharr_t *tbl, int idx)
{
    qhasharr_slot_t *_tbl_slots = NULL;
    qhasharr_init(tbl, &_tbl_slots);
    int loop_count = 0;

    if (_tbl_slots[idx].count == 0)
    {
        errno = EFAULT;
        return false;
    }

    while (true)
    {
        int link = _tbl_slots[idx].link;
        _remove_slot(tbl, idx);

        if (link == -1) break;

        idx = link;

        /***************************/
        /*  should delete the tbl->num */
        /***************************/
        // check the dead lock
        loop_count++;
        if (loop_count > tbl->maxslots)
        {
            break;
        }
    }

    // decrease stored key counter
    tbl->num--;

    return true;
}
Exemple #3
0
/**
 * 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;
}
Exemple #4
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;
}
Exemple #5
0
/**
 * 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;
}
Exemple #6
0
/**
 * 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;
}