From 1d8a2516b28246493030ca6ab35d187f65e0e23e Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Wed, 20 Nov 2013 07:01:20 -0700 Subject: [PATCH] fix problem resizing mutable hash tables A hash-table size grew based on the number of key slots occupied, instead of the number of value slots, where the two differ when keys are added and removed in the table. Thanks to Ryan for the example. --- .../racket-test/tests/racket/hash-mem.rkt | 46 +++++++++++++++++++ racket/src/racket/src/hash.c | 5 +- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 pkgs/racket-pkgs/racket-test/tests/racket/hash-mem.rkt diff --git a/pkgs/racket-pkgs/racket-test/tests/racket/hash-mem.rkt b/pkgs/racket-pkgs/racket-test/tests/racket/hash-mem.rkt new file mode 100644 index 0000000000..51a37b132f --- /dev/null +++ b/pkgs/racket-pkgs/racket-test/tests/racket/hash-mem.rkt @@ -0,0 +1,46 @@ +#lang racket/base +(require racket/cmdline) + +(define N 25) + +;; create an eq?-fresh object +(define (alloc i) + (number->string i)) + +(define (check status) + (define mem (quotient (current-memory-use) #e1e6)) + (printf "memory use: ~s\n" mem) + (cond + [(and status ((vector-ref status 0) . < . mem)) + (if ((vector-ref status 1) . > . 3) + (error "memory use grew too many times") + (vector mem (add1 (vector-ref status 1))))] + [status status] + [else (vector mem 0)])) + + (quotient (current-memory-use) #e1e6) + +(define (test-mutable) + (define h (make-hasheq)) + (for/fold ([status #f]) ([i N]) + (collect-garbage) + (collect-garbage) + (for ([i #e1e6]) + (define p (alloc i)) + (hash-set! h p #t) + (hash-remove! h p)) + (check status))) + +(define (test-immutable) + (define h #hasheq()) + (for/fold ([status #f]) ([i N]) + (collect-garbage) + (collect-garbage) + (for ([i #e1e6]) + (define p (alloc i)) + (set! h (hash-set h p #t)) + (set! h (hash-remove h p))) + (check status))) + +(test-mutable) +(test-immutable) diff --git a/racket/src/racket/src/hash.c b/racket/src/racket/src/hash.c index 43db3e4c34..a7c96011b2 100644 --- a/racket/src/racket/src/hash.c +++ b/racket/src/racket/src/hash.c @@ -308,7 +308,10 @@ static Scheme_Object *do_hash(Scheme_Hash_Table *table, Scheme_Object *key, int Scheme_Object **oldkeys = table->keys; Scheme_Object **oldvals = table->vals; - size = oldsize << 1; + if (table->count << 1 >= table->mcount) + size = oldsize << 1; + else + size = oldsize; table->size = size; {