Statistics code.
authorRobert Haas <rhaas@postgresql.org>
Mon, 30 Jul 2012 16:22:12 +0000 (16:22 +0000)
committerRobert Haas <rhaas@postgresql.org>
Mon, 13 Oct 2014 17:14:18 +0000 (13:14 -0400)
src/backend/utils/hash/chash.c

index f44b65009f3a1a50ff4b8810a6560b12f26908e7..bfcf809d3648fe3636a3f353778a116381ae3578 100644 (file)
@@ -158,10 +158,24 @@ typedef struct CHashTableData
    char           *arena;          /* arena */
 
    /*
-    * This field will be different in each backend; the shared copy is
+    * These fields will be different in each backend; the shared copy is
     * unused.
     */
    uint32          gc_next;        /* next garbage list to reclaim */
+   uint64          s_insert_retry; /* insert point concurrently updated */
+   uint64          s_delete_retry; /* delete point concurrently updated */
+   uint64          s_cleanup_scan; /* expunge-after-delete failed */
+   uint64          s_scan_expunge_ok;      /* scan did expunge */
+   uint64          s_scan_expunge_fail;    /* expunge failed */
+   uint64          s_scan_restart;         /* scan restarted */
+   uint64          s_cleanup_expunge_ok;   /* cleanup scan did expunge */
+   uint64          s_cleanup_expunge_fail; /* cleanup scan expunge failed */
+   uint64          s_cleanup_restart;      /* cleanup scan restarted */
+   uint64          s_allocate_pop_fail;    /* freelist pop failed */
+   uint64          s_gc_pop_fail;      /* garbage list pop failed */
+   uint64          s_gc_reclaim_retry; /* failed to return GC'd nodes */
+   uint64          s_garbage_retry;    /* failed to enqueue garbage */
+   uint64          s_free_retry;       /* failed to perform immediate free */
 } CHashTableData;
 
 #define CHashTableGetRaw(table, offset) \
@@ -225,7 +239,7 @@ CHashBootstrap(CHashDescriptor *desc)
    uint32          bucket_shift;
 
    /* Allocate table and copy descriptor. */
-   table = MemoryContextAlloc(TopMemoryContext, sizeof(CHashTableData));
+   table = MemoryContextAllocZero(TopMemoryContext, sizeof(CHashTableData));
    memcpy(&table->desc, desc, sizeof(CHashDescriptor)); 
 
    /* Sanity checks. */
@@ -474,7 +488,10 @@ retry:
        nnew->next = scan.target;
        if (!__sync_bool_compare_and_swap(scan.pointer_to_target,
                                          scan.target, new))
+       {
+           table->s_insert_retry++;
            goto retry;
+       }
    }
 
    /* Allow garbage collection for this bucket. */
@@ -536,6 +553,7 @@ CHashDelete(CHashTable table, void *entry)
                cleanup_scan = true;
            break;
        }
+       table->s_delete_retry++;
    }
 
    /*
@@ -543,7 +561,10 @@ CHashDelete(CHashTable table, void *entry)
     * to make sure it's really gone.
     */
    if (cleanup_scan)
+   {
+       table->s_cleanup_scan++;
        CHashBucketCleanup(table, &table->bucket[bucket], hashcode);
+   }
 
    /* Allow garbage collection for this bucket. */
    CHashTableUnsuppressGC();
@@ -631,6 +652,7 @@ zap:
                 * all non-deleted items (and possibly some deleted items)
                 * that were present at the time we began the scan.
                 */
+               table->s_scan_expunge_ok++;
                CHashAddToGarbage(table, hashcode & table->bucket_mask,
                                  target);
                target = CHashPtrUnmark(next);
@@ -658,9 +680,13 @@ zap:
                 * have to be pretty unlucky to have it happen even twice in
                 * a row.
                 */
+               table->s_scan_expunge_fail++;
                target = *pointer_to_target;
                if (CHashPtrIsMarked(target))
+               {
+                   table->s_scan_restart++;
                    goto retry;
+               }
                continue;
            }
        }
@@ -771,6 +797,7 @@ retry:
                                             CHashPtrUnmark(next)))
            {
                /* We removed the item. */
+               table->s_cleanup_expunge_ok++;
                CHashAddToGarbage(table, hashcode & table->bucket_mask,
                                  target);
                target = CHashPtrUnmark(next);
@@ -845,14 +872,18 @@ CHashAllocate(CHashTable table)
            pg_read_barrier_depends();
            if (__sync_bool_compare_and_swap(b, new, n->un.gcnext))
                return new;
+           table->s_allocate_pop_fail++;
        }
 
        /* If next garbage list is non-empty, empty it via compare-and-swap. */
        table->gc_next = (table->gc_next + 1) % table->ngarbage;
        b = &table->garbage[table->gc_next];
        garbage = *b;
-       if (!CHashPtrIsInvalid(garbage) &&
-           __sync_bool_compare_and_swap(b, garbage, InvalidCHashPtr))
+       if (CHashPtrIsInvalid(garbage))
+           ;
+       else if (!__sync_bool_compare_and_swap(b, garbage, InvalidCHashPtr))
+           ++table->s_gc_pop_fail;
+       else
        {
            uint64      chash_bucket;
            uint32      i;
@@ -905,11 +936,14 @@ CHashAllocate(CHashTable table)
 
                /* Push reclaimed elements onto home free list. */
                b = &table->freelist[f_home];
-               do
+               for (;;)
                {
                    oldhead = *b;
                    n->un.gcnext = oldhead;
-               } while (!__sync_bool_compare_and_swap(b, oldhead, fhead));
+                   if (__sync_bool_compare_and_swap(b, oldhead, fhead))
+                       break;
+                   ++table->s_gc_reclaim_retry;
+               }
            }
 
            /* Return the element we saved for ourselves. */
@@ -943,11 +977,14 @@ CHashAddToGarbage(CHashTable table, uint32 bucket, CHashPtr c)
    n = CHashTableGetNode(table, c);
    garbage = &table->garbage[garbage_bucket];
 
-   do
+   while (1)
    {
        g = *garbage;
        n->un.gcnext = g;
-   } while (!__sync_bool_compare_and_swap(garbage, g, c));
+       if (__sync_bool_compare_and_swap(garbage, g, c))
+           break;
+       ++table->s_garbage_retry;
+   }
 }
 
 /*
@@ -970,9 +1007,12 @@ CHashImmediateFree(CHashTable table, CHashPtr c)
    n = CHashTableGetNode(table, c);
    free = &table->freelist[f_home];
 
-   do
+   for (;;)
    {
        f = *free;
        n->un.gcnext = f;
-   } while (!__sync_bool_compare_and_swap(free, f, c));
+       if (__sync_bool_compare_and_swap(free, f, c))
+           break;
+       ++table->s_free_retry;
+   }
 }