Author: Armin Rigo <[email protected]>
Branch: hashtable-iter
Changeset: r1597:8da7f5322135
Date: 2015-01-31 22:47 +0100
http://bitbucket.org/pypy/stmgc/changeset/8da7f5322135/

Log:    document the plan

diff --git a/c7/stm/hashtable.c b/c7/stm/hashtable.c
--- a/c7/stm/hashtable.c
+++ b/c7/stm/hashtable.c
@@ -12,22 +12,30 @@
 collision).
 
 The main operations on a hashtable are reading or writing an object at a
-given index.  It might support in the future enumerating the indexes of
-non-NULL objects.
+given index.  It also supports iterating its non-NULL entries.
 
 There are two markers for every index (a read and a write marker).
 This is unlike regular arrays, which have only two markers in total.
 
+Additionally, we use the read marker for the hashtable object itself
+to mean "we are iterating".  When a transaction has got this "global"
+read marker and another transaction attempts to create a new key/value
+pair via stm_hashtable_{lookup,read,write}, the call immediately fails
+with a read/write conflict.  This gives priority to the iterating
+transaction rather than the modifying transaction, which is probably
+what we want.
+
 
 Implementation
 --------------
 
 First idea: have the hashtable in raw memory, pointing to "entry"
-objects.  The entry objects themselves point to the user-specified
-objects.  The entry objects have the read/write markers.  Every entry
-object, once created, stays around.  It is only removed by the next
-major GC if it points to NULL and its read/write markers are not set
-in any currently-running transaction.
+objects (which are regular, GC- and STM-managed objects).  The entry
+objects themselves point to the user-specified objects.  The entry
+objects hold the read/write markers.  Every entry object, once
+created, stays around.  It is only removed by the next major GC if it
+points to NULL and its read/write markers are not set in any
+currently-running transaction.
 
 References
 ----------
@@ -54,8 +62,12 @@
 
        The field 'resize_counter' also works as a write lock: changes
        go via the intermediate value RESIZING_LOCK (0).
+
+       In addition, 'resize_counter' can be the negative of the odd
+       number that it would normally be, as a hint to force the check
+       of the global read marker, as set by iteration.
     */
-    uintptr_t resize_counter;
+    intptr_t resize_counter;
 
     stm_hashtable_entry_t *items[INITIAL_HASHTABLE_SIZE];
 } stm_hashtable_table_t;
@@ -88,7 +100,7 @@
 
 void stm_hashtable_free(stm_hashtable_t *hashtable)
 {
-    uintptr_t rc = hashtable->initial_table.resize_counter;
+    intptr_t rc = hashtable->initial_table.resize_counter;
     free(hashtable);
     while (IS_EVEN(rc)) {
         assert(rc != RESIZING_LOCK);
@@ -150,15 +162,16 @@
     assert(biggertable);   // XXX
 
     stm_hashtable_table_t *table = hashtable->table;
-    table->resize_counter = (uintptr_t)biggertable;
+    table->resize_counter = (intptr_t)biggertable;
     /* ^^^ this unlocks the table by writing a non-zero value to
        table->resize_counter, but the new value is a pointer to the
        new bigger table, so IS_EVEN() is still true */
+    assert(IS_EVEN(table->resize_counter));
 
     init_table(biggertable, biggercount);
 
     uintptr_t j, mask = table->mask;
-    uintptr_t rc = biggertable->resize_counter;
+    intptr_t rc = biggertable->resize_counter;
     char *segment_base = get_segment_base(remove_unread_from_seg);
     for (j = 0; j <= mask; j++) {
         stm_hashtable_entry_t *entry = table->items[j];
@@ -175,6 +188,7 @@
         _insert_clean(biggertable, entry);
         rc -= 6;
     }
+    assert(rc > 0);
     biggertable->resize_counter = rc;
 
     write_fence();   /* make sure that 'biggertable' is valid here,
@@ -218,7 +232,7 @@
     }
     /* here, we didn't find the 'entry' with the correct index. */
 
-    uintptr_t rc = VOLATILE_TABLE(table)->resize_counter;
+    intptr_t rc = VOLATILE_TABLE(table)->resize_counter;
 
     /* if rc is RESIZING_LOCK (which is 0, so even), a concurrent thread
        is writing to the hashtable.  Or, if rc is another even number, it is
@@ -307,6 +321,7 @@
         return entry;
     }
     else {
+        //xxxxxxxxxxxxxxxxxxxxxxx;
         /* if rc is smaller than 6, we must allocate a new bigger table.
          */
         uintptr_t biggercount = table->mask + 1;
@@ -364,7 +379,7 @@
     assert(!IS_EVEN(table->resize_counter));
 
     if (table != &hashtable->initial_table) {
-        uintptr_t rc = hashtable->initial_table.resize_counter;
+        intptr_t rc = hashtable->initial_table.resize_counter;
         while (1) {
             assert(IS_EVEN(rc));
             assert(rc != RESIZING_LOCK);
@@ -375,7 +390,8 @@
             rc = old_table->resize_counter;
             free(old_table);
         }
-        hashtable->initial_table.resize_counter = (uintptr_t)table;
+        hashtable->initial_table.resize_counter = (intptr_t)table;
+        assert(IS_EVEN(hashtable->initial_table.resize_counter));
     }
 }
 
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to