[Groonga-commit] groonga/groonga [master] Refactor grn_hash_reset().

Back to archive index

null+****@clear***** null+****@clear*****
2012年 4月 4日 (水) 19:35:23 JST


Susumu Yata	2012-04-04 19:35:23 +0900 (Wed, 04 Apr 2012)

  New Revision: 80d3e8b6d44452bbc35f8203d160bbcf52c5ae25

  Log:
    Refactor grn_hash_reset().

  Modified files:
    lib/hash.c

  Modified: lib/hash.c (+76 -38)
===================================================================
--- lib/hash.c    2012-04-04 18:31:09 +0900 (1da13bb)
+++ lib/hash.c    2012-04-04 19:35:23 +0900 (5e496f7)
@@ -1631,65 +1631,103 @@ grn_hash_calculate_step(uint32_t hash_value)
   return (hash_value >> 2) | 0x1010101;
 }
 
-/* TODO: to be fixed later. */
 static grn_rc
-grn_hash_reset(grn_ctx *ctx, grn_hash *hash, uint32_t ne)
-{
-  entry *ee;
-  grn_id e, *index = NULL, *sp = NULL, *dp;
-  uint32_t n, n0 = *hash->n_entries, offs = 0, offd = 0;
-  if (!ne) { ne = n0 * 2; }
-  if (ne > INT_MAX) { return GRN_NO_MEMORY_AVAILABLE; }
-  for (n = INITIAL_INDEX_SIZE; n <= ne; n *= 2);
+grn_hash_reset(grn_ctx *ctx, grn_hash *hash, uint32_t expected_n_entries)
+{
+  grn_id *new_index = NULL;
+  uint32_t new_index_size = INITIAL_INDEX_SIZE;
+  grn_id *src_ptr = NULL, *dest_ptr = NULL;
+  uint32_t src_offset = 0, dest_offset = 0;
+  const uint32_t n_entries = *hash->n_entries;
+  const uint32_t max_offset = *hash->max_offset;
+
+  if (!expected_n_entries) {
+    expected_n_entries = n_entries * 2;
+  }
+  if (expected_n_entries > INT_MAX) {
+    return GRN_NO_MEMORY_AVAILABLE;
+  }
+  while (new_index_size <= expected_n_entries) {
+    new_index_size *= 2;
+  }
+
   if (grn_hash_is_io_hash(hash)) {
     uint32_t i;
-    offs = hash->header->idx_offset;
-    offd = MAX_INDEX_SIZE - offs;
-    for (i = 0; i < n; i += (IDX_MASK_IN_A_SEGMENT + 1)) {
-      dp = grn_io_hash_idx_at(ctx, hash, i + offd); /* todo : use idx_at */
-      if (!dp) { return GRN_NO_MEMORY_AVAILABLE; }
-      memset(dp, 0, GRN_HASH_SEGMENT_SIZE);
+    src_offset = hash->header->idx_offset;
+    dest_offset = MAX_INDEX_SIZE - src_offset;
+    for (i = 0; i < new_index_size; i += (IDX_MASK_IN_A_SEGMENT + 1)) {
+      /*
+       * The following grn_io_hash_idx_at() allocates memory for a new segment
+       * and returns a pointer to the new segment. It's actually bad manners
+       * but faster than calling grn_io_hash_idx_at() for each element.
+       */
+      dest_ptr = grn_io_hash_idx_at(ctx, hash, i + dest_offset);
+      if (!dest_ptr) {
+        return GRN_NO_MEMORY_AVAILABLE;
+      }
+      memset(dest_ptr, 0, GRN_HASH_SEGMENT_SIZE);
     }
   } else {
     GRN_ASSERT(ctx == hash->ctx);
-    if (!(index = GRN_CTX_ALLOC(ctx, n * sizeof(grn_id)))) {
+    new_index = GRN_CTX_ALLOC(ctx, new_index_size * sizeof(grn_id));
+    if (!new_index) {
       return GRN_NO_MEMORY_AVAILABLE;
     }
-    sp = hash->index;
+    src_ptr = hash->index;
   }
+
   {
-    uint32_t i, j, k, m0 = *hash->max_offset, m = n - 1, s;
-    for (k = 0, j = 0; k < n0 && j <= m0; j++, sp++) {
-      if (grn_hash_is_io_hash(hash) && !(j & IDX_MASK_IN_A_SEGMENT)) {
-        sp = grn_io_hash_idx_at(ctx, hash, j + offs);
-        if (!sp) { return GRN_NO_MEMORY_AVAILABLE; }
+    uint32_t src_pos, count;
+    const uint32_t new_max_offset = new_index_size - 1;
+    for (count = 0, src_pos = 0; count < n_entries && src_pos <= max_offset;
+         src_pos++, src_ptr++) {
+      uint32_t i, step;
+      grn_id entry_id;
+      grn_hash_entry *entry;
+      if (grn_hash_is_io_hash(hash) && !(src_pos & IDX_MASK_IN_A_SEGMENT)) {
+        src_ptr = grn_io_hash_idx_at(ctx, hash, src_pos + src_offset);
+        if (!src_ptr) {
+          return GRN_NO_MEMORY_AVAILABLE;
+        }
+      }
+      entry_id = *src_ptr;
+      if (!entry_id || (entry_id == GARBAGE)) {
+        continue;
+      }
+      entry = grn_hash_entry_at(ctx, hash, entry_id, GRN_TABLE_ADD);
+      if (!entry) {
+        return GRN_NO_MEMORY_AVAILABLE;
       }
-      e = *sp;
-      if (!e || (e == GARBAGE)) { continue; }
-      ee = grn_hash_entry_at(ctx, hash, e, GRN_TABLE_ADD);
-      if (!ee) { return GRN_NO_MEMORY_AVAILABLE; }
-      for (i = ee->key, s = grn_hash_calculate_step(i); ; i += s) {
+      step = grn_hash_calculate_step(entry->hash_value);
+      for (i = entry->hash_value; ; i += step) {
+        i &= new_max_offset;
         if (grn_hash_is_io_hash(hash)) {
-          dp = grn_io_hash_idx_at(ctx, hash, (i & m) + offd);
-          if (!dp) { return GRN_NO_MEMORY_AVAILABLE; }
+          dest_ptr = grn_io_hash_idx_at(ctx, hash, i + dest_offset);
+          if (!dest_ptr) {
+            return GRN_NO_MEMORY_AVAILABLE;
+          }
         } else {
-          dp = index + (i & m);
+          dest_ptr = new_index + i;
+        }
+        if (!*dest_ptr) {
+          break;
         }
-        if (!*dp) { break; }
       }
-      *dp = e;
-      k++;
+      *dest_ptr = entry_id;
+      count++;
     }
-    *hash->max_offset = m;
+    *hash->max_offset = new_max_offset;
     *hash->n_garbages = 0;
   }
+
   if (grn_hash_is_io_hash(hash)) {
-    hash->header->idx_offset = offd;
+    hash->header->idx_offset = dest_offset;
   } else {
-    grn_id *i0 = hash->index;
-    hash->index = index;
-    GRN_CTX_FREE(ctx, i0);
+    grn_id * const old_index = hash->index;
+    hash->index = new_index;
+    GRN_CTX_FREE(ctx, old_index);
   }
+
   return GRN_SUCCESS;
 }
 




Groonga-commit メーリングリストの案内
Back to archive index