From 62ec3013e8a60ae43129dfa47433a17a9801ecd2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 5 Nov 2012 23:29:23 +0000 Subject: [PATCH] Need to check hash table for staleness when deleting a key. Copied from Perforce Change: 180354 ServerID: perforce.ravenbrook.com --- mps/example/scheme/scheme.c | 5 +++- mps/manual/source/guide/advanced.rst | 44 ++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/mps/example/scheme/scheme.c b/mps/example/scheme/scheme.c index 4f0cf66bd85..69a3089700a 100644 --- a/mps/example/scheme/scheme.c +++ b/mps/example/scheme/scheme.c @@ -993,7 +993,10 @@ static void table_delete(obj_t tbl, obj_t key) { struct bucket_s *b; assert(TYPE(tbl) == TYPE_TABLE); - b = buckets_find(tbl, tbl->table.buckets, key, &tbl->table.ld); + b = buckets_find(tbl, tbl->table.buckets, key, NULL); + if ((b == NULL || b->key == NULL) && mps_ld_isstale(&tbl->table.ld, arena, key)) { + b = table_rehash(tbl, tbl->table.buckets->buckets.length, key); + } if (b != NULL && b->key != NULL) { b->key = obj_deleted; ++ tbl->table.buckets->buckets.deleted; diff --git a/mps/manual/source/guide/advanced.rst b/mps/manual/source/guide/advanced.rst index 1f72c9dd020..46e5eaf2ecb 100644 --- a/mps/manual/source/guide/advanced.rst +++ b/mps/manual/source/guide/advanced.rst @@ -332,11 +332,6 @@ any of its keys. looked up, when the staleness will be discovered. After all, it may never be looked up. -.. note:: - - Don't forget that deleting a key from an address-based hash table - also results in a dependency on its location. - If you look up a key in an address-based hash table and fail to find it there, that might be because the table's dependency on the location of the key is stale: that is, if the garbage collector moved the key. The @@ -435,6 +430,45 @@ the location dependency becomes stale and the table has to be rehashed. move in the collection, so it's not found in the table, and that causes :c:func:`mps_ld_isstale` to be tested. +Don't forget to check the location dependency for staleness if you are +about to delete a key from a hash table but discover that it's not +there. In the toy Scheme interpreter, deletion looks like this: + +.. code-block:: c + :emphasize-lines: 6 + + static void table_delete(obj_t tbl, obj_t key) + { + struct bucket_s *b; + assert(TYPE(tbl) == TYPE_TABLE); + b = buckets_find(tbl, tbl->table.buckets, key, NULL); + if ((b == NULL || b->key == NULL) && mps_ld_isstale(&tbl->table.ld, arena, key)) { + b = table_rehash(tbl, tbl->table.buckets->buckets.length, key); + } + if (b != NULL && b->key != NULL) { + b->key = obj_deleted; + ++ tbl->table.buckets->buckets.deleted; + } + } + +Again, by adding the line ``puts("stale!");`` after +:c:func:`mps_ld_isstale` returns true, it's possible to see when the +location dependency becomes stale and the table has to be rehashed: + +.. code-block:: none + + MPS Toy Scheme Example + 13248, 0> (define ht (make-eq-hashtable)) + ht + 13624, 0> (hashtable-set! ht 'one 1) + 13808, 0> (gc) + 13832, 1> (hashtable-delete! ht 'one) + stale! + 14112, 1> ht + #[hashtable] + + + .. topics:: :ref:`topic-location`.