Beispiel #1
0
int l_remove(node_t *head, key_t key) {
    node_t *pred, *item, *sitem;
    while (TRUE) {
        if (!l_find(&pred, &item, head, key)) {
            trace("remove item failed %d\n", key);
            return FALSE;
        }
        sitem = STRIP_MARK(item);
        node_t *inext = sitem->next;
        /* 先标记再删除 */
        if (!CAS(&sitem->next, inext, MARK(inext))) {
            trace("cas item %p mark failed\n", sitem->next);
            continue;
        }
        sitem->val = NULL_VALUE;
        int tag = GET_TAG(pred->next) + 1;
        if (CAS(&pred->next, item, TAG(STRIP_MARK(sitem->next), tag))) {
            trace("remove item %p success\n", item);
            haz_defer_free(sitem);
            return TRUE;
        }
        trace("cas item remove item %p failed\n", item);
    }
    return FALSE;
}
Beispiel #2
0
value_t l_lookup(node_t *head, key_t key) {
    node_t *pred, *item;
    if (l_find(&pred, &item, head, key)) {
        return STRIP_MARK(item)->val;
    }
    return NULL_VALUE;
}
Beispiel #3
0
int l_find(node_t **pred_ptr, node_t **item_ptr, node_t *head, key_t key) {
    node_t *pred = head;
    node_t *item = head->next;
    /* pred和next会被使用,所以进行标记 */
    hazard_t *hp1 = haz_get(0);
    hazard_t *hp2 = haz_get(1);
    while (item) {
        node_t *sitem = STRIP_MARK(item);
        haz_set_ptr(hp1, STRIP_MARK(pred));
        haz_set_ptr(hp2, STRIP_MARK(item));
        /* 
         如果已被标记,那么紧接着item可能被移除链表甚至释放,所以需要重头查找
        */
        if (HAS_MARK(sitem->next)) { 
            trace("item->next %p %p marked, retry\n", item, sitem->next);
            return l_find(pred_ptr, item_ptr, head, key);
        }
        int d = KEY_CMP(sitem->key, key);
        if (d >= 0) {
            trace("item %p match key %d, pred %p\n", item, key, pred);
            *pred_ptr = pred;
            *item_ptr = item;
            return d == 0 ? TRUE : FALSE;
        }
        pred = item;
        item = sitem->next;
    } 
    trace("not found key %d\n", key);
    *pred_ptr = pred;
    *item_ptr = NULL;
    return FALSE;
}
Beispiel #4
0
/*
  DESCRIPTION
    deletes a node as identified by hashnr/keey/keylen from the list
    that starts from 'head'

  RETURN
    0 - ok
    1 - not found

  NOTE
    it uses pins[0..2], on return all pins are removed.
*/
static int l_delete(LF_SLIST * volatile *head, CHARSET_INFO *cs, uint32 hashnr,
                   const uchar *key, uint keylen, LF_PINS *pins)
{
  CURSOR cursor;
  int res;

  for (;;)
  {
    if (!l_find(head, cs, hashnr, key, keylen, &cursor, pins))
    {
      res= 1; /* not found */
      break;
    }
    else
    {
      /* mark the node deleted */
      if (my_atomic_casptr((void **) (char*) &(cursor.curr->link),
                           (void **) (char*) &cursor.next,
                           (void *)(((intptr)cursor.next) | 1)))
      {
        /* and remove it from the list */
        if (my_atomic_casptr((void **)cursor.prev,
                             (void **)(char*)&cursor.curr, cursor.next))
          _lf_alloc_free(pins, cursor.curr);
        else
        {
          /*
            somebody already "helped" us and removed the node ?
            Let's check if we need to help that someone too!
            (to ensure the number of "set DELETED flag" actions
            is equal to the number of "remove from the list" actions)
          */
          l_find(head, cs, hashnr, key, keylen, &cursor, pins);
        }
        res= 0;
        break;
      }
    }
  }
  _lf_unpin(pins, 0);
  _lf_unpin(pins, 1);
  _lf_unpin(pins, 2);
  return res;
}
Beispiel #5
0
/*
  Test the find function.
*/
void find_test(linked_list list, int item, int result) {
  link l = l_find(list, item);

  if (l == NULL && result != 0) {
    printf("Find test failed: expected to find %d, got NULL.\n", item);
  }
  else if (l != NULL && result == 0) {
    printf("Find test failed: expected NULL when finding %d.\n", item);
  }
  else if (l != NULL && l->item != item) {
    printf("Find test failed: expected %d, found %d.\n", item, l->item);
  }
}
Beispiel #6
0
/*
  DESCRIPTION
    searches for a node as identified by hashnr/keey/keylen in the list
    that starts from 'head'

  RETURN
    0 - not found
    node - found

  NOTE
    it uses pins[0..2], on return the pin[2] keeps the node found
    all other pins are removed.
*/
static LF_SLIST *l_search(LF_SLIST * volatile *head, CHARSET_INFO *cs,
                         uint32 hashnr, const uchar *key, uint keylen,
                         LF_PINS *pins)
{
  CURSOR cursor;
  int res= l_find(head, cs, hashnr, key, keylen, &cursor, pins);
  if (res)
    _lf_pin(pins, 2, cursor.curr);
  else
    _lf_unpin(pins, 2);
  _lf_unpin(pins, 1);
  _lf_unpin(pins, 0);
  return res ? cursor.curr : 0;
}
Beispiel #7
0
static int add_section_label(struct label *l, const char *name,
			     const char *attribute, uint64_t value,
			     struct label **length)
{
	char label[255];
	int errcode;

	errcode = create_section_label_name(label, sizeof(label), name,
					    attribute);
	if (errcode < 0)
		return errcode;

	errcode = l_append(l, label, value);
	if (errcode < 0)
		return errcode;

	if (length)
		*length = l_find(l, label);

	return 0;
}
Beispiel #8
0
/**
   Iterate over all elements in hash and call function with the element

   @note
   If one of 'action' invocations returns 1 the iteration aborts.
   'action' might see some elements twice!

   @retval 0    ok
   @retval 1    error (action returned 1)
*/
int lf_hash_iterate(LF_HASH *hash, LF_PINS *pins,
                    my_hash_walk_action action, void *argument)
{
  CURSOR cursor;
  uint bucket= 0;
  int res;
  LF_SLIST * volatile *el;

  el= lf_dynarray_lvalue(&hash->array, bucket);
  if (unlikely(!el))
    return 0; /* if there's no bucket==0, the hash is empty */
  if (*el == NULL && unlikely(initialize_bucket(hash, el, bucket, pins)))
    return 0; /* if there's no bucket==0, the hash is empty */

  res= l_find(el, 0, 0, (uchar*)argument, 0, &cursor, pins, action);

  lf_unpin(pins, 2);
  lf_unpin(pins, 1);
  lf_unpin(pins, 0);
  return res;
}
Beispiel #9
0
/*
  DESCRIPTION
    insert a 'node' in the list that starts from 'head' in the correct
    position (as found by l_find)

  RETURN
    0     - inserted
    not 0 - a pointer to a duplicate (not pinned and thus unusable)

  NOTE
    it uses pins[0..2], on return all pins are removed.
    if there're nodes with the same key value, a new node is added before them.
*/
static LF_SLIST *l_insert(LF_SLIST * volatile *head, CHARSET_INFO *cs,
                         LF_SLIST *node, LF_PINS *pins, uint flags)
{
  CURSOR         cursor;
  int            res;

  for (;;)
  {
    if (l_find(head, cs, node->hashnr, node->key, node->keylen,
              &cursor, pins) &&
        (flags & LF_HASH_UNIQUE))
    {
      res= 0; /* duplicate found */
      break;
    }
    else
    {
      node->link= (intptr)cursor.curr;
      DBUG_ASSERT(node->link != (intptr)node); /* no circular references */
      DBUG_ASSERT(cursor.prev != &node->link); /* no circular references */
      if (my_atomic_casptr((void **) cursor.prev,
                           (void **)(char*) &cursor.curr, node))
      {
        res= 1; /* inserted ok */
        break;
      }
    }
  }
  _lf_unpin(pins, 0);
  _lf_unpin(pins, 1);
  _lf_unpin(pins, 2);
  /*
    Note that cursor.curr is not pinned here and the pointer is unreliable,
    the object may dissapear anytime. But if it points to a dummy node, the
    pointer is safe, because dummy nodes are never freed - initialize_bucket()
    uses this fact.
  */
  return res ? 0 : cursor.curr;
}
Beispiel #10
0
value_t l_insert(node_t *head, key_t key, value_t val) {
    node_t *pred, *item, *new_item;
    while (TRUE) {
        if (l_find(&pred, &item, head, key)) { /* update its value */
            /* 更新值时,使用item->val互斥,NULL_VALUE表示被删除 */
            node_t *sitem = STRIP_MARK(item);
            value_t old_val = sitem->val;
            while (old_val != NULL_VALUE) {
                value_t ret = CAS_V(&sitem->val, old_val, val);
                if (ret == old_val) {
                    trace("update item %p value success\n", item);
                    return ret;
                }
                trace("update item lost race %p\n", item);
                old_val = ret;
            }
            trace("item %p removed, retry\n", item);
            continue; /* the item has been removed, we retry */
        }
        new_item = (node_t*) malloc(sizeof(node_t));
        new_item->key = key;
        new_item->val = val;
        new_item->next = item;
        /* a). pred是否有效问题:无效只会发生在使用pred->next时,而l_remove正移除该pred
               就会在CAS(&item->next)中竞争,如果remove中成功,那么insert CAS就失败,
               然后重试;反之,remove失败重试,所以保证了pred有效
           b). item本身增加tag一定程度上降低ABA问题几率
        */
        if (CAS(&pred->next, item, new_item)) {
            trace("insert item %p(next) %p success\n", item, new_item);
            return val;
        }
        trace("cas item %p failed, retry\n", item);
        free(new_item);
    }
    return NULL_VALUE;
}
Beispiel #11
0
void big_test() {
    linked_list list = l_create();

  l_add_front(list, 3);

  length_test(list, 1);
  front_test(list, 3);
  back_test(list, 3);
  //list = 3


  l_add_back(list, 4);
  length_test(list, 2);
  front_test(list, 3);
  back_test(list, 4);
  //list = 3, 4

  
  l_add_front(list, 2);
  length_test(list, 3);
  front_test(list, 2);
  back_test(list, 4);
  //list = 2, 3, 4

  
  int array1[] = {2, 3, 4};
  print_test(list, array1, 3);


  l_add_front(list, 1);
  l_add_back(list, 5);
  length_test(list, 5);
  front_test(list, 1);
  back_test(list, 5);
  //list = 1, 2, 3, 4, 5

  
  find_test(list, 3, 1);
  link l = l_find(list, 3);
  l_remove(list, l);
  find_test(list, 3, 0);
  length_test(list, 4);
  front_test(list, 1);
  back_test(list, 5);
  //list = 1, 2, 4, 5

  
  int array2[] = {1, 2, 4, 5};
  print_test(list, array2, 4);

  
  l_remove_back(list);
  length_test(list, 3);
  back_test(list, 4);
  //list = 1, 2, 4
  
  l_remove_front(list);
  length_test(list, 2);
  front_test(list, 2);
  //list = 2, 4

  l_destroy(list);
}
Beispiel #12
0
int l_exist(node_t *head, key_t key) {
    node_t *pred, *item;
    return l_find(&pred, &item, head, key);
}