1616
1717package org .dizitart .no2 .mvstore ;
1818
19+ import static org .dizitart .no2 .common .util .ValidationUtils .notNull ;
20+
21+ import java .lang .ref .Cleaner ;
22+ import java .util .Iterator ;
23+ import java .util .Map ;
24+ import java .util .NoSuchElementException ;
25+ import java .util .Set ;
26+ import java .util .concurrent .ConcurrentHashMap ;
27+ import java .util .concurrent .atomic .AtomicBoolean ;
28+ import java .util .function .Supplier ;
29+
1930import org .dizitart .no2 .common .RecordStream ;
2031import org .dizitart .no2 .common .tuples .Pair ;
32+ import org .dizitart .no2 .exceptions .NitriteIOException ;
2133import org .dizitart .no2 .store .NitriteMap ;
2234import org .dizitart .no2 .store .NitriteStore ;
2335import org .h2 .mvstore .MVMap ;
2436import org .h2 .mvstore .MVStore ;
2537
26- import java .util .Iterator ;
27- import java .util .Map ;
28- import java .util .concurrent .atomic .AtomicBoolean ;
29-
30- import static org .dizitart .no2 .common .util .ValidationUtils .notNull ;
31-
3238/**
33- * @since 1.0
3439 * @author Anindya Chatterjee
40+ * @since 1.0
3541 */
3642class NitriteMVMap <Key , Value > implements NitriteMap <Key , Value > {
43+
44+ private static final Cleaner CLEANER = Cleaner .create ();
45+
3746 private final MVMap <Key , Value > mvMap ;
3847 private final NitriteStore <?> nitriteStore ;
3948 private final MVStore mvStore ;
4049 private final AtomicBoolean droppedFlag ;
4150 private final AtomicBoolean closedFlag ;
51+ private final Set <VersionUsage > versionUsages ;
4252
43- NitriteMVMap (MVMap <Key , Value > mvMap , NitriteStore <?> nitriteStore ) {
53+ NitriteMVMap (final MVMap <Key , Value > mvMap , final NitriteStore <?> nitriteStore ) {
4454 this .mvMap = mvMap ;
4555 this .nitriteStore = nitriteStore ;
4656 this .mvStore = mvMap .getStore ();
4757 this .closedFlag = new AtomicBoolean (false );
4858 this .droppedFlag = new AtomicBoolean (false );
59+ this .versionUsages = ConcurrentHashMap .newKeySet ();
4960 }
5061
5162 @ Override
52- public boolean containsKey (Key key ) {
63+ public boolean containsKey (final Key key ) {
5364 return mvMap .containsKey (key );
5465 }
5566
5667 @ Override
57- public Value get (Key key ) {
68+ public Value get (final Key key ) {
5869 return mvMap .get (key );
5970 }
6071
@@ -65,7 +76,7 @@ public NitriteStore<?> getStore() {
6576
6677 @ Override
6778 public void clear () {
68- MVStore .TxCounter txCounter = mvStore .registerVersionUsage ();
79+ final MVStore .TxCounter txCounter = mvStore .registerVersionUsage ();
6980 try {
7081 mvMap .clear ();
7182 updateLastModifiedTime ();
@@ -81,14 +92,14 @@ public String getName() {
8192
8293 @ Override
8394 public RecordStream <Value > values () {
84- return RecordStream . fromIterable ( mvMap .values ());
95+ return () -> versionedIterator (() -> mvMap .values (). iterator ());
8596 }
8697
8798 @ Override
88- public Value remove (Key key ) {
89- MVStore .TxCounter txCounter = mvStore .registerVersionUsage ();
99+ public Value remove (final Key key ) {
100+ final MVStore .TxCounter txCounter = mvStore .registerVersionUsage ();
90101 try {
91- Value value = mvMap .remove (key );
102+ final Value value = mvMap .remove (key );
92103 updateLastModifiedTime ();
93104 return value ;
94105 } finally {
@@ -98,13 +109,13 @@ public Value remove(Key key) {
98109
99110 @ Override
100111 public RecordStream <Key > keys () {
101- return RecordStream . fromIterable ( mvMap .keySet ());
112+ return () -> versionedIterator (() -> mvMap .keySet (). iterator ());
102113 }
103114
104115 @ Override
105- public void put (Key key , Value value ) {
116+ public void put (final Key key , final Value value ) {
106117 notNull (value , "value cannot be null" );
107- MVStore .TxCounter txCounter = mvStore .registerVersionUsage ();
118+ final MVStore .TxCounter txCounter = mvStore .registerVersionUsage ();
108119 try {
109120 mvMap .put (key , value );
110121 updateLastModifiedTime ();
@@ -119,11 +130,11 @@ public long size() {
119130 }
120131
121132 @ Override
122- public Value putIfAbsent (Key key , Value value ) {
133+ public Value putIfAbsent (final Key key , final Value value ) {
123134 notNull (value , "value cannot be null" );
124- MVStore .TxCounter txCounter = mvStore .registerVersionUsage ();
135+ final MVStore .TxCounter txCounter = mvStore .registerVersionUsage ();
125136 try {
126- Value v = mvMap .putIfAbsent (key , value );
137+ final Value v = mvMap .putIfAbsent (key , value );
127138 updateLastModifiedTime ();
128139 return v ;
129140 } finally {
@@ -133,8 +144,8 @@ public Value putIfAbsent(Key key, Value value) {
133144
134145 @ Override
135146 public RecordStream <Pair <Key , Value >> entries () {
136- return () -> new Iterator <>() {
137- final Iterator <Map .Entry <Key , Value >> entryIterator = mvMap .entrySet ().iterator ();
147+ return () -> versionedIterator (() -> new Iterator <>() {
148+ private final Iterator <Map .Entry <Key , Value >> entryIterator = mvMap .entrySet ().iterator ();
138149
139150 @ Override
140151 public boolean hasNext () {
@@ -143,15 +154,19 @@ public boolean hasNext() {
143154
144155 @ Override
145156 public Pair <Key , Value > next () {
146- Map .Entry <Key , Value > entry = entryIterator .next ();
157+ final Map .Entry <Key , Value > entry = entryIterator .next ();
147158 return new Pair <>(entry .getKey (), entry .getValue ());
148159 }
149- };
160+ }) ;
150161 }
151162
152163 @ Override
153164 public RecordStream <Pair <Key , Value >> reversedEntries () {
154- return () -> new ReverseIterator <>(mvMap );
165+ return () -> versionedIterator (() -> new ReverseIterator <>(mvMap ));
166+ }
167+
168+ private <Element > Iterator <Element > versionedIterator (final Supplier <Iterator <Element >> iteratorSupplier ) {
169+ return new VersionedIterator <>(mvStore , iteratorSupplier , versionUsages );
155170 }
156171
157172 @ Override
@@ -165,22 +180,22 @@ public Key lastKey() {
165180 }
166181
167182 @ Override
168- public Key higherKey (Key key ) {
183+ public Key higherKey (final Key key ) {
169184 return mvMap .higherKey (key );
170185 }
171186
172187 @ Override
173- public Key ceilingKey (Key key ) {
188+ public Key ceilingKey (final Key key ) {
174189 return mvMap .ceilingKey (key );
175190 }
176191
177192 @ Override
178- public Key lowerKey (Key key ) {
193+ public Key lowerKey (final Key key ) {
179194 return mvMap .lowerKey (key );
180195 }
181196
182197 @ Override
183- public Key floorKey (Key key ) {
198+ public Key floorKey (final Key key ) {
184199 return mvMap .floorKey (key );
185200 }
186201
@@ -194,11 +209,12 @@ public void drop() {
194209 if (!droppedFlag .get ()) {
195210 droppedFlag .compareAndSet (false , true );
196211 closedFlag .compareAndSet (false , true );
212+ releaseVersionUsages ();
197213
198- MVStore .TxCounter txCounter = mvStore .registerVersionUsage ();
214+ final MVStore .TxCounter txCounter = mvStore .registerVersionUsage ();
199215 try {
200- nitriteStore .closeMap (getName ());
201- nitriteStore .removeMap (getName ());
216+ nitriteStore .closeMap (mvMap . getName ());
217+ nitriteStore .removeMap (mvMap . getName ());
202218 } finally {
203219 mvStore .deregisterVersionUsage (txCounter );
204220 }
@@ -214,12 +230,82 @@ public boolean isDropped() {
214230 public void close () {
215231 if (!closedFlag .get () && !droppedFlag .get ()) {
216232 closedFlag .compareAndSet (false , true );
217- nitriteStore .closeMap (getName ());
233+ releaseVersionUsages ();
234+ nitriteStore .closeMap (mvMap .getName ());
218235 }
219236 }
220237
221238 @ Override
222239 public boolean isClosed () {
223240 return closedFlag .get ();
224241 }
242+
243+ private void releaseVersionUsages () {
244+ for (final VersionUsage versionUsage : versionUsages ) {
245+ versionUsage .release ();
246+ }
247+ }
248+
249+ private static class VersionedIterator <Element > implements Iterator <Element > {
250+
251+ private final Iterator <Element > iterator ;
252+ private final Cleaner .Cleanable cleanable ;
253+ private final VersionUsage versionUsage ;
254+ private boolean exhausted ;
255+
256+ private VersionedIterator (final MVStore mvStore ,
257+ final Supplier <Iterator <Element >> iteratorSupplier ,
258+ final Set <VersionUsage > versionUsages ) {
259+
260+ versionUsage = new VersionUsage (mvStore , mvStore .registerVersionUsage (), versionUsages );
261+ versionUsages .add (versionUsage );
262+
263+ try {
264+ this .iterator = iteratorSupplier .get ();
265+ this .cleanable = CLEANER .register (this , versionUsage ::release );
266+ } catch (final RuntimeException | Error e ) {
267+ versionUsage .release ();
268+ throw e ;
269+ }
270+ }
271+
272+ @ Override
273+ public boolean hasNext () {
274+ if (exhausted ) {
275+ return false ;
276+ }
277+ ensureOpen ();
278+ try {
279+ final boolean hasNext = iterator .hasNext ();
280+ if (!hasNext ) {
281+ exhausted = true ;
282+ cleanable .clean ();
283+ }
284+ return hasNext ;
285+ } catch (final RuntimeException | Error e ) {
286+ cleanable .clean ();
287+ throw e ;
288+ }
289+ }
290+
291+ @ Override
292+ public Element next () {
293+ if (exhausted ) {
294+ throw new NoSuchElementException ();
295+ }
296+ ensureOpen ();
297+ try {
298+ return iterator .next ();
299+ } catch (final RuntimeException | Error e ) {
300+ cleanable .clean ();
301+ throw e ;
302+ }
303+ }
304+
305+ private void ensureOpen () {
306+ if (versionUsage .isReleased ()) {
307+ throw new NitriteIOException ("MVStore is closed" );
308+ }
309+ }
310+ }
225311}
0 commit comments