@@ -75,7 +75,7 @@ public:
7575
7676 void refill (ref CachedExtentMap emap, shared (Arena)* arena,
7777 ref ThreadBinState state, ubyte sizeClass, size_t slotSize) {
78- auto nfill = nmax >> state.fillShift ;
78+ auto nfill = state.getFill(nmax) ;
7979 assert (nfill > 0 );
8080
8181 /**
@@ -99,7 +99,14 @@ public:
9999 return true ;
100100 }
101101
102- void flushToFree (ref CachedExtentMap emap) {
102+ void flushToFree (ref CachedExtentMap emap, ref ThreadBinState state) {
103+ /**
104+ * When we use free explicitely, we want to make sure we have room
105+ * left in the bin to accomodate further freed elements, even in case
106+ * where we refill.
107+ */
108+ state.onFlush();
109+
103110 /**
104111 * We do not have enough space in the bin, so start flushing.
105112 * However, we do not want to flush all of it, as it would leave
@@ -298,7 +305,25 @@ private:
298305
299306struct ThreadBinState {
300307 bool refilled;
308+ bool flushed;
301309 ubyte fillShift;
310+
311+ uint getFill (ushort nmax) const {
312+ return nmax >> fillShift;
313+ }
314+
315+ bool onFlush () {
316+ if (flushed) {
317+ return false ;
318+ }
319+
320+ flushed = true ;
321+ if (fillShift == 0 ) {
322+ fillShift++ ;
323+ }
324+
325+ return true ;
326+ }
302327}
303328
304329bool isValidThreadBinCapacity (uint capacity ) {
@@ -521,3 +546,32 @@ unittest refill {
521546 " Invalid cached element count!" );
522547 }
523548}
549+
550+ unittest flushed {
551+ enum BinSize = 200 ;
552+
553+ // Setup the state.
554+ ThreadBinState state;
555+ assert (! state.flushed, " Thread bin flushed!" );
556+ assert (state.getFill(BinSize) == BinSize, " Unexpected fill!" );
557+
558+ // When we flush, we reduce the max fill.
559+ state.onFlush();
560+
561+ assert (state.flushed, " Thread bin not flushed!" );
562+ assert (state.getFill(BinSize) == BinSize / 2 , " Unexpected fill!" );
563+
564+ // On repeat, nothing happens.
565+ state.onFlush();
566+
567+ assert (state.flushed, " Thread bin not flushed!" );
568+ assert (state.getFill(BinSize) == BinSize / 2 , " Unexpected fill!" );
569+
570+ // When flushed is cleared, we redo, but never
571+ // reduce fill to less than half the bin.
572+ state.flushed = false ;
573+ state.onFlush();
574+
575+ assert (state.flushed, " Thread bin not flushed!" );
576+ assert (state.getFill(BinSize) == BinSize / 2 , " Unexpected fill!" );
577+ }
0 commit comments