为什么要在 levelDB 的缓存中使用 while 循环(函数 Resize)?



当我看到levelDB的缓存,地址的实现。我不明白为什么它在for循环中使用while循环(在函数Resize中),我认为它可以用if语句代替。我希望有人能帮助我。

 void Resize() {
    uint32_t new_length = 4;
    while (new_length < elems_) {
      new_length *= 2;
    }
    LRUHandle** new_list = new LRUHandle*[new_length];
    memset(new_list, 0, sizeof(new_list[0]) * new_length);
    uint32_t count = 0;
    for (uint32_t i = 0; i < length_; i++) {
      LRUHandle* h = list_[i];
      while (h != NULL) {
        LRUHandle* next = h->next_hash;
        uint32_t hash = h->hash;
        LRUHandle** ptr = &new_list[hash & (new_length - 1)];
        h->next_hash = *ptr;
        *ptr = h;
        h = next;
        count++;
      }
    }
    assert(elems_ == count);
    delete[] list_;
    list_ = new_list;
    length_ = new_length;
  }
};

list_显然是一个链表数组。while (h != NULL),结合h = next(其中nexth->next_hash),意味着while循环将对每个链表的所有元素进行操作,仅在到达最后一个元素时停止(当h变为NULL时,要么是因为列表为空,要么是因为元素的next_hashNULL)。

如果你用if (h != NULL)替换它,它将只对链表的第一个元素起作用

看起来list_是一个动态的单链表数组。

我假设list_看起来像下面的

list_[0]-> node_1 -> node_2 -> null
list_[1]-> node_3 -> null
list_[2]-> null
....
list_[n]-> node_m-1 -> node_m -> null

要正确地将所有元素复制到new_list中,需要使用while循环。否则,任何不能从list_直接寻址的元素都不会被复制/散列到new_list中。在上面的图中,这意味着node_2和node_m+1不会被添加到new_list中。

new_list将保持相同的形状,但应该有更少的冲突。

使用if语句,new_list看起来像这样:
new_list[0]-> node_1 -> null
new_list[1]-> null
new_list[2]-> node_2 -> null
...
new_list[p-1]-> node_k -> null
new_list[p] -> null

即new_list中的每一项都指向一个包含1个或0个元素的列表。注意,该图中的node_1不一定与上图中的节点1相同。

使用If语句而不是while循环也会导致内存泄漏,因为您不能再访问所有元素。

变量list_[i]有一个子列表,whilefor循环中循环遍历子列表

if语句不起作用,如果您有两个元素list_[i]list_[j]都散列到同一个索引new_list[m]。在这种情况下,您必须使用while语句来合并两个桶。同时,这个实现中每个bucket的长度平均小于1,所以这里的while语句实际上和if语句一样快。

最新更新