1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002, 2013 Oracle and/or its affiliates.  All rights reserved.
5  *
6  */
7 
8 package com.sleepycat.collections.test;
9 
10 import java.util.ArrayList;
11 import java.util.Collection;
12 import java.util.Collections;
13 import java.util.Enumeration;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.ListIterator;
18 import java.util.Map;
19 import java.util.NoSuchElementException;
20 import java.util.Set;
21 import java.util.SortedMap;
22 import java.util.SortedSet;
23 import java.util.concurrent.ConcurrentMap;
24 
25 import junit.framework.Test;
26 import junit.framework.TestCase;
27 import junit.framework.TestSuite;
28 
29 import com.sleepycat.bind.EntityBinding;
30 import com.sleepycat.bind.EntryBinding;
31 import com.sleepycat.collections.MapEntryParameter;
32 import com.sleepycat.collections.StoredCollection;
33 import com.sleepycat.collections.StoredCollections;
34 import com.sleepycat.collections.StoredContainer;
35 import com.sleepycat.collections.StoredEntrySet;
36 import com.sleepycat.collections.StoredIterator;
37 import com.sleepycat.collections.StoredKeySet;
38 import com.sleepycat.collections.StoredList;
39 import com.sleepycat.collections.StoredMap;
40 import com.sleepycat.collections.StoredSortedEntrySet;
41 import com.sleepycat.collections.StoredSortedKeySet;
42 import com.sleepycat.collections.StoredSortedMap;
43 import com.sleepycat.collections.StoredSortedValueSet;
44 import com.sleepycat.collections.StoredValueSet;
45 import com.sleepycat.collections.TransactionRunner;
46 import com.sleepycat.collections.TransactionWorker;
47 import com.sleepycat.compat.DbCompat;
48 import com.sleepycat.db.Database;
49 import com.sleepycat.db.DatabaseException;
50 import com.sleepycat.db.Environment;
51 import com.sleepycat.util.ExceptionUnwrapper;
52 import com.sleepycat.util.test.SharedTestUtils;
53 import com.sleepycat.util.test.TestEnv;
54 
55 /**
56  * @author Mark Hayes
57  */
58 public class CollectionTest extends TestCase {
59 
60     private static final int NONE = 0;
61     private static final int SUB = 1;
62     private static final int HEAD = 2;
63     private static final int TAIL = 3;
64 
65     /*
66      * For long tests we permute testStoredIterator to test both StoredIterator
67      * and BlockIterator.  When testing BlockIterator, we permute the maxKey
68      * over the array values below.  BlockIterator's block size is 10.  So we
69      * test below the block size (6), at the block size (10), and above it (14
70      * and 22).
71      */
72     private static final int DEFAULT_MAX_KEY = 6;
73     private static final int[] MAX_KEYS = {6, 10, 14, 22};
74 
75     private boolean testStoredIterator;
76     private int maxKey; /* Must be a multiple of 2. */
77     private int beginKey = 1;
78     private int endKey;
79 
80     private Environment env;
81     private Database store;
82     private Database index;
83     private final boolean isEntityBinding;
84     private final boolean isAutoCommit;
85     private TestStore testStore;
86     private String testName;
87     private final EntryBinding keyBinding;
88     private final EntryBinding valueBinding;
89     private final EntityBinding entityBinding;
90     private TransactionRunner readRunner;
91     private TransactionRunner writeRunner;
92     private TransactionRunner writeIterRunner;
93     private TestEnv testEnv;
94 
95     private StoredMap map;
96     private StoredMap imap; // insertable map (primary store for indexed map)
97     private StoredSortedMap smap; // sorted map (null or equal to map)
98     private StoredMap saveMap;
99     private StoredSortedMap saveSMap;
100     private int rangeType;
101     private StoredList list;
102     private StoredList ilist; // insertable list (primary store for index list)
103     private StoredList saveList;
104     private StoredKeySet keySet;
105     private StoredValueSet valueSet;
106 
107     /**
108      * Runs a command line collection test.
109      * @see #usage
110      */
main(String[] args)111     public static void main(String[] args) {
112         if (args.length == 1 &&
113             (args[0].equals("-h") || args[0].equals("-help"))) {
114             usage();
115         } else {
116             junit.framework.TestResult tr =
117                 junit.textui.TestRunner.run(suite(args));
118             if (tr.errorCount() > 0 ||
119                 tr.failureCount() > 0) {
120                 System.exit(1);
121             } else {
122                 System.exit(0);
123             }
124         }
125     }
126 
usage()127     private static void usage() {
128 
129         System.out.println(
130             "Usage: java com.sleepycat.collections.test.CollectionTest\n" +
131             "              -h | -help\n" +
132             "              [testName]...\n" +
133             "  where testName has the format:\n" +
134             "    <env>-<store>-{entity|value}\n" +
135             "  <env> is:\n" +
136             "    bdb | cdb | txn\n" +
137             "  <store> is:\n" +
138             "    btree-uniq | btree-dup | btree-dupsort | btree-recnum |\n" +
139             "    hash-uniq | hash-dup | hash-dupsort |\n" +
140             "    queue | recno | recno-renum\n" +
141             "  For example:  bdb-btree-uniq-entity\n" +
142             "  If no arguments are given then all tests are run.");
143         System.exit(2);
144     }
145 
suite()146     public static Test suite() {
147         return suite(null);
148     }
149 
suite(String[] args)150     static Test suite(String[] args) {
151         if (SharedTestUtils.runLongTests()) {
152             TestSuite suite = new TestSuite();
153 
154             /* StoredIterator tests. */
155             permuteTests(args, suite, true, DEFAULT_MAX_KEY);
156 
157             /* BlockIterator tests with different maxKey values. */
158             for (int i = 0; i < MAX_KEYS.length; i += 1) {
159                 permuteTests(args, suite, false, MAX_KEYS[i]);
160             }
161 
162             return suite;
163         } else {
164             return baseSuite(args);
165         }
166     }
167 
permuteTests(String[] args, TestSuite suite, boolean storedIter, int maxKey)168     private static void permuteTests(String[] args,
169                                      TestSuite suite,
170                                      boolean storedIter,
171                                      int maxKey) {
172        TestSuite baseTests = baseSuite(args);
173         Enumeration e = baseTests.tests();
174         while (e.hasMoreElements()) {
175             CollectionTest t = (CollectionTest) e.nextElement();
176             t.setParams(storedIter, maxKey);
177             suite.addTest(t);
178         }
179     }
180 
baseSuite(String[] args)181     private static TestSuite baseSuite(String[] args) {
182         TestSuite suite = new TestSuite();
183         for (int i = 0; i < TestEnv.ALL.length; i += 1) {
184             for (int j = 0; j < TestStore.ALL.length; j += 1) {
185                 for (int k = 0; k < 2; k += 1) {
186                     boolean entityBinding = (k != 0);
187 
188                     addTest(args, suite, new CollectionTest(
189                             TestEnv.ALL[i], TestStore.ALL[j],
190                             entityBinding, false));
191 
192                     if (TestEnv.ALL[i].isTxnMode()) {
193                         addTest(args, suite, new CollectionTest(
194                                 TestEnv.ALL[i], TestStore.ALL[j],
195                                 entityBinding, true));
196                     }
197                 }
198             }
199         }
200         return suite;
201     }
202 
addTest(String[] args, TestSuite suite, CollectionTest test)203     private static void addTest(String[] args, TestSuite suite,
204                                 CollectionTest test) {
205 
206         if (args == null || args.length == 0) {
207             suite.addTest(test);
208         } else {
209             for (int t = 0; t < args.length; t += 1) {
210                 if (args[t].equals(test.testName)) {
211                     suite.addTest(test);
212                     break;
213                 }
214             }
215         }
216     }
217 
CollectionTest(TestEnv testEnv, TestStore testStore, boolean isEntityBinding, boolean isAutoCommit)218     public CollectionTest(TestEnv testEnv, TestStore testStore,
219                           boolean isEntityBinding, boolean isAutoCommit) {
220 
221         super(null);
222 
223         this.testEnv = testEnv;
224         this.testStore = testStore;
225         this.isEntityBinding = isEntityBinding;
226         this.isAutoCommit = isAutoCommit;
227 
228         keyBinding = testStore.getKeyBinding();
229         valueBinding = testStore.getValueBinding();
230         entityBinding = testStore.getEntityBinding();
231 
232         setParams(false, DEFAULT_MAX_KEY);
233     }
234 
setParams(boolean storedIter, int maxKey)235     private void setParams(boolean storedIter, int maxKey) {
236 
237         this.testStoredIterator = storedIter;
238         this.maxKey = maxKey;
239         this.endKey = maxKey;
240 
241         testName = testEnv.getName() + '-' + testStore.getName() +
242                     (isEntityBinding ? "-entity" : "-value") +
243                     (isAutoCommit ? "-autoCommit" : "") +
244                     (testStoredIterator ? "-storedIter" : "") +
245                     ((maxKey != DEFAULT_MAX_KEY) ? ("-maxKey-" + maxKey) : "");
246     }
247 
248     @Override
tearDown()249     public void tearDown() {
250         setName(testName);
251     }
252 
253     @Override
runTest()254     public void runTest()
255         throws Exception {
256 
257         SharedTestUtils.printTestName(SharedTestUtils.qualifiedTestName(this));
258         try {
259             env = testEnv.open(testName);
260 
261             // For testing auto-commit, use a normal (transactional) runner for
262             // all reading and for writing via an iterator, and a do-nothing
263             // runner for writing via collections; if auto-commit is tested,
264             // the per-collection auto-commit property will be set elsewhere.
265             //
266             TransactionRunner normalRunner = newTransactionRunner(env);
267             normalRunner.setAllowNestedTransactions(
268                     DbCompat.NESTED_TRANSACTIONS);
269             TransactionRunner nullRunner = new NullTransactionRunner(env);
270             readRunner = nullRunner;
271             if (isAutoCommit) {
272                 writeRunner = nullRunner;
273                 writeIterRunner = testStoredIterator ? normalRunner
274                                                      : nullRunner;
275             } else {
276                 writeRunner = normalRunner;
277                 writeIterRunner = normalRunner;
278             }
279 
280             store = testStore.open(env, "unindexed.db");
281             testUnindexed();
282             store.close();
283             store = null;
284 
285             TestStore indexOf = testStore.getIndexOf();
286             if (indexOf != null) {
287                 store = indexOf.open(env, "indexed.db");
288                 index = testStore.openIndex(store, "index.db");
289                 testIndexed();
290                 index.close();
291                 index = null;
292                 store.close();
293                 store = null;
294             }
295             env.close();
296             env = null;
297         } catch (Exception e) {
298             throw ExceptionUnwrapper.unwrap(e);
299         } finally {
300             if (index != null) {
301                 try {
302                     index.close();
303                 } catch (Exception e) {
304                 }
305             }
306             if (store != null) {
307                 try {
308                     store.close();
309                 } catch (Exception e) {
310                 }
311             }
312             if (env != null) {
313                 try {
314                     env.close();
315                 } catch (Exception e) {
316                 }
317             }
318             /* Ensure that GC can cleanup. */
319             index = null;
320             store = null;
321             env = null;
322             readRunner = null;
323             writeRunner = null;
324             writeIterRunner = null;
325             map = null;
326             imap = null;
327             smap = null;
328             saveMap = null;
329             saveSMap = null;
330             list = null;
331             ilist = null;
332             saveList = null;
333             keySet = null;
334             valueSet = null;
335             testEnv = null;
336             testStore = null;
337         }
338     }
339 
340     /**
341      * Is overridden in XACollectionTest.
342      * @throws DatabaseException from subclasses.
343      */
newTransactionRunner(Environment env)344     protected TransactionRunner newTransactionRunner(Environment env)
345         throws DatabaseException {
346 
347         return new TransactionRunner(env);
348     }
349 
testCreation(StoredContainer cont, int expectSize)350     void testCreation(StoredContainer cont, int expectSize) {
351         assertEquals(index != null, cont.isSecondary());
352         assertEquals(testStore.isOrdered(), cont.isOrdered());
353         assertEquals(testStore.areKeyRangesAllowed(),
354                      cont.areKeyRangesAllowed());
355         assertEquals(testStore.areKeysRenumbered(), cont.areKeysRenumbered());
356         assertEquals(testStore.areDuplicatesAllowed(),
357                      cont.areDuplicatesAllowed());
358         assertEquals(testEnv.isTxnMode(), cont.isTransactional());
359         assertEquals(expectSize, cont.size());
360     }
361 
testMapCreation(ConcurrentMap map)362     void testMapCreation(ConcurrentMap map) {
363         assertTrue(map.values() instanceof Set);
364         assertEquals(testStore.areKeyRangesAllowed(),
365                      map.keySet() instanceof SortedSet);
366         assertEquals(testStore.areKeyRangesAllowed(),
367                      map.entrySet() instanceof SortedSet);
368         assertEquals(testStore.areKeyRangesAllowed() && isEntityBinding,
369                      map.values() instanceof SortedSet);
370     }
371 
testUnindexed()372     void testUnindexed()
373         throws Exception {
374 
375         // create primary map
376         if (testStore.areKeyRangesAllowed()) {
377             if (isEntityBinding) {
378                 smap = new StoredSortedMap(store, keyBinding,
379                                            entityBinding,
380                                            testStore.getKeyAssigner());
381                 valueSet = new StoredSortedValueSet(store, entityBinding,
382                                                     true);
383             } else {
384                 smap = new StoredSortedMap(store, keyBinding,
385                                            valueBinding,
386                                            testStore.getKeyAssigner());
387                 // sorted value set is not possible since key cannot be derived
388                 // for performing subSet, etc.
389             }
390             keySet = new StoredSortedKeySet(store, keyBinding, true);
391             map = smap;
392         } else {
393             if (isEntityBinding) {
394                 map = new StoredMap(store, keyBinding, entityBinding,
395                                     testStore.getKeyAssigner());
396                 valueSet = new StoredValueSet(store, entityBinding, true);
397             } else {
398                 map = new StoredMap(store, keyBinding, valueBinding,
399                                     testStore.getKeyAssigner());
400                 valueSet = new StoredValueSet(store, valueBinding, true);
401             }
402             smap = null;
403             keySet = new StoredKeySet(store, keyBinding, true);
404         }
405         imap = map;
406 
407         // create primary list
408         if (testStore.hasRecNumAccess()) {
409             if (isEntityBinding) {
410                 ilist = new StoredList(store, entityBinding,
411                                        testStore.getKeyAssigner());
412             } else {
413                 ilist = new StoredList(store, valueBinding,
414                                        testStore.getKeyAssigner());
415             }
416             list = ilist;
417         } else {
418             try {
419                 if (isEntityBinding) {
420                     ilist = new StoredList(store, entityBinding,
421                                            testStore.getKeyAssigner());
422                 } else {
423                     ilist = new StoredList(store, valueBinding,
424                                            testStore.getKeyAssigner());
425                 }
426                 fail();
427             } catch (IllegalArgumentException expected) {}
428         }
429 
430         testCreation(map, 0);
431         if (list != null) {
432             testCreation(list, 0);
433         }
434         testMapCreation(map);
435         addAll();
436         testAll();
437     }
438 
testIndexed()439     void testIndexed()
440         throws Exception {
441 
442         // create primary map
443         if (isEntityBinding) {
444             map = new StoredMap(store, keyBinding, entityBinding,
445                                 testStore.getKeyAssigner());
446         } else {
447             map = new StoredMap(store, keyBinding, valueBinding,
448                                 testStore.getKeyAssigner());
449         }
450         imap = map;
451         smap = null;
452         // create primary list
453         if (testStore.hasRecNumAccess()) {
454             if (isEntityBinding) {
455                 list = new StoredList(store, entityBinding,
456                                       testStore.getKeyAssigner());
457             } else {
458                 list = new StoredList(store, valueBinding,
459                                       testStore.getKeyAssigner());
460             }
461             ilist = list;
462         }
463 
464         addAll();
465         readAll();
466 
467         // create indexed map (keySet/valueSet)
468         if (testStore.areKeyRangesAllowed()) {
469             if (isEntityBinding) {
470                 map = smap = new StoredSortedMap(index, keyBinding,
471                                                  entityBinding, true);
472                 valueSet = new StoredSortedValueSet(index, entityBinding,
473                                                     true);
474             } else {
475                 map = smap = new StoredSortedMap(index, keyBinding,
476                                                  valueBinding, true);
477                 // sorted value set is not possible since key cannot be derived
478                 // for performing subSet, etc.
479             }
480             keySet = new StoredSortedKeySet(index, keyBinding, true);
481         } else {
482             if (isEntityBinding) {
483                 map = new StoredMap(index, keyBinding, entityBinding, true);
484                 valueSet = new StoredValueSet(index, entityBinding, true);
485             } else {
486                 map = new StoredMap(index, keyBinding, valueBinding, true);
487                 valueSet = new StoredValueSet(index, valueBinding, true);
488             }
489             smap = null;
490             keySet = new StoredKeySet(index, keyBinding, true);
491         }
492 
493         // create indexed list
494         if (testStore.hasRecNumAccess()) {
495             if (isEntityBinding) {
496                 list = new StoredList(index, entityBinding, true);
497             } else {
498                 list = new StoredList(index, valueBinding, true);
499             }
500         } else {
501             try {
502                 if (isEntityBinding) {
503                     list = new StoredList(index, entityBinding, true);
504                 } else {
505                     list = new StoredList(index, valueBinding, true);
506                 }
507                 fail();
508             } catch (IllegalArgumentException expected) {}
509         }
510 
511         testCreation(map, maxKey);
512         testCreation((StoredContainer) map.values(), maxKey);
513         testCreation((StoredContainer) map.keySet(), maxKey);
514         testCreation((StoredContainer) map.entrySet(), maxKey);
515         if (list != null) {
516             testCreation(list, maxKey);
517         }
518         testMapCreation(map);
519         testAll();
520     }
521 
testAll()522     void testAll()
523         throws Exception {
524 
525         checkKeySetAndValueSet();
526         readAll();
527         updateAll();
528         readAll();
529         if (!map.areKeysRenumbered()) {
530             removeOdd();
531             readEven();
532             addOdd();
533             readAll();
534             removeOddIter();
535             readEven();
536             if (imap.areDuplicatesAllowed()) {
537                 addOddDup();
538             } else {
539                 addOdd();
540             }
541             readAll();
542             removeOddEntry();
543             readEven();
544             addOdd();
545             readAll();
546             if (isEntityBinding) {
547                 removeOddEntity();
548                 readEven();
549                 addOddEntity();
550                 readAll();
551             }
552             bulkOperations();
553         }
554         if (isListAddAllowed()) {
555             removeOddList();
556             readEvenList();
557             addOddList();
558             readAll();
559             if (!isEntityBinding) {
560                 removeOddListValue();
561                 readEvenList();
562                 addOddList();
563                 readAll();
564             }
565         }
566         if (list != null) {
567             bulkListOperations();
568         } else {
569             listOperationsNotAllowed();
570         }
571         if (smap != null) {
572             readWriteRange(SUB,  1, 1);
573             readWriteRange(HEAD, 1, 1);
574             readWriteRange(SUB,  1, maxKey);
575             readWriteRange(HEAD, 1, maxKey);
576             readWriteRange(TAIL, 1, maxKey);
577             readWriteRange(SUB,  1, 3);
578             readWriteRange(HEAD, 1, 3);
579             readWriteRange(SUB,  2, 2);
580             readWriteRange(SUB,  2, maxKey);
581             readWriteRange(TAIL, 2, maxKey);
582             readWriteRange(SUB,  maxKey, maxKey);
583             readWriteRange(TAIL, maxKey, maxKey);
584             readWriteRange(SUB,  maxKey + 1, maxKey + 1);
585             readWriteRange(TAIL, maxKey + 1, maxKey + 1);
586             readWriteRange(SUB,  0, 0);
587             readWriteRange(HEAD, 0, 0);
588         }
589         updateAll();
590         readAll();
591         if (map.areDuplicatesAllowed()) {
592             readWriteDuplicates();
593             readAll();
594         } else {
595             duplicatesNotAllowed();
596             readAll();
597         }
598         if (testEnv.isCdbMode()) {
599             testCdbLocking();
600         }
601         removeAll();
602         if (!map.areKeysRenumbered()) {
603             testConcurrentMap();
604         }
605         if (isListAddAllowed()) {
606             testIterAddList();
607             clearAll();
608         }
609         if (imap.areDuplicatesAllowed()) {
610             testIterAddDuplicates();
611             clearAll();
612         }
613         if (isListAddAllowed()) {
614             addAllList();
615             readAll();
616             removeAllList();
617         }
618         appendAll();
619     }
620 
checkKeySetAndValueSet()621     void checkKeySetAndValueSet() {
622 
623         // use bulk operations to check that explicitly constructed
624         // keySet/valueSet are equivalent
625         assertEquals(keySet, imap.keySet());
626         if (valueSet != null) {
627             assertEquals(valueSet, imap.values());
628         }
629     }
630 
iterator(Collection storedCollection)631     Iterator iterator(Collection storedCollection) {
632 
633         if (testStoredIterator) {
634             return ((StoredCollection) storedCollection).storedIterator();
635         } else {
636             return storedCollection.iterator();
637         }
638     }
639 
addAll()640     void addAll()
641         throws Exception {
642 
643         writeRunner.run(new TransactionWorker() {
644             public void doWork() {
645                 assertTrue(imap.isEmpty());
646                 Iterator iter = iterator(imap.entrySet());
647                 try {
648                     assertTrue(!iter.hasNext());
649                 } finally {
650                     StoredIterator.close(iter);
651                 }
652                 assertEquals(0, imap.keySet().toArray().length);
653                 assertEquals(0, imap.keySet().toArray(new Object[0]).length);
654                 assertEquals(0, imap.entrySet().toArray().length);
655                 assertEquals(0, imap.entrySet().toArray(new Object[0]).length);
656                 assertEquals(0, imap.values().toArray().length);
657                 assertEquals(0, imap.values().toArray(new Object[0]).length);
658 
659                 for (int i = beginKey; i <= endKey; i += 1) {
660                     Long key = makeKey(i);
661                     Object val = makeVal(i);
662                     assertNull(imap.get(key));
663                     assertTrue(!imap.keySet().contains(key));
664                     assertTrue(!imap.values().contains(val));
665                     assertNull(imap.put(key, val));
666                     assertEquals(val, imap.get(key));
667                     assertTrue(imap.keySet().contains(key));
668                     assertTrue(imap.values().contains(val));
669                     assertTrue(imap.duplicates(key).contains(val));
670                     if (!imap.areDuplicatesAllowed()) {
671                         assertEquals(val, imap.put(key, val));
672                     }
673                     checkDupsSize(1, imap.duplicates(key));
674                 }
675                 assertTrue(!imap.isEmpty());
676             }
677         });
678     }
679 
appendAll()680     void appendAll()
681         throws Exception {
682 
683         writeRunner.run(new TransactionWorker() {
684             public void doWork() {
685                 assertTrue(imap.isEmpty());
686 
687                 TestKeyAssigner keyAssigner = testStore.getKeyAssigner();
688                 if (keyAssigner != null) {
689                     keyAssigner.reset();
690                 }
691 
692                 for (int i = beginKey; i <= endKey; i += 1) {
693                     boolean useList = (i & 1) == 0;
694                     Long key = makeKey(i);
695                     Object val = makeVal(i);
696                     assertNull(imap.get(key));
697                     if (keyAssigner != null) {
698                         if (useList && ilist != null) {
699                             assertEquals(i - 1, ilist.append(val));
700                         } else {
701                             assertEquals(key, imap.append(val));
702                         }
703                         assertEquals(val, imap.get(key));
704                     } else {
705                         Long recnoKey;
706                         if (useList && ilist != null) {
707                             recnoKey = new Long(ilist.append(val) + 1);
708                         } else {
709                             recnoKey = (Long) imap.append(val);
710                         }
711                         assertNotNull(recnoKey);
712                         Object recnoVal;
713                         if (isEntityBinding) {
714                             recnoVal = makeEntity(recnoKey.intValue(), i);
715                         } else {
716                             recnoVal = val;
717                         }
718                         assertEquals(recnoVal, imap.get(recnoKey));
719                     }
720                 }
721             }
722         });
723     }
724 
updateAll()725     void updateAll()
726         throws Exception {
727 
728         writeRunner.run(new TransactionWorker() {
729             public void doWork() throws Exception {
730                 for (int i = beginKey; i <= endKey; i += 1) {
731                     Long key = makeKey(i);
732                     Object val = makeVal(i);
733                     if (!imap.areDuplicatesAllowed()) {
734                         assertEquals(val, imap.put(key, val));
735                     }
736                     if (isEntityBinding) {
737                         assertTrue(!imap.values().add(val));
738                     }
739                     checkDupsSize(1, imap.duplicates(key));
740                     if (ilist != null) {
741                         int idx = i - 1;
742                         assertEquals(val, ilist.set(idx, val));
743                     }
744                 }
745                 updateIter(map.entrySet());
746                 updateIter(map.values());
747                 if (beginKey <= endKey) {
748                     ListIterator iter = (ListIterator) iterator(map.keySet());
749                     try {
750                         assertNotNull(iter.next());
751                         iter.set(makeKey(beginKey));
752                         fail();
753                     } catch (UnsupportedOperationException e) {
754                     } finally {
755                         StoredIterator.close(iter);
756                     }
757                 }
758                 if (list != null) {
759                     updateIter(list);
760                 }
761             }
762         });
763     }
764 
updateIter(final Collection coll)765     void updateIter(final Collection coll)
766         throws Exception {
767 
768         writeIterRunner.run(new TransactionWorker() {
769             public void doWork() {
770                 ListIterator iter = (ListIterator) iterator(coll);
771                 try {
772                     for (int i = beginKey; i <= endKey; i += 1) {
773                         assertTrue(iter.hasNext());
774                         Object obj = iter.next();
775                         if (map.isOrdered()) {
776                             assertEquals(i, intIter(coll, obj));
777                         }
778                         if (index != null) {
779                             try {
780                                 setValuePlusOne(iter, obj);
781                                 fail();
782                             } catch (UnsupportedOperationException e) {}
783                         } else if
784                            (((StoredCollection) coll).areDuplicatesOrdered()) {
785                             try {
786                                 setValuePlusOne(iter, obj);
787                                 fail();
788                             } catch (RuntimeException e) {
789                                 Exception e2 = ExceptionUnwrapper.unwrap(e);
790                                 assertTrue(e2.getClass().getName(),
791                                       e2 instanceof IllegalArgumentException ||
792                                       e2 instanceof DatabaseException);
793                             }
794                         } else {
795                             setValuePlusOne(iter, obj);
796                             /* Ensure iterator position is correct. */
797                             if (map.isOrdered()) {
798                                 assertTrue(iter.hasPrevious());
799                                 obj = iter.previous();
800                                 assertEquals(i, intIter(coll, obj));
801                                 assertTrue(iter.hasNext());
802                                 obj = iter.next();
803                                 assertEquals(i, intIter(coll, obj));
804                             }
805                         }
806                     }
807                     assertTrue(!iter.hasNext());
808                 } finally {
809                     StoredIterator.close(iter);
810                 }
811             }
812         });
813     }
814 
setValuePlusOne(ListIterator iter, Object obj)815     void setValuePlusOne(ListIterator iter, Object obj) {
816 
817         if (obj instanceof Map.Entry) {
818             Map.Entry entry = (Map.Entry) obj;
819             Long key = (Long) entry.getKey();
820             Object oldVal = entry.getValue();
821             Object val = makeVal(key.intValue() + 1);
822             if (isEntityBinding) {
823                 try {
824                     // must fail on attempt to change the key via an entity
825                     entry.setValue(val);
826                     fail();
827                 } catch (IllegalArgumentException e) {}
828                 val = makeEntity(key.intValue(), key.intValue() + 1);
829             }
830             entry.setValue(val);
831             assertEquals(val, entry.getValue());
832             assertEquals(val, map.get(key));
833             assertTrue(map.duplicates(key).contains(val));
834             checkDupsSize(1, map.duplicates(key));
835             entry.setValue(oldVal);
836             assertEquals(oldVal, entry.getValue());
837             assertEquals(oldVal, map.get(key));
838             assertTrue(map.duplicates(key).contains(oldVal));
839             checkDupsSize(1, map.duplicates(key));
840         } else {
841             Object oldVal = obj;
842             Long key = makeKey(intVal(obj));
843             Object val = makeVal(key.intValue() + 1);
844             if (isEntityBinding) {
845                 try {
846                     // must fail on attempt to change the key via an entity
847                     iter.set(val);
848                     fail();
849                 } catch (IllegalArgumentException e) {}
850                 val = makeEntity(key.intValue(), key.intValue() + 1);
851             }
852             iter.set(val);
853             assertEquals(val, map.get(key));
854             assertTrue(map.duplicates(key).contains(val));
855             checkDupsSize(1, map.duplicates(key));
856             iter.set(oldVal);
857             assertEquals(oldVal, map.get(key));
858             assertTrue(map.duplicates(key).contains(oldVal));
859             checkDupsSize(1, map.duplicates(key));
860         }
861     }
862 
removeAll()863     void removeAll()
864         throws Exception {
865 
866         writeIterRunner.run(new TransactionWorker() {
867             public void doWork() {
868                 assertTrue(!map.isEmpty());
869                 ListIterator iter = null;
870                 try {
871                     if (list != null) {
872                         iter = (ListIterator) iterator(list);
873                     } else {
874                         iter = (ListIterator) iterator(map.values());
875                     }
876                     iteratorSetAndRemoveNotAllowed(iter);
877 
878                     Object val = iter.next();
879                     assertNotNull(val);
880                     iter.remove();
881                     iteratorSetAndRemoveNotAllowed(iter);
882 
883                     if (index == null) {
884                         val = iter.next();
885                         assertNotNull(val);
886                         iter.set(val);
887 
888                         if (map.areDuplicatesAllowed()) {
889                             iter.add(makeVal(intVal(val), intVal(val) + 1));
890                             iteratorSetAndRemoveNotAllowed(iter);
891                         }
892                     }
893                 } finally {
894                     StoredIterator.close(iter);
895                 }
896                 map.clear();
897                 assertTrue(map.isEmpty());
898                 assertTrue(map.entrySet().isEmpty());
899                 assertTrue(map.keySet().isEmpty());
900                 assertTrue(map.values().isEmpty());
901                 for (int i = beginKey; i <= endKey; i += 1) {
902                     Long key = makeKey(i);
903                     Object val = makeVal(i);
904                     assertNull(map.get(key));
905                     assertTrue(!map.duplicates(key).contains(val));
906                     checkDupsSize(0, map.duplicates(key));
907                 }
908             }
909         });
910     }
911 
clearAll()912     void clearAll()
913         throws Exception {
914 
915         writeRunner.run(new TransactionWorker() {
916             public void doWork() {
917                 map.clear();
918                 assertTrue(map.isEmpty());
919             }
920         });
921     }
922 
923     /**
924      * Tests that removing while iterating works properly, especially when
925      * removing everything in the key range or everything from some point to
926      * the end of the range. [#15858]
927      */
removeIter()928     void removeIter()
929         throws Exception {
930 
931         writeIterRunner.run(new TransactionWorker() {
932             public void doWork() {
933                 ListIterator iter;
934 
935                 /* Save contents. */
936                 HashMap<Object, Object> savedMap =
937                     new HashMap<Object, Object>(map);
938                 assertEquals(savedMap, map);
939 
940                 /* Remove all moving forward. */
941                 iter = (ListIterator) iterator(map.keySet());
942                 try {
943                     while (iter.hasNext()) {
944                         assertNotNull(iter.next());
945                         iter.remove();
946                     }
947                     assertTrue(!iter.hasNext());
948                     assertTrue(!iter.hasPrevious());
949                     assertTrue(map.isEmpty());
950                 } finally {
951                     StoredIterator.close(iter);
952                 }
953 
954                 /* Restore contents. */
955                 imap.putAll(savedMap);
956                 assertEquals(savedMap, map);
957 
958                 /* Remove all moving backward. */
959                 iter = (ListIterator) iterator(map.keySet());
960                 try {
961                     while (iter.hasNext()) {
962                         assertNotNull(iter.next());
963                     }
964                     while (iter.hasPrevious()) {
965                         assertNotNull(iter.previous());
966                         iter.remove();
967                     }
968                     assertTrue(map.toString(), !iter.hasNext());
969                     assertTrue(!iter.hasPrevious());
970                     assertTrue(map.isEmpty());
971                 } finally {
972                     StoredIterator.close(iter);
973                 }
974 
975                 /* Restore contents. */
976                 imap.putAll(savedMap);
977                 assertEquals(savedMap, map);
978 
979                 int first = Math.max(1, beginKey);
980                 int last = Math.min(maxKey, endKey);
981 
982                 /* Skip N forward, remove all from that point forward. */
983                 for (int readTo = first + 1; readTo <= last; readTo += 1) {
984                     iter = (ListIterator) iterator(map.keySet());
985                     try {
986                         for (int i = first; i < readTo; i += 1) {
987                             assertTrue(iter.hasNext());
988                             assertNotNull(iter.next());
989                         }
990                         for (int i = readTo; i <= last; i += 1) {
991                             assertTrue(iter.hasNext());
992                             assertNotNull(iter.next());
993                             iter.remove();
994                         }
995                         assertTrue(!iter.hasNext());
996                         assertTrue(iter.hasPrevious());
997                         assertEquals(readTo - first, map.size());
998                     } finally {
999                         StoredIterator.close(iter);
1000                     }
1001 
1002                     /* Restore contents. */
1003                     for (Map.Entry entry : savedMap.entrySet()) {
1004                         if (!imap.entrySet().contains(entry)) {
1005                             imap.put(entry.getKey(), entry.getValue());
1006                         }
1007                     }
1008                     assertEquals(savedMap, map);
1009                 }
1010 
1011                 /* Skip N backward, remove all from that point backward. */
1012                 for (int readTo = last - 1; readTo >= first; readTo -= 1) {
1013                     iter = (ListIterator) iterator(map.keySet());
1014                     try {
1015                         while (iter.hasNext()) {
1016                             assertNotNull(iter.next());
1017                         }
1018                         for (int i = last; i > readTo; i -= 1) {
1019                             assertTrue(iter.hasPrevious());
1020                             assertNotNull(iter.previous());
1021                         }
1022                         for (int i = readTo; i >= first; i -= 1) {
1023                             assertTrue(iter.hasPrevious());
1024                             assertNotNull(iter.previous());
1025                             iter.remove();
1026                         }
1027                         assertTrue(!iter.hasPrevious());
1028                         assertTrue(iter.hasNext());
1029                         assertEquals(last - readTo, map.size());
1030                     } finally {
1031                         StoredIterator.close(iter);
1032                     }
1033 
1034                     /* Restore contents. */
1035                     for (Map.Entry entry : savedMap.entrySet()) {
1036                         if (!imap.entrySet().contains(entry)) {
1037                             imap.put(entry.getKey(), entry.getValue());
1038                         }
1039                     }
1040                     assertEquals(savedMap, map);
1041                 }
1042             }
1043         });
1044     }
1045 
iteratorSetAndRemoveNotAllowed(ListIterator i)1046     void iteratorSetAndRemoveNotAllowed(ListIterator i) {
1047 
1048         try {
1049             i.remove();
1050             fail();
1051         } catch (IllegalStateException e) {}
1052 
1053         if (index == null) {
1054             try {
1055                 Object val = makeVal(1);
1056                 i.set(val);
1057                 fail();
1058             } catch (IllegalStateException e) {}
1059         }
1060     }
1061 
removeOdd()1062     void removeOdd()
1063         throws Exception {
1064 
1065         writeRunner.run(new TransactionWorker() {
1066             public void doWork() {
1067                 boolean toggle = false;
1068                 for (int i = beginKey; i <= endKey; i += 2) {
1069                     toggle = !toggle;
1070                     Long key = makeKey(i);
1071                     Object val = makeVal(i);
1072                     if (toggle) {
1073                         assertTrue(map.keySet().contains(key));
1074                         assertTrue(map.keySet().remove(key));
1075                         assertTrue(!map.keySet().contains(key));
1076                     } else {
1077                         assertTrue(map.containsValue(val));
1078                         Object oldVal = map.remove(key);
1079                         assertEquals(oldVal, val);
1080                         assertTrue(!map.containsKey(key));
1081                         assertTrue(!map.containsValue(val));
1082                     }
1083                     assertNull(map.get(key));
1084                     assertTrue(!map.duplicates(key).contains(val));
1085                     checkDupsSize(0, map.duplicates(key));
1086                 }
1087             }
1088         });
1089     }
1090 
removeOddEntity()1091     void removeOddEntity()
1092         throws Exception {
1093 
1094         writeRunner.run(new TransactionWorker() {
1095             public void doWork() {
1096                 for (int i = beginKey; i <= endKey; i += 2) {
1097                     Long key = makeKey(i);
1098                     Object val = makeVal(i);
1099                     assertTrue(map.values().contains(val));
1100                     assertTrue(map.values().remove(val));
1101                     assertTrue(!map.values().contains(val));
1102                     assertNull(map.get(key));
1103                     assertTrue(!map.duplicates(key).contains(val));
1104                     checkDupsSize(0, map.duplicates(key));
1105                 }
1106             }
1107         });
1108     }
1109 
removeOddEntry()1110     void removeOddEntry()
1111         throws Exception {
1112 
1113         writeRunner.run(new TransactionWorker() {
1114             public void doWork() {
1115                 for (int i = beginKey; i <= endKey; i += 2) {
1116                     Long key = makeKey(i);
1117                     Object val = mapEntry(i);
1118                     assertTrue(map.entrySet().contains(val));
1119                     assertTrue(map.entrySet().remove(val));
1120                     assertTrue(!map.entrySet().contains(val));
1121                     assertNull(map.get(key));
1122                 }
1123             }
1124         });
1125     }
1126 
removeOddIter()1127     void removeOddIter()
1128         throws Exception {
1129 
1130         writeIterRunner.run(new TransactionWorker() {
1131             public void doWork() {
1132                 Iterator iter = iterator(map.keySet());
1133                 try {
1134                     for (int i = beginKey; i <= endKey; i += 1) {
1135                         assertTrue(iter.hasNext());
1136                         Long key = (Long) iter.next();
1137                         assertNotNull(key);
1138                         if (map instanceof SortedMap) {
1139                             assertEquals(makeKey(i), key);
1140                         }
1141                         if ((key.intValue() & 1) != 0) {
1142                             iter.remove();
1143                         }
1144                     }
1145                 } finally {
1146                     StoredIterator.close(iter);
1147                 }
1148             }
1149         });
1150     }
1151 
removeOddList()1152     void removeOddList()
1153         throws Exception {
1154 
1155         writeRunner.run(new TransactionWorker() {
1156             public void doWork() {
1157                 for (int i = beginKey; i <= endKey; i += 2) {
1158                     // remove by index
1159                     // (with entity binding, embbeded keys in values are
1160                     // being changed so we can't use values for comparison)
1161                     int idx = (i - beginKey) / 2;
1162                     Object val = makeVal(i);
1163                     if (!isEntityBinding) {
1164                         assertTrue(list.contains(val));
1165                         assertEquals(val, list.get(idx));
1166                         assertEquals(idx, list.indexOf(val));
1167                     }
1168                     assertNotNull(list.get(idx));
1169                     if (isEntityBinding) {
1170                         assertNotNull(list.remove(idx));
1171                     } else {
1172                         assertTrue(list.contains(val));
1173                         assertEquals(val, list.remove(idx));
1174                     }
1175                     assertTrue(!list.remove(val));
1176                     assertTrue(!list.contains(val));
1177                     assertTrue(!val.equals(list.get(idx)));
1178                 }
1179             }
1180         });
1181     }
1182 
removeOddListValue()1183     void removeOddListValue()
1184         throws Exception {
1185 
1186         writeRunner.run(new TransactionWorker() {
1187             public void doWork() {
1188                 for (int i = beginKey; i <= endKey; i += 2) {
1189                     // for non-entity case remove by value
1190                     // (with entity binding, embbeded keys in values are
1191                     // being changed so we can't use values for comparison)
1192                     int idx = (i - beginKey) / 2;
1193                     Object val = makeVal(i);
1194                     assertTrue(list.contains(val));
1195                     assertEquals(val, list.get(idx));
1196                     assertEquals(idx, list.indexOf(val));
1197                     assertTrue(list.remove(val));
1198                     assertTrue(!list.remove(val));
1199                     assertTrue(!list.contains(val));
1200                     assertTrue(!val.equals(list.get(idx)));
1201                 }
1202             }
1203         });
1204     }
1205 
addOdd()1206     void addOdd()
1207         throws Exception {
1208 
1209         writeRunner.run(new TransactionWorker() {
1210             public void doWork() {
1211                 // add using Map.put()
1212                 for (int i = beginKey; i <= endKey; i += 2) {
1213                     Long key = makeKey(i);
1214                     Object val = makeVal(i);
1215                     assertNull(imap.get(key));
1216                     assertNull(imap.put(key, val));
1217                     assertEquals(val, imap.get(key));
1218                     assertTrue(imap.duplicates(key).contains(val));
1219                     checkDupsSize(1, imap.duplicates(key));
1220                     if (isEntityBinding) {
1221                         assertTrue(!imap.values().add(val));
1222                     }
1223                     if (!imap.areDuplicatesAllowed()) {
1224                         assertEquals(val, imap.put(key, val));
1225                     }
1226                 }
1227             }
1228         });
1229     }
1230 
addOddEntity()1231     void addOddEntity()
1232         throws Exception {
1233 
1234         writeRunner.run(new TransactionWorker() {
1235             public void doWork() {
1236                 // add using Map.values().add()
1237                 for (int i = beginKey; i <= endKey; i += 2) {
1238                     Long key = makeKey(i);
1239                     Object val = makeVal(i);
1240                     assertNull(imap.get(key));
1241                     assertTrue(!imap.values().contains(val));
1242                     assertTrue(imap.values().add(val));
1243                     assertEquals(val, imap.get(key));
1244                     assertTrue(imap.values().contains(val));
1245                     assertTrue(imap.duplicates(key).contains(val));
1246                     checkDupsSize(1, imap.duplicates(key));
1247                     if (isEntityBinding) {
1248                         assertTrue(!imap.values().add(val));
1249                     }
1250                 }
1251             }
1252         });
1253     }
1254 
addOddDup()1255     void addOddDup()
1256         throws Exception {
1257 
1258         writeRunner.run(new TransactionWorker() {
1259             public void doWork() {
1260                 // add using Map.duplicates().add()
1261                 for (int i = beginKey; i <= endKey; i += 2) {
1262                     Long key = makeKey(i);
1263                     Object val = makeVal(i);
1264                     assertNull(imap.get(key));
1265                     assertTrue(!imap.values().contains(val));
1266                     assertTrue(imap.duplicates(key).add(val));
1267                     assertEquals(val, imap.get(key));
1268                     assertTrue(imap.values().contains(val));
1269                     assertTrue(imap.duplicates(key).contains(val));
1270                     checkDupsSize(1, imap.duplicates(key));
1271                     assertTrue(!imap.duplicates(key).add(val));
1272                     if (isEntityBinding) {
1273                         assertTrue(!imap.values().add(val));
1274                     }
1275                 }
1276             }
1277         });
1278     }
1279 
addOddList()1280     void addOddList()
1281         throws Exception {
1282 
1283         writeRunner.run(new TransactionWorker() {
1284             public void doWork() {
1285                 for (int i = beginKey; i <= endKey; i += 2) {
1286                     int idx = i - beginKey;
1287                     Object val = makeVal(i);
1288                     assertTrue(!list.contains(val));
1289                     assertTrue(!val.equals(list.get(idx)));
1290                     list.add(idx, val);
1291                     assertTrue(list.contains(val));
1292                     assertEquals(val, list.get(idx));
1293                 }
1294             }
1295         });
1296     }
1297 
addAllList()1298     void addAllList()
1299         throws Exception {
1300 
1301         writeRunner.run(new TransactionWorker() {
1302             public void doWork() {
1303                 for (int i = beginKey; i <= endKey; i += 1) {
1304                     int idx = i - beginKey;
1305                     Object val = makeVal(i);
1306                     assertTrue(!list.contains(val));
1307                     assertTrue(list.add(val));
1308                     assertTrue(list.contains(val));
1309                     assertEquals(val, list.get(idx));
1310                 }
1311             }
1312         });
1313     }
1314 
removeAllList()1315     void removeAllList()
1316         throws Exception {
1317 
1318         writeRunner.run(new TransactionWorker() {
1319             public void doWork() {
1320                 assertTrue(!list.isEmpty());
1321                 list.clear();
1322                 assertTrue(list.isEmpty());
1323                 for (int i = beginKey; i <= endKey; i += 1) {
1324                     int idx = i - beginKey;
1325                     assertNull(list.get(idx));
1326                 }
1327             }
1328         });
1329     }
1330 
1331     /**
1332      * Tests ConcurentMap methods implemented by StordMap.  Starts with an
1333      * empty DB and ends with an empty DB.  [#16218]
1334      */
testConcurrentMap()1335     void testConcurrentMap()
1336         throws Exception {
1337 
1338         writeRunner.run(new TransactionWorker() {
1339             public void doWork() {
1340                 for (int i = beginKey; i <= endKey; i += 1) {
1341                     Long key = makeKey(i);
1342                     Object val = makeVal(i);
1343                     Object valPlusOne = makeVal(i, i + 1);
1344                     assertFalse(imap.containsKey(key));
1345 
1346                     assertNull(imap.putIfAbsent(key, val));
1347                     assertEquals(val, imap.get(key));
1348 
1349                     assertEquals(val, imap.putIfAbsent(key, val));
1350                     assertEquals(val, imap.get(key));
1351 
1352                     if (!imap.areDuplicatesAllowed()) {
1353                         assertEquals(val, imap.replace(key, valPlusOne));
1354                         assertEquals(valPlusOne, imap.get(key));
1355 
1356                         assertEquals(valPlusOne, imap.replace(key, val));
1357                         assertEquals(val, imap.get(key));
1358 
1359                         assertFalse(imap.replace(key, valPlusOne, val));
1360                         assertEquals(val, imap.get(key));
1361 
1362                         assertTrue(imap.replace(key, val, valPlusOne));
1363                         assertEquals(valPlusOne, imap.get(key));
1364 
1365                         assertTrue(imap.replace(key, valPlusOne, val));
1366                         assertEquals(val, imap.get(key));
1367                     }
1368 
1369                     assertFalse(imap.remove(key, valPlusOne));
1370                     assertTrue(imap.containsKey(key));
1371 
1372                     assertTrue(imap.remove(key, val));
1373                     assertFalse(imap.containsKey(key));
1374 
1375                     assertNull(imap.replace(key, val));
1376                     assertFalse(imap.containsKey(key));
1377                 }
1378             }
1379         });
1380     }
1381 
testIterAddList()1382     void testIterAddList()
1383         throws Exception {
1384 
1385         writeIterRunner.run(new TransactionWorker() {
1386             public void doWork() {
1387                 ListIterator i = (ListIterator) iterator(list);
1388                 try {
1389                     assertTrue(!i.hasNext());
1390                     i.add(makeVal(3));
1391                     assertTrue(!i.hasNext());
1392                     assertTrue(i.hasPrevious());
1393                     assertEquals(3, intVal(i.previous()));
1394 
1395                     i.add(makeVal(1));
1396                     assertTrue(i.hasPrevious());
1397                     assertTrue(i.hasNext());
1398                     assertEquals(1, intVal(i.previous()));
1399                     assertTrue(i.hasNext());
1400                     assertEquals(1, intVal(i.next()));
1401                     assertTrue(i.hasNext());
1402                     assertEquals(3, intVal(i.next()));
1403                     assertEquals(3, intVal(i.previous()));
1404 
1405                     assertTrue(i.hasNext());
1406                     i.add(makeVal(2));
1407                     assertTrue(i.hasNext());
1408                     assertTrue(i.hasPrevious());
1409                     assertEquals(2, intVal(i.previous()));
1410                     assertTrue(i.hasNext());
1411                     assertEquals(2, intVal(i.next()));
1412                     assertTrue(i.hasNext());
1413                     assertEquals(3, intVal(i.next()));
1414 
1415                     assertTrue(!i.hasNext());
1416                     i.add(makeVal(4));
1417                     i.add(makeVal(5));
1418                     assertTrue(!i.hasNext());
1419                     assertEquals(5, intVal(i.previous()));
1420                     assertEquals(4, intVal(i.previous()));
1421                     assertEquals(3, intVal(i.previous()));
1422                     assertEquals(2, intVal(i.previous()));
1423                     assertEquals(1, intVal(i.previous()));
1424                     assertTrue(!i.hasPrevious());
1425                 } finally {
1426                     StoredIterator.close(i);
1427                 }
1428             }
1429         });
1430     }
1431 
testIterAddDuplicates()1432     void testIterAddDuplicates()
1433         throws Exception {
1434 
1435         writeIterRunner.run(new TransactionWorker() {
1436             public void doWork() {
1437                 assertNull(imap.put(makeKey(1), makeVal(1)));
1438                 ListIterator i =
1439                     (ListIterator) iterator(imap.duplicates(makeKey(1)));
1440                 try {
1441                     if (imap.areDuplicatesOrdered()) {
1442                         i.add(makeVal(1, 4));
1443                         i.add(makeVal(1, 2));
1444                         i.add(makeVal(1, 3));
1445                         while (i.hasPrevious()) i.previous();
1446                         assertEquals(1, intVal(i.next()));
1447                         assertEquals(2, intVal(i.next()));
1448                         assertEquals(3, intVal(i.next()));
1449                         assertEquals(4, intVal(i.next()));
1450                         assertTrue(!i.hasNext());
1451                     } else {
1452                         assertEquals(1, intVal(i.next()));
1453                         i.add(makeVal(1, 2));
1454                         i.add(makeVal(1, 3));
1455                         assertTrue(!i.hasNext());
1456                         assertTrue(i.hasPrevious());
1457                         assertEquals(3, intVal(i.previous()));
1458                         assertEquals(2, intVal(i.previous()));
1459                         assertEquals(1, intVal(i.previous()));
1460                         assertTrue(!i.hasPrevious());
1461                         i.add(makeVal(1, 4));
1462                         i.add(makeVal(1, 5));
1463                         assertTrue(i.hasNext());
1464                         assertEquals(5, intVal(i.previous()));
1465                         assertEquals(4, intVal(i.previous()));
1466                         assertTrue(!i.hasPrevious());
1467                         assertEquals(4, intVal(i.next()));
1468                         assertEquals(5, intVal(i.next()));
1469                         assertEquals(1, intVal(i.next()));
1470                         assertEquals(2, intVal(i.next()));
1471                         assertEquals(3, intVal(i.next()));
1472                         assertTrue(!i.hasNext());
1473                     }
1474                 } finally {
1475                     StoredIterator.close(i);
1476                 }
1477             }
1478         });
1479     }
1480 
readAll()1481     void readAll()
1482         throws Exception {
1483 
1484         readRunner.run(new TransactionWorker() {
1485             public void doWork() {
1486                 // map
1487 
1488                 assertNotNull(map.toString());
1489                 for (int i = beginKey; i <= endKey; i += 1) {
1490                     Long key = makeKey(i);
1491                     Object val = map.get(key);
1492                     assertEquals(makeVal(i), val);
1493                     assertTrue(map.containsKey(key));
1494                     assertTrue(map.containsValue(val));
1495                     assertTrue(map.keySet().contains(key));
1496                     assertTrue(map.values().contains(val));
1497                     assertTrue(map.duplicates(key).contains(val));
1498                     checkDupsSize(1, map.duplicates(key));
1499                 }
1500                 assertNull(map.get(makeKey(-1)));
1501                 assertNull(map.get(makeKey(0)));
1502                 assertNull(map.get(makeKey(beginKey - 1)));
1503                 assertNull(map.get(makeKey(endKey + 1)));
1504                 checkDupsSize(0, map.duplicates(makeKey(-1)));
1505                 checkDupsSize(0, map.duplicates(makeKey(0)));
1506                 checkDupsSize(0, map.duplicates(makeKey(beginKey - 1)));
1507                 checkDupsSize(0, map.duplicates(makeKey(endKey + 1)));
1508 
1509                 // entrySet
1510 
1511                 Set set = map.entrySet();
1512                 assertNotNull(set.toString());
1513                 assertEquals(beginKey > endKey, set.isEmpty());
1514                 Iterator iter = iterator(set);
1515                 try {
1516                     for (int i = beginKey; i <= endKey; i += 1) {
1517                         assertTrue(iter.hasNext());
1518                         Map.Entry entry = (Map.Entry) iter.next();
1519                         Long key = (Long) entry.getKey();
1520                         Object val = entry.getValue();
1521                         if (map instanceof SortedMap) {
1522                             assertEquals(intKey(key), i);
1523                         }
1524                         assertEquals(intKey(key), intVal(val));
1525                         assertTrue(set.contains(entry));
1526                     }
1527                     assertTrue(!iter.hasNext());
1528                 } finally {
1529                     StoredIterator.close(iter);
1530                 }
1531                 Map.Entry[] entries =
1532                     (Map.Entry[]) set.toArray(new Map.Entry[0]);
1533                 assertNotNull(entries);
1534                 assertEquals(endKey - beginKey + 1, entries.length);
1535                 for (int i = beginKey; i <= endKey; i += 1) {
1536                     Map.Entry entry = entries[i - beginKey];
1537                     assertNotNull(entry);
1538                     if (map instanceof SortedMap) {
1539                         assertEquals(makeKey(i), entry.getKey());
1540                         assertEquals(makeVal(i), entry.getValue());
1541                     }
1542                 }
1543                 readIterator(set, iterator(set), beginKey, endKey);
1544                 if (smap != null) {
1545                     SortedSet sset = (SortedSet) set;
1546                     if (beginKey == 1 && endKey >= 1) {
1547                         readIterator(sset,
1548                                      iterator(sset.subSet(mapEntry(1),
1549                                                           mapEntry(2))),
1550                                      1, 1);
1551                     }
1552                     if (beginKey <= 2 && endKey >= 2) {
1553                         readIterator(sset,
1554                                      iterator(sset.subSet(mapEntry(2),
1555                                                           mapEntry(3))),
1556                                      2, 2);
1557                     }
1558                     if (beginKey <= endKey) {
1559                         readIterator(sset,
1560                                      iterator(sset.subSet
1561                                                 (mapEntry(endKey),
1562                                                  mapEntry(endKey + 1))),
1563                                      endKey, endKey);
1564                     }
1565                     if (isSubMap()) {
1566                         if (beginKey <= endKey) {
1567                             if (rangeType != TAIL) {
1568                                 try {
1569                                     sset.subSet(mapEntry(endKey + 1),
1570                                                 mapEntry(endKey + 2));
1571                                     fail();
1572                                 } catch (IllegalArgumentException e) {}
1573                             }
1574                             if (rangeType != HEAD) {
1575                                 try {
1576                                     sset.subSet(mapEntry(0),
1577                                                 mapEntry(1));
1578                                     fail();
1579                                 } catch (IllegalArgumentException e) {}
1580                             }
1581                         }
1582                     } else {
1583                         readIterator(sset,
1584                                      iterator(sset.subSet
1585                                                 (mapEntry(endKey + 1),
1586                                                  mapEntry(endKey + 2))),
1587                                      endKey, endKey - 1);
1588                         readIterator(sset,
1589                                      iterator(sset.subSet(mapEntry(0),
1590                                                           mapEntry(1))),
1591                                      0, -1);
1592                     }
1593                 }
1594 
1595                 // keySet
1596 
1597                 set = map.keySet();
1598                 assertNotNull(set.toString());
1599                 assertEquals(beginKey > endKey, set.isEmpty());
1600                 iter = iterator(set);
1601                 try {
1602                     for (int i = beginKey; i <= endKey; i += 1) {
1603                         assertTrue(iter.hasNext());
1604                         Long key = (Long) iter.next();
1605                         assertTrue(set.contains(key));
1606                         Object val = map.get(key);
1607                         if (map instanceof SortedMap) {
1608                             assertEquals(key, makeKey(i));
1609                         }
1610                         assertEquals(intKey(key), intVal(val));
1611                     }
1612                     assertTrue("" + beginKey + ' ' + endKey, !iter.hasNext());
1613                 } finally {
1614                     StoredIterator.close(iter);
1615                 }
1616                 Long[] keys = (Long[]) set.toArray(new Long[0]);
1617                 assertNotNull(keys);
1618                 assertEquals(endKey - beginKey + 1, keys.length);
1619                 for (int i = beginKey; i <= endKey; i += 1) {
1620                     Long key = keys[i - beginKey];
1621                     assertNotNull(key);
1622                     if (map instanceof SortedMap) {
1623                         assertEquals(makeKey(i), key);
1624                     }
1625                 }
1626                 readIterator(set, iterator(set), beginKey, endKey);
1627 
1628                 // values
1629 
1630                 Collection coll = map.values();
1631                 assertNotNull(coll.toString());
1632                 assertEquals(beginKey > endKey, coll.isEmpty());
1633                 iter = iterator(coll);
1634                 try {
1635                     for (int i = beginKey; i <= endKey; i += 1) {
1636                         assertTrue(iter.hasNext());
1637                         Object val = iter.next();
1638                         if (map instanceof SortedMap) {
1639                             assertEquals(makeVal(i), val);
1640                         }
1641                     }
1642                     assertTrue(!iter.hasNext());
1643                 } finally {
1644                     StoredIterator.close(iter);
1645                 }
1646                 Object[] values = coll.toArray();
1647                 assertNotNull(values);
1648                 assertEquals(endKey - beginKey + 1, values.length);
1649                 for (int i = beginKey; i <= endKey; i += 1) {
1650                     Object val = values[i - beginKey];
1651                     assertNotNull(val);
1652                     if (map instanceof SortedMap) {
1653                         assertEquals(makeVal(i), val);
1654                     }
1655                 }
1656                 readIterator(coll, iterator(coll), beginKey, endKey);
1657 
1658                 // list
1659 
1660                 if (list != null) {
1661                     assertNotNull(list.toString());
1662                     assertEquals(beginKey > endKey, list.isEmpty());
1663                     for (int i = beginKey; i <= endKey; i += 1) {
1664                         int idx = i - beginKey;
1665                         Object val = list.get(idx);
1666                         assertEquals(makeVal(i), val);
1667                         assertTrue(list.contains(val));
1668                         assertEquals(idx, list.indexOf(val));
1669                         assertEquals(idx, list.lastIndexOf(val));
1670                     }
1671                     ListIterator li = (ListIterator) iterator(list);
1672                     try {
1673                         for (int i = beginKey; i <= endKey; i += 1) {
1674                             int idx = i - beginKey;
1675                             assertTrue(li.hasNext());
1676                             assertEquals(idx, li.nextIndex());
1677                             Object val = li.next();
1678                             assertEquals(makeVal(i), val);
1679                             assertEquals(idx, li.previousIndex());
1680                         }
1681                         assertTrue(!li.hasNext());
1682                     } finally {
1683                         StoredIterator.close(li);
1684                     }
1685                     if (beginKey < endKey) {
1686                         li = list.listIterator(1);
1687                         try {
1688                             for (int i = beginKey + 1; i <= endKey; i += 1) {
1689                                 int idx = i - beginKey;
1690                                 assertTrue(li.hasNext());
1691                                 assertEquals(idx, li.nextIndex());
1692                                 Object val = li.next();
1693                                 assertEquals(makeVal(i), val);
1694                                 assertEquals(idx, li.previousIndex());
1695                             }
1696                             assertTrue(!li.hasNext());
1697                         } finally {
1698                             StoredIterator.close(li);
1699                         }
1700                     }
1701                     values = list.toArray();
1702                     assertNotNull(values);
1703                     assertEquals(endKey - beginKey + 1, values.length);
1704                     for (int i = beginKey; i <= endKey; i += 1) {
1705                         Object val = values[i - beginKey];
1706                         assertNotNull(val);
1707                         assertEquals(makeVal(i), val);
1708                     }
1709                     readIterator(list, iterator(list), beginKey, endKey);
1710                 }
1711 
1712                 // first/last
1713 
1714                 if (smap != null) {
1715                     if (beginKey <= endKey &&
1716                         beginKey >= 1 && beginKey <= maxKey) {
1717                         assertEquals(makeKey(beginKey),
1718                                      smap.firstKey());
1719                         assertEquals(makeKey(beginKey),
1720                                      ((SortedSet) smap.keySet()).first());
1721                         Object entry = ((SortedSet) smap.entrySet()).first();
1722                         assertEquals(makeKey(beginKey),
1723                                      ((Map.Entry) entry).getKey());
1724                         if (smap.values() instanceof SortedSet) {
1725                             assertEquals(makeVal(beginKey),
1726                                          ((SortedSet) smap.values()).first());
1727                         }
1728                     } else {
1729                         assertNull(smap.firstKey());
1730                         assertNull(((SortedSet) smap.keySet()).first());
1731                         assertNull(((SortedSet) smap.entrySet()).first());
1732                         if (smap.values() instanceof SortedSet) {
1733                             assertNull(((SortedSet) smap.values()).first());
1734                         }
1735                     }
1736                     if (beginKey <= endKey &&
1737                         endKey >= 1 && endKey <= maxKey) {
1738                         assertEquals(makeKey(endKey),
1739                                      smap.lastKey());
1740                         assertEquals(makeKey(endKey),
1741                                      ((SortedSet) smap.keySet()).last());
1742                         Object entry = ((SortedSet) smap.entrySet()).last();
1743                         assertEquals(makeKey(endKey),
1744                                      ((Map.Entry) entry).getKey());
1745                         if (smap.values() instanceof SortedSet) {
1746                             assertEquals(makeVal(endKey),
1747                                          ((SortedSet) smap.values()).last());
1748                         }
1749                     } else {
1750                         assertNull(smap.lastKey());
1751                         assertNull(((SortedSet) smap.keySet()).last());
1752                         assertNull(((SortedSet) smap.entrySet()).last());
1753                         if (smap.values() instanceof SortedSet) {
1754                             assertNull(((SortedSet) smap.values()).last());
1755                         }
1756                     }
1757                 }
1758             }
1759         });
1760     }
1761 
readEven()1762     void readEven()
1763         throws Exception {
1764 
1765         readRunner.run(new TransactionWorker() {
1766             public void doWork() {
1767                 int readBegin = ((beginKey & 1) != 0) ?
1768                                     (beginKey + 1) : beginKey;
1769                 int readEnd = ((endKey & 1) != 0) ?  (endKey - 1) : endKey;
1770                 int readIncr = 2;
1771 
1772                 // map
1773 
1774                 for (int i = beginKey; i <= endKey; i += 1) {
1775                     Long key = makeKey(i);
1776                     if ((i & 1) == 0) {
1777                         Object val = map.get(key);
1778                         assertEquals(makeVal(i), val);
1779                         assertTrue(map.containsKey(key));
1780                         assertTrue(map.containsValue(val));
1781                         assertTrue(map.keySet().contains(key));
1782                         assertTrue(map.values().contains(val));
1783                         assertTrue(map.duplicates(key).contains(val));
1784                         checkDupsSize(1, map.duplicates(key));
1785                     } else {
1786                         Object val = makeVal(i);
1787                         assertTrue(!map.containsKey(key));
1788                         assertTrue(!map.containsValue(val));
1789                         assertTrue(!map.keySet().contains(key));
1790                         assertTrue(!map.values().contains(val));
1791                         assertTrue(!map.duplicates(key).contains(val));
1792                         checkDupsSize(0, map.duplicates(key));
1793                     }
1794                 }
1795 
1796                 // entrySet
1797 
1798                 Set set = map.entrySet();
1799                 assertEquals(beginKey > endKey, set.isEmpty());
1800                 Iterator iter = iterator(set);
1801                 try {
1802                     for (int i = readBegin; i <= readEnd; i += readIncr) {
1803                         assertTrue(iter.hasNext());
1804                         Map.Entry entry = (Map.Entry) iter.next();
1805                         Long key = (Long) entry.getKey();
1806                         Object val = entry.getValue();
1807                         if (map instanceof SortedMap) {
1808                             assertEquals(intKey(key), i);
1809                         }
1810                         assertEquals(intKey(key), intVal(val));
1811                         assertTrue(set.contains(entry));
1812                     }
1813                     assertTrue(!iter.hasNext());
1814                 } finally {
1815                     StoredIterator.close(iter);
1816                 }
1817 
1818                 // keySet
1819 
1820                 set = map.keySet();
1821                 assertEquals(beginKey > endKey, set.isEmpty());
1822                 iter = iterator(set);
1823                 try {
1824                     for (int i = readBegin; i <= readEnd; i += readIncr) {
1825                         assertTrue(iter.hasNext());
1826                         Long key = (Long) iter.next();
1827                         assertTrue(set.contains(key));
1828                         Object val = map.get(key);
1829                         if (map instanceof SortedMap) {
1830                             assertEquals(key, makeKey(i));
1831                         }
1832                         assertEquals(intKey(key), intVal(val));
1833                     }
1834                     assertTrue(!iter.hasNext());
1835                 } finally {
1836                     StoredIterator.close(iter);
1837                 }
1838 
1839                 // values
1840 
1841                 Collection coll = map.values();
1842                 assertEquals(beginKey > endKey, coll.isEmpty());
1843                 iter = iterator(coll);
1844                 try {
1845                     for (int i = readBegin; i <= readEnd; i += readIncr) {
1846                         assertTrue(iter.hasNext());
1847                         Object val = iter.next();
1848                         if (map instanceof SortedMap) {
1849                             assertEquals(makeVal(i), val);
1850                         }
1851                     }
1852                     assertTrue(!iter.hasNext());
1853                 } finally {
1854                     StoredIterator.close(iter);
1855                 }
1856 
1857                 // list not used since keys may not be renumbered for this
1858                 // method to work in general
1859 
1860                 // first/last
1861 
1862                 if (smap != null) {
1863                     if (readBegin <= readEnd &&
1864                         readBegin >= 1 && readBegin <= maxKey) {
1865                         assertEquals(makeKey(readBegin),
1866                                      smap.firstKey());
1867                         assertEquals(makeKey(readBegin),
1868                                      ((SortedSet) smap.keySet()).first());
1869                         Object entry = ((SortedSet) smap.entrySet()).first();
1870                         assertEquals(makeKey(readBegin),
1871                                      ((Map.Entry) entry).getKey());
1872                         if (smap.values() instanceof SortedSet) {
1873                             assertEquals(makeVal(readBegin),
1874                                          ((SortedSet) smap.values()).first());
1875                         }
1876                     } else {
1877                         assertNull(smap.firstKey());
1878                         assertNull(((SortedSet) smap.keySet()).first());
1879                         assertNull(((SortedSet) smap.entrySet()).first());
1880                         if (smap.values() instanceof SortedSet) {
1881                             assertNull(((SortedSet) smap.values()).first());
1882                         }
1883                     }
1884                     if (readBegin <= readEnd &&
1885                         readEnd >= 1 && readEnd <= maxKey) {
1886                         assertEquals(makeKey(readEnd),
1887                                      smap.lastKey());
1888                         assertEquals(makeKey(readEnd),
1889                                      ((SortedSet) smap.keySet()).last());
1890                         Object entry = ((SortedSet) smap.entrySet()).last();
1891                         assertEquals(makeKey(readEnd),
1892                                      ((Map.Entry) entry).getKey());
1893                         if (smap.values() instanceof SortedSet) {
1894                             assertEquals(makeVal(readEnd),
1895                                          ((SortedSet) smap.values()).last());
1896                         }
1897                     } else {
1898                         assertNull(smap.lastKey());
1899                         assertNull(((SortedSet) smap.keySet()).last());
1900                         assertNull(((SortedSet) smap.entrySet()).last());
1901                         if (smap.values() instanceof SortedSet) {
1902                             assertNull(((SortedSet) smap.values()).last());
1903                         }
1904                     }
1905                 }
1906             }
1907         });
1908     }
1909 
readEvenList()1910     void readEvenList()
1911         throws Exception {
1912 
1913         readRunner.run(new TransactionWorker() {
1914             public void doWork() {
1915                 int readBegin = ((beginKey & 1) != 0) ?
1916                                     (beginKey + 1) : beginKey;
1917                 int readEnd = ((endKey & 1) != 0) ?  (endKey - 1) : endKey;
1918                 int readIncr = 2;
1919 
1920                 assertEquals(beginKey > endKey, list.isEmpty());
1921                 ListIterator iter = (ListIterator) iterator(list);
1922                 try {
1923                     int idx = 0;
1924                     for (int i = readBegin; i <= readEnd; i += readIncr) {
1925                         assertTrue(iter.hasNext());
1926                         assertEquals(idx, iter.nextIndex());
1927                         Object val = iter.next();
1928                         assertEquals(idx, iter.previousIndex());
1929                         if (isEntityBinding) {
1930                             assertEquals(i, intVal(val));
1931                         } else {
1932                             assertEquals(makeVal(i), val);
1933                         }
1934                         idx += 1;
1935                     }
1936                     assertTrue(!iter.hasNext());
1937                 } finally {
1938                     StoredIterator.close(iter);
1939                 }
1940             }
1941         });
1942     }
1943 
readIterator(Collection coll, Iterator iter, int beginValue, int endValue)1944     void readIterator(Collection coll, Iterator iter,
1945                       int beginValue, int endValue) {
1946 
1947         ListIterator li = (ListIterator) iter;
1948         boolean isList = (coll instanceof List);
1949         Iterator clone = null;
1950         try {
1951             // at beginning
1952             assertTrue(!li.hasPrevious());
1953             assertTrue(!li.hasPrevious());
1954             try { li.previous(); } catch (NoSuchElementException e) {}
1955             if (isList) {
1956                 assertEquals(-1, li.previousIndex());
1957             }
1958             if (endValue < beginValue) {
1959                 // is empty
1960                 assertTrue(!iter.hasNext());
1961                 try { iter.next(); } catch (NoSuchElementException e) {}
1962                 if (isList) {
1963                     assertEquals(Integer.MAX_VALUE, li.nextIndex());
1964                 }
1965             }
1966             // loop thru all and collect in array
1967             int[] values = new int[endValue - beginValue + 1];
1968             for (int i = beginValue; i <= endValue; i += 1) {
1969                 assertTrue(iter.hasNext());
1970                 int idx = i - beginKey;
1971                 if (isList) {
1972                     assertEquals(idx, li.nextIndex());
1973                 }
1974                 int value = intIter(coll, iter.next());
1975                 if (isList) {
1976                     assertEquals(idx, li.previousIndex());
1977                 }
1978                 values[i - beginValue] = value;
1979                 if (((StoredCollection) coll).isOrdered()) {
1980                     assertEquals(i, value);
1981                 } else {
1982                     assertTrue(value >= beginValue);
1983                     assertTrue(value <= endValue);
1984                 }
1985             }
1986             // at end
1987             assertTrue(!iter.hasNext());
1988             try { iter.next(); } catch (NoSuchElementException e) {}
1989             if (isList) {
1990                 assertEquals(Integer.MAX_VALUE, li.nextIndex());
1991             }
1992             // clone at same position
1993             clone = StoredCollections.iterator(iter);
1994             assertTrue(!clone.hasNext());
1995             // loop thru in reverse
1996             for (int i = endValue; i >= beginValue; i -= 1) {
1997                 assertTrue(li.hasPrevious());
1998                 int idx = i - beginKey;
1999                 if (isList) {
2000                     assertEquals(idx, li.previousIndex());
2001                 }
2002                 int value = intIter(coll, li.previous());
2003                 if (isList) {
2004                     assertEquals(idx, li.nextIndex());
2005                 }
2006                 assertEquals(values[i - beginValue], value);
2007             }
2008             // clone should not have changed
2009             assertTrue(!clone.hasNext());
2010             // at beginning
2011             assertTrue(!li.hasPrevious());
2012             try { li.previous(); } catch (NoSuchElementException e) {}
2013             if (isList) {
2014                 assertEquals(-1, li.previousIndex());
2015             }
2016             // loop thru with some back-and-forth
2017             for (int i = beginValue; i <= endValue; i += 1) {
2018                 assertTrue(iter.hasNext());
2019                 int idx = i - beginKey;
2020                 if (isList) {
2021                     assertEquals(idx, li.nextIndex());
2022                 }
2023                 Object obj = iter.next();
2024                 if (isList) {
2025                     assertEquals(idx, li.previousIndex());
2026                 }
2027                 assertEquals(obj, li.previous());
2028                 if (isList) {
2029                     assertEquals(idx, li.nextIndex());
2030                 }
2031                 assertEquals(obj, iter.next());
2032                 if (isList) {
2033                     assertEquals(idx, li.previousIndex());
2034                 }
2035                 int value = intIter(coll, obj);
2036                 assertEquals(values[i - beginValue], value);
2037             }
2038             // at end
2039             assertTrue(!iter.hasNext());
2040             try { iter.next(); } catch (NoSuchElementException e) {}
2041             if (isList) {
2042                 assertEquals(Integer.MAX_VALUE, li.nextIndex());
2043             }
2044         } finally {
2045             StoredIterator.close(iter);
2046             StoredIterator.close(clone);
2047         }
2048     }
2049 
bulkOperations()2050     void bulkOperations()
2051         throws Exception {
2052 
2053         writeRunner.run(new TransactionWorker() {
2054             public void doWork() {
2055                 HashMap hmap = new HashMap();
2056                 for (int i = Math.max(1, beginKey);
2057                          i <= Math.min(maxKey, endKey);
2058                          i += 1) {
2059                     hmap.put(makeKey(i), makeVal(i));
2060                 }
2061                 assertEquals(hmap, map);
2062                 assertEquals(hmap.entrySet(), map.entrySet());
2063                 assertEquals(hmap.keySet(), map.keySet());
2064                 assertEquals(map.values(), hmap.values());
2065 
2066                 assertTrue(map.entrySet().containsAll(hmap.entrySet()));
2067                 assertTrue(map.keySet().containsAll(hmap.keySet()));
2068                 assertTrue(map.values().containsAll(hmap.values()));
2069 
2070                 map.clear();
2071                 assertTrue(map.isEmpty());
2072                 imap.putAll(hmap);
2073                 assertEquals(hmap, map);
2074 
2075                 assertTrue(map.entrySet().removeAll(hmap.entrySet()));
2076                 assertTrue(map.entrySet().isEmpty());
2077                 assertTrue(!map.entrySet().removeAll(hmap.entrySet()));
2078                 assertTrue(imap.entrySet().addAll(hmap.entrySet()));
2079                 assertTrue(map.entrySet().containsAll(hmap.entrySet()));
2080                 assertTrue(!imap.entrySet().addAll(hmap.entrySet()));
2081                 assertEquals(hmap, map);
2082 
2083                 assertTrue(!map.entrySet().retainAll(hmap.entrySet()));
2084                 assertEquals(hmap, map);
2085                 assertTrue(map.entrySet().retainAll(Collections.EMPTY_SET));
2086                 assertTrue(map.isEmpty());
2087                 imap.putAll(hmap);
2088                 assertEquals(hmap, map);
2089 
2090                 assertTrue(map.values().removeAll(hmap.values()));
2091                 assertTrue(map.values().isEmpty());
2092                 assertTrue(!map.values().removeAll(hmap.values()));
2093                 if (isEntityBinding) {
2094                     assertTrue(imap.values().addAll(hmap.values()));
2095                     assertTrue(map.values().containsAll(hmap.values()));
2096                     assertTrue(!imap.values().addAll(hmap.values()));
2097                 } else {
2098                     imap.putAll(hmap);
2099                 }
2100                 assertEquals(hmap, map);
2101 
2102                 assertTrue(!map.values().retainAll(hmap.values()));
2103                 assertEquals(hmap, map);
2104                 assertTrue(map.values().retainAll(Collections.EMPTY_SET));
2105                 assertTrue(map.isEmpty());
2106                 imap.putAll(hmap);
2107                 assertEquals(hmap, map);
2108 
2109                 assertTrue(map.keySet().removeAll(hmap.keySet()));
2110                 assertTrue(map.keySet().isEmpty());
2111                 assertTrue(!map.keySet().removeAll(hmap.keySet()));
2112                 assertTrue(imap.keySet().addAll(hmap.keySet()));
2113                 assertTrue(imap.keySet().containsAll(hmap.keySet()));
2114                 if (index != null) {
2115                     assertTrue(map.keySet().isEmpty());
2116                 }
2117                 assertTrue(!imap.keySet().addAll(hmap.keySet()));
2118                 // restore values to non-null
2119                 imap.keySet().removeAll(hmap.keySet());
2120                 imap.putAll(hmap);
2121                 assertEquals(hmap, map);
2122 
2123                 assertTrue(!map.keySet().retainAll(hmap.keySet()));
2124                 assertEquals(hmap, map);
2125                 assertTrue(map.keySet().retainAll(Collections.EMPTY_SET));
2126                 assertTrue(map.isEmpty());
2127                 imap.putAll(hmap);
2128                 assertEquals(hmap, map);
2129             }
2130         });
2131     }
2132 
bulkListOperations()2133     void bulkListOperations()
2134         throws Exception {
2135 
2136         writeRunner.run(new TransactionWorker() {
2137             public void doWork() {
2138                 ArrayList alist = new ArrayList();
2139                 for (int i = beginKey; i <= endKey; i += 1) {
2140                     alist.add(makeVal(i));
2141                 }
2142 
2143                 assertEquals(alist, list);
2144                 assertTrue(list.containsAll(alist));
2145 
2146                 if (isListAddAllowed()) {
2147                     list.clear();
2148                     assertTrue(list.isEmpty());
2149                     assertTrue(ilist.addAll(alist));
2150                     assertEquals(alist, list);
2151                 }
2152 
2153                 assertTrue(!list.retainAll(alist));
2154                 assertEquals(alist, list);
2155 
2156                 if (isListAddAllowed()) {
2157                     assertTrue(list.retainAll(Collections.EMPTY_SET));
2158                     assertTrue(list.isEmpty());
2159                     assertTrue(ilist.addAll(alist));
2160                     assertEquals(alist, list);
2161                 }
2162 
2163                 if (isListAddAllowed() && !isEntityBinding) {
2164                     // deleting in a renumbered list with entity binding will
2165                     // change the values dynamically, making it very difficult
2166                     // to test
2167                     assertTrue(list.removeAll(alist));
2168                     assertTrue(list.isEmpty());
2169                     assertTrue(!list.removeAll(alist));
2170                     assertTrue(ilist.addAll(alist));
2171                     assertTrue(list.containsAll(alist));
2172                     assertEquals(alist, list);
2173                 }
2174 
2175                 if (isListAddAllowed() && !isEntityBinding) {
2176                     // addAll at an index is also very difficult to test with
2177                     // an entity binding
2178 
2179                     // addAll at first index
2180                     ilist.addAll(beginKey, alist);
2181                     assertTrue(list.containsAll(alist));
2182                     assertEquals(2 * alist.size(), countElements(list));
2183                     for (int i = beginKey; i <= endKey; i += 1)
2184                         ilist.remove(beginKey);
2185                     assertEquals(alist, list);
2186 
2187                     // addAll at last index
2188                     ilist.addAll(endKey, alist);
2189                     assertTrue(list.containsAll(alist));
2190                     assertEquals(2 * alist.size(), countElements(list));
2191                     for (int i = beginKey; i <= endKey; i += 1)
2192                         ilist.remove(endKey);
2193                     assertEquals(alist, list);
2194 
2195                     // addAll in the middle
2196                     ilist.addAll(endKey - 1, alist);
2197                     assertTrue(list.containsAll(alist));
2198                     assertEquals(2 * alist.size(), countElements(list));
2199                     for (int i = beginKey; i <= endKey; i += 1)
2200                         ilist.remove(endKey - 1);
2201                     assertEquals(alist, list);
2202                 }
2203             }
2204         });
2205     }
2206 
readWriteRange(final int type, final int rangeBegin, final int rangeEnd)2207     void readWriteRange(final int type, final int rangeBegin,
2208                         final int rangeEnd)
2209         throws Exception {
2210 
2211         writeRunner.run(new TransactionWorker() {
2212             public void doWork() throws Exception {
2213                 setRange(type, rangeBegin, rangeEnd);
2214                 createOutOfRange(rangeBegin, rangeEnd);
2215                 if (rangeType != TAIL) {
2216                     writeOutOfRange(new Long(rangeEnd + 1));
2217                 }
2218                 if (rangeType != HEAD) {
2219                     writeOutOfRange(new Long(rangeBegin - 1));
2220                 }
2221                 if (rangeBegin <= rangeEnd) {
2222                     updateAll();
2223                 }
2224                 if (rangeBegin < rangeEnd && !map.areKeysRenumbered()) {
2225                     bulkOperations();
2226                     removeIter();
2227                 }
2228                 readAll();
2229                 clearRange();
2230             }
2231         });
2232     }
2233 
setRange(int type, int rangeBegin, int rangeEnd)2234     void setRange(int type, int rangeBegin, int rangeEnd) {
2235 
2236         rangeType = type;
2237         saveMap = map;
2238         saveSMap = smap;
2239         saveList = list;
2240         int listBegin = rangeBegin - beginKey;
2241         boolean canMakeSubList = (list != null && listBegin>= 0);
2242         if (!canMakeSubList) {
2243             list = null;
2244         }
2245         if (list != null) {
2246             try {
2247                 list.subList(-1, 0);
2248                 fail();
2249             } catch (IndexOutOfBoundsException e) { }
2250         }
2251         switch (type) {
2252 
2253         case SUB:
2254             smap = (StoredSortedMap) smap.subMap(makeKey(rangeBegin),
2255                                                  makeKey(rangeEnd + 1));
2256             if (canMakeSubList) {
2257                 list = (StoredList) list.subList(listBegin,
2258                                                  rangeEnd + 1 - beginKey);
2259             }
2260             // check for equivalent ranges
2261             assertEquals(smap,
2262                         (saveSMap).subMap(
2263                             makeKey(rangeBegin), true,
2264                             makeKey(rangeEnd + 1), false));
2265             assertEquals(smap.entrySet(),
2266                         ((StoredSortedEntrySet) saveSMap.entrySet()).subSet(
2267                             mapEntry(rangeBegin), true,
2268                             mapEntry(rangeEnd + 1), false));
2269             assertEquals(smap.keySet(),
2270                         ((StoredSortedKeySet) saveSMap.keySet()).subSet(
2271                             makeKey(rangeBegin), true,
2272                             makeKey(rangeEnd + 1), false));
2273             if (smap.values() instanceof SortedSet) {
2274                 assertEquals(smap.values(),
2275                             ((StoredSortedValueSet) saveSMap.values()).subSet(
2276                                 makeVal(rangeBegin), true,
2277                                 makeVal(rangeEnd + 1), false));
2278             }
2279             break;
2280         case HEAD:
2281             smap = (StoredSortedMap) smap.headMap(makeKey(rangeEnd + 1));
2282             if (canMakeSubList) {
2283                 list = (StoredList) list.subList(0,
2284                                                  rangeEnd + 1 - beginKey);
2285             }
2286             // check for equivalent ranges
2287             assertEquals(smap,
2288                         (saveSMap).headMap(
2289                             makeKey(rangeEnd + 1), false));
2290             assertEquals(smap.entrySet(),
2291                         ((StoredSortedEntrySet) saveSMap.entrySet()).headSet(
2292                             mapEntry(rangeEnd + 1), false));
2293             assertEquals(smap.keySet(),
2294                         ((StoredSortedKeySet) saveSMap.keySet()).headSet(
2295                             makeKey(rangeEnd + 1), false));
2296             if (smap.values() instanceof SortedSet) {
2297                 assertEquals(smap.values(),
2298                             ((StoredSortedValueSet) saveSMap.values()).headSet(
2299                                 makeVal(rangeEnd + 1), false));
2300             }
2301             break;
2302         case TAIL:
2303             smap = (StoredSortedMap) smap.tailMap(makeKey(rangeBegin));
2304             if (canMakeSubList) {
2305                 list = (StoredList) list.subList(listBegin,
2306                                                  maxKey + 1 - beginKey);
2307             }
2308             // check for equivalent ranges
2309             assertEquals(smap,
2310                         (saveSMap).tailMap(
2311                             makeKey(rangeBegin), true));
2312             assertEquals(smap.entrySet(),
2313                         ((StoredSortedEntrySet) saveSMap.entrySet()).tailSet(
2314                             mapEntry(rangeBegin), true));
2315             assertEquals(smap.keySet(),
2316                         ((StoredSortedKeySet) saveSMap.keySet()).tailSet(
2317                             makeKey(rangeBegin), true));
2318             if (smap.values() instanceof SortedSet) {
2319                 assertEquals(smap.values(),
2320                             ((StoredSortedValueSet) saveSMap.values()).tailSet(
2321                                 makeVal(rangeBegin), true));
2322             }
2323             break;
2324         default: throw new RuntimeException();
2325         }
2326         map = smap;
2327         beginKey = rangeBegin;
2328         if (rangeBegin < 1 || rangeEnd > maxKey) {
2329             endKey = rangeBegin - 1; // force empty range for readAll()
2330         } else {
2331             endKey = rangeEnd;
2332         }
2333     }
2334 
clearRange()2335     void clearRange() {
2336 
2337         rangeType = NONE;
2338         beginKey = 1;
2339         endKey = maxKey;
2340         map = saveMap;
2341         smap = saveSMap;
2342         list = saveList;
2343     }
2344 
createOutOfRange(int rangeBegin, int rangeEnd)2345     void createOutOfRange(int rangeBegin, int rangeEnd) {
2346         // map
2347 
2348         if (rangeType != TAIL) {
2349             try {
2350                 smap.subMap(makeKey(rangeBegin), makeKey(rangeEnd + 2));
2351                 fail();
2352             } catch (IllegalArgumentException e) { }
2353             try {
2354                 smap.headMap(makeKey(rangeEnd + 2));
2355                 fail();
2356             } catch (IllegalArgumentException e) { }
2357             checkDupsSize(0, smap.duplicates(makeKey(rangeEnd + 2)));
2358         }
2359         if (rangeType != HEAD) {
2360             try {
2361                 smap.subMap(makeKey(rangeBegin - 1), makeKey(rangeEnd + 1));
2362                 fail();
2363             } catch (IllegalArgumentException e) { }
2364             try {
2365                 smap.tailMap(makeKey(rangeBegin - 1));
2366                 fail();
2367             } catch (IllegalArgumentException e) { }
2368             checkDupsSize(0, smap.duplicates(makeKey(rangeBegin - 1)));
2369         }
2370 
2371         // keySet
2372 
2373         if (rangeType != TAIL) {
2374             SortedSet sset = (SortedSet) map.keySet();
2375             try {
2376                 sset.subSet(makeKey(rangeBegin), makeKey(rangeEnd + 2));
2377                 fail();
2378             } catch (IllegalArgumentException e) { }
2379             try {
2380                 sset.headSet(makeKey(rangeEnd + 2));
2381                 fail();
2382             } catch (IllegalArgumentException e) { }
2383             try {
2384                 iterator(sset.subSet(makeKey(rangeEnd + 1),
2385                                      makeKey(rangeEnd + 2)));
2386                 fail();
2387             } catch (IllegalArgumentException e) { }
2388         }
2389         if (rangeType != HEAD) {
2390             SortedSet sset = (SortedSet) map.keySet();
2391             try {
2392                 sset.subSet(makeKey(rangeBegin - 1), makeKey(rangeEnd + 1));
2393                 fail();
2394             } catch (IllegalArgumentException e) { }
2395             try {
2396                 sset.tailSet(makeKey(rangeBegin - 1));
2397                 fail();
2398             } catch (IllegalArgumentException e) { }
2399             try {
2400                 iterator(sset.subSet(makeKey(rangeBegin - 1),
2401                                      makeKey(rangeBegin)));
2402                 fail();
2403             } catch (IllegalArgumentException e) { }
2404         }
2405 
2406         // entrySet
2407 
2408         if (rangeType != TAIL) {
2409             SortedSet sset = (SortedSet) map.entrySet();
2410             try {
2411                 sset.subSet(mapEntry(rangeBegin), mapEntry(rangeEnd + 2));
2412                 fail();
2413             } catch (IllegalArgumentException e) { }
2414             try {
2415                 sset.headSet(mapEntry(rangeEnd + 2));
2416                 fail();
2417             } catch (IllegalArgumentException e) { }
2418             try {
2419                 iterator(sset.subSet(mapEntry(rangeEnd + 1),
2420                                      mapEntry(rangeEnd + 2)));
2421                 fail();
2422             } catch (IllegalArgumentException e) { }
2423         }
2424         if (rangeType != HEAD) {
2425             SortedSet sset = (SortedSet) map.entrySet();
2426             try {
2427                 sset.subSet(mapEntry(rangeBegin - 1), mapEntry(rangeEnd + 1));
2428                 fail();
2429             } catch (IllegalArgumentException e) { }
2430             try {
2431                 sset.tailSet(mapEntry(rangeBegin - 1));
2432                 fail();
2433             } catch (IllegalArgumentException e) { }
2434             try {
2435                 iterator(sset.subSet(mapEntry(rangeBegin - 1),
2436                                      mapEntry(rangeBegin)));
2437                 fail();
2438             } catch (IllegalArgumentException e) { }
2439         }
2440 
2441         // values
2442 
2443         if (map.values() instanceof SortedSet) {
2444             SortedSet sset = (SortedSet) map.values();
2445             if (rangeType != TAIL) {
2446                 try {
2447                     sset.subSet(makeVal(rangeBegin),
2448                                 makeVal(rangeEnd + 2));
2449                     fail();
2450                 } catch (IllegalArgumentException e) { }
2451                 try {
2452                     sset.headSet(makeVal(rangeEnd + 2));
2453                     fail();
2454                 } catch (IllegalArgumentException e) { }
2455             }
2456             if (rangeType != HEAD) {
2457                 try {
2458                     sset.subSet(makeVal(rangeBegin - 1),
2459                                 makeVal(rangeEnd + 1));
2460                     fail();
2461                 } catch (IllegalArgumentException e) { }
2462                 try {
2463                     sset.tailSet(makeVal(rangeBegin - 1));
2464                     fail();
2465                 } catch (IllegalArgumentException e) { }
2466             }
2467         }
2468 
2469         // list
2470 
2471         if (list != null) {
2472             int size = rangeEnd - rangeBegin + 1;
2473             try {
2474                 list.subList(0, size + 1);
2475                 fail();
2476             } catch (IndexOutOfBoundsException e) { }
2477             try {
2478                 list.subList(-1, size);
2479                 fail();
2480             } catch (IndexOutOfBoundsException e) { }
2481             try {
2482                 list.subList(2, 1);
2483                 fail();
2484             } catch (IndexOutOfBoundsException e) { }
2485             try {
2486                 list.subList(size, size);
2487                 fail();
2488             } catch (IndexOutOfBoundsException e) { }
2489         }
2490     }
2491 
writeOutOfRange(Long badNewKey)2492     void writeOutOfRange(Long badNewKey) {
2493         try {
2494             map.put(badNewKey, makeVal(badNewKey));
2495             fail();
2496         } catch (IllegalArgumentException e) {
2497             assertTrue(e.toString(), index == null);
2498         } catch (UnsupportedOperationException e) {
2499             assertTrue(index != null);
2500         }
2501         try {
2502             map.keySet().add(badNewKey);
2503             fail();
2504         } catch (IllegalArgumentException e) {
2505             assertTrue(index == null);
2506         } catch (UnsupportedOperationException e) {
2507             assertTrue(index != null);
2508         }
2509         try {
2510             map.values().add(makeEntity(badNewKey));
2511             fail();
2512         } catch (IllegalArgumentException e) {
2513             assertTrue(isEntityBinding && index == null);
2514         } catch (UnsupportedOperationException e) {
2515             assertTrue(!(isEntityBinding && index == null));
2516         }
2517         if (list != null) {
2518             int i = badNewKey.intValue() - beginKey;
2519             try {
2520                 list.set(i, makeVal(i));
2521                 fail();
2522             } catch (IndexOutOfBoundsException e) {
2523                 assertTrue(index == null);
2524             } catch (UnsupportedOperationException e) {
2525                 assertTrue(index != null);
2526             }
2527             try {
2528                 list.add(i, makeVal(badNewKey));
2529                 fail();
2530             } catch (UnsupportedOperationException e) {
2531             }
2532         }
2533     }
2534 
readWriteDuplicates()2535     void readWriteDuplicates()
2536         throws Exception {
2537 
2538         writeRunner.run(new TransactionWorker() {
2539             public void doWork() throws Exception {
2540                 if (index == null) {
2541                     readWritePrimaryDuplicates(beginKey);
2542                     readWritePrimaryDuplicates(beginKey + 1);
2543                     readWritePrimaryDuplicates(endKey);
2544                     readWritePrimaryDuplicates(endKey - 1);
2545                 } else {
2546                     readWriteIndexedDuplicates(beginKey);
2547                     readWriteIndexedDuplicates(beginKey + 1);
2548                     readWriteIndexedDuplicates(endKey);
2549                     readWriteIndexedDuplicates(endKey - 1);
2550                 }
2551             }
2552         });
2553     }
2554 
readWritePrimaryDuplicates(int i)2555     void readWritePrimaryDuplicates(int i)
2556         throws Exception {
2557 
2558         Collection dups;
2559         // make duplicate values
2560         final Long key = makeKey(i);
2561         final Object[] values = new Object[5];
2562         for (int j = 0; j < values.length; j += 1) {
2563             values[j] = isEntityBinding
2564                         ? makeEntity(i, i + j)
2565                         : makeVal(i + j);
2566         }
2567         // add duplicates
2568         outerLoop: for (int writeMode = 0;; writeMode += 1) {
2569             //System.out.println("write mode " + writeMode);
2570             switch (writeMode) {
2571                 case 0:
2572                 case 1: {
2573                     // write with Map.put()
2574                     for (int j = 1; j < values.length; j += 1) {
2575                         map.put(key, values[j]);
2576                     }
2577                     break;
2578                 }
2579                 case 2: {
2580                     // write with Map.duplicates().add()
2581                     dups = map.duplicates(key);
2582                     for (int j = 1; j < values.length; j += 1) {
2583                         dups.add(values[j]);
2584                     }
2585                     break;
2586                 }
2587                 case 3: {
2588                     // write with Map.duplicates().iterator().add()
2589                     writeIterRunner.run(new TransactionWorker() {
2590                         public void doWork() {
2591                             Collection dups = map.duplicates(key);
2592                             Iterator iter = iterator(dups);
2593                             assertEquals(values[0], iter.next());
2594                             assertTrue(!iter.hasNext());
2595                             try {
2596                                 for (int j = 1; j < values.length; j += 1) {
2597                                     ((ListIterator) iter).add(values[j]);
2598                                 }
2599                             } finally {
2600                                 StoredIterator.close(iter);
2601                             }
2602                         }
2603                     });
2604                     break;
2605                 }
2606                 case 4: {
2607                     // write with Map.values().add()
2608                     if (!isEntityBinding) {
2609                         continue;
2610                     }
2611                     Collection set = map.values();
2612                     for (int j = 1; j < values.length; j += 1) {
2613                         set.add(values[j]);
2614                     }
2615                     break;
2616                 }
2617                 default: {
2618                     break outerLoop;
2619                 }
2620             }
2621             checkDupsSize(values.length, map.duplicates(key));
2622             // read duplicates
2623             readDuplicates(i, key, values);
2624             // remove duplicates
2625             switch (writeMode) {
2626                 case 0: {
2627                     // remove with Map.remove()
2628                     checkDupsSize(values.length, map.duplicates(key));
2629                     map.remove(key); // remove all values
2630                     checkDupsSize(0, map.duplicates(key));
2631                     map.put(key, values[0]); // put back original value
2632                     checkDupsSize(1, map.duplicates(key));
2633                     break;
2634                 }
2635                 case 1: {
2636                     // remove with Map.keySet().remove()
2637                     map.keySet().remove(key); // remove all values
2638                     map.put(key, values[0]); // put back original value
2639                     break;
2640                 }
2641                 case 2: {
2642                     // remove with Map.duplicates().clear()
2643                     dups = map.duplicates(key);
2644                     dups.clear(); // remove all values
2645                     dups.add(values[0]); // put back original value
2646                     break;
2647                 }
2648                 case 3: {
2649                     // remove with Map.duplicates().iterator().remove()
2650                     writeIterRunner.run(new TransactionWorker() {
2651                         public void doWork() {
2652                             Collection dups = map.duplicates(key);
2653                             Iterator iter = iterator(dups);
2654                             try {
2655                                 for (int j = 0; j < values.length; j += 1) {
2656                                     assertEquals(values[j], iter.next());
2657                                     if (j != 0) {
2658                                         iter.remove();
2659                                     }
2660                                 }
2661                             } finally {
2662                                 StoredIterator.close(iter);
2663                             }
2664                         }
2665                     });
2666                     break;
2667                 }
2668                 case 4: {
2669                     // remove with Map.values().remove()
2670                     if (!isEntityBinding) {
2671                         throw new IllegalStateException();
2672                     }
2673                     Collection set = map.values();
2674                     for (int j = 1; j < values.length; j += 1) {
2675                         set.remove(values[j]);
2676                     }
2677                     break;
2678                 }
2679                 default: throw new IllegalStateException();
2680             }
2681             // verify that only original value is present
2682             dups = map.duplicates(key);
2683             assertTrue(dups.contains(values[0]));
2684             for (int j = 1; j < values.length; j += 1) {
2685                 assertTrue(!dups.contains(values[j]));
2686             }
2687             checkDupsSize(1, dups);
2688         }
2689     }
2690 
readWriteIndexedDuplicates(int i)2691     void readWriteIndexedDuplicates(int i) {
2692         Object key = makeKey(i);
2693         Object[] values = new Object[3];
2694         values[0] = makeVal(i);
2695         for (int j = 1; j < values.length; j += 1) {
2696             values[j] = isEntityBinding
2697                         ? makeEntity(endKey + j, i)
2698                         : makeVal(i);
2699         }
2700         // add duplicates
2701         for (int j = 1; j < values.length; j += 1) {
2702             imap.put(makeKey(endKey + j), values[j]);
2703         }
2704         // read duplicates
2705         readDuplicates(i, key, values);
2706         // remove duplicates
2707         for (int j = 1; j < values.length; j += 1) {
2708             imap.remove(makeKey(endKey + j));
2709         }
2710         checkDupsSize(1, map.duplicates(key));
2711     }
2712 
readDuplicates(int i, Object key, Object[] values)2713     void readDuplicates(int i, Object key, Object[] values) {
2714 
2715         boolean isOrdered = map.isOrdered();
2716         Collection dups;
2717         Iterator iter;
2718         // read with Map.duplicates().iterator()
2719         dups = map.duplicates(key);
2720         checkDupsSize(values.length, dups);
2721         iter = iterator(dups);
2722         try {
2723             for (int j = 0; j < values.length; j += 1) {
2724                 assertTrue(iter.hasNext());
2725                 Object val = iter.next();
2726                 assertEquals(values[j], val);
2727             }
2728             assertTrue(!iter.hasNext());
2729         } finally {
2730             StoredIterator.close(iter);
2731         }
2732         // read with Map.values().iterator()
2733         Collection clone = ((StoredCollection) map.values()).toList();
2734         iter = iterator(map.values());
2735         try {
2736             for (int j = beginKey; j < i; j += 1) {
2737                 Object val = iter.next();
2738                 assertTrue(clone.remove(makeVal(j)));
2739                 if (isOrdered) {
2740                     assertEquals(makeVal(j), val);
2741                 }
2742             }
2743             for (int j = 0; j < values.length; j += 1) {
2744                 Object val = iter.next();
2745                 assertTrue(clone.remove(values[j]));
2746                 if (isOrdered) {
2747                     assertEquals(values[j], val);
2748                 }
2749             }
2750             for (int j = i + 1; j <= endKey; j += 1) {
2751                 Object val = iter.next();
2752                 assertTrue(clone.remove(makeVal(j)));
2753                 if (isOrdered) {
2754                     assertEquals(makeVal(j), val);
2755                 }
2756             }
2757             assertTrue(!iter.hasNext());
2758             assertTrue(clone.isEmpty());
2759         } finally {
2760             StoredIterator.close(iter);
2761         }
2762         // read with Map.entrySet().iterator()
2763         clone = ((StoredCollection) map.entrySet()).toList();
2764         iter = iterator(map.entrySet());
2765         try {
2766             for (int j = beginKey; j < i; j += 1) {
2767                 Map.Entry entry = (Map.Entry) iter.next();
2768                 assertTrue(clone.remove(mapEntry(j)));
2769                 if (isOrdered) {
2770                     assertEquals(makeVal(j), entry.getValue());
2771                     assertEquals(makeKey(j), entry.getKey());
2772                 }
2773             }
2774             for (int j = 0; j < values.length; j += 1) {
2775                 Map.Entry entry = (Map.Entry) iter.next();
2776                 assertTrue(clone.remove(mapEntry(makeKey(i), values[j])));
2777                 if (isOrdered) {
2778                     assertEquals(values[j], entry.getValue());
2779                     assertEquals(makeKey(i), entry.getKey());
2780                 }
2781             }
2782             for (int j = i + 1; j <= endKey; j += 1) {
2783                 Map.Entry entry = (Map.Entry) iter.next();
2784                 assertTrue(clone.remove(mapEntry(j)));
2785                 if (isOrdered) {
2786                     assertEquals(makeVal(j), entry.getValue());
2787                     assertEquals(makeKey(j), entry.getKey());
2788                 }
2789             }
2790             assertTrue(!iter.hasNext());
2791             assertTrue(clone.isEmpty());
2792         } finally {
2793             StoredIterator.close(iter);
2794         }
2795         // read with Map.keySet().iterator()
2796         clone = ((StoredCollection) map.keySet()).toList();
2797         iter = iterator(map.keySet());
2798         try {
2799             for (int j = beginKey; j < i; j += 1) {
2800                 Object val = iter.next();
2801                 assertTrue(clone.remove(makeKey(j)));
2802                 if (isOrdered) {
2803                     assertEquals(makeKey(j), val);
2804                 }
2805             }
2806             if (true) {
2807                 // only one key is iterated for all duplicates
2808                 Object val = iter.next();
2809                 assertTrue(clone.remove(makeKey(i)));
2810                 if (isOrdered) {
2811                     assertEquals(makeKey(i), val);
2812                 }
2813             }
2814             for (int j = i + 1; j <= endKey; j += 1) {
2815                 Object val = iter.next();
2816                 assertTrue(clone.remove(makeKey(j)));
2817                 if (isOrdered) {
2818                     assertEquals(makeKey(j), val);
2819                 }
2820             }
2821             assertTrue(!iter.hasNext());
2822             assertTrue(clone.isEmpty());
2823         } finally {
2824             StoredIterator.close(iter);
2825         }
2826     }
2827 
duplicatesNotAllowed()2828     void duplicatesNotAllowed() {
2829 
2830         Collection dups = map.duplicates(makeKey(beginKey));
2831         try {
2832             dups.add(makeVal(beginKey));
2833             fail();
2834         } catch (UnsupportedOperationException expected) { }
2835         ListIterator iter = (ListIterator) iterator(dups);
2836         try {
2837             iter.add(makeVal(beginKey));
2838             fail();
2839         } catch (UnsupportedOperationException expected) {
2840         } finally {
2841             StoredIterator.close(iter);
2842         }
2843     }
2844 
listOperationsNotAllowed()2845     void listOperationsNotAllowed() {
2846 
2847         ListIterator iter = (ListIterator) iterator(map.values());
2848         try {
2849             try {
2850                 iter.nextIndex();
2851                 fail();
2852             } catch (UnsupportedOperationException expected) { }
2853             try {
2854                 iter.previousIndex();
2855                 fail();
2856             } catch (UnsupportedOperationException expected) { }
2857         } finally {
2858             StoredIterator.close(iter);
2859         }
2860     }
2861 
testCdbLocking()2862     void testCdbLocking() {
2863 
2864         Iterator readIterator;
2865         Iterator writeIterator;
2866         StoredKeySet set = (StoredKeySet) map.keySet();
2867 
2868         // can open two CDB read cursors
2869         readIterator = set.storedIterator(false);
2870         try {
2871             Iterator readIterator2 = set.storedIterator(false);
2872             StoredIterator.close(readIterator2);
2873         } finally {
2874             StoredIterator.close(readIterator);
2875         }
2876 
2877         // can open two CDB write cursors
2878         writeIterator = set.storedIterator(true);
2879         try {
2880             Iterator writeIterator2 = set.storedIterator(true);
2881             StoredIterator.close(writeIterator2);
2882         } finally {
2883             StoredIterator.close(writeIterator);
2884         }
2885 
2886         // cannot open CDB write cursor when read cursor is open,
2887         readIterator = set.storedIterator(false);
2888         try {
2889             writeIterator = set.storedIterator(true);
2890             fail();
2891             StoredIterator.close(writeIterator);
2892         } catch (IllegalStateException e) {
2893         } finally {
2894             StoredIterator.close(readIterator);
2895         }
2896 
2897         if (index == null) {
2898             // cannot put() with read cursor open
2899             readIterator = set.storedIterator(false);
2900             try {
2901                 map.put(makeKey(1), makeVal(1));
2902                 fail();
2903             } catch (IllegalStateException e) {
2904             } finally {
2905                 StoredIterator.close(readIterator);
2906             }
2907 
2908             // cannot append() with write cursor open with RECNO/QUEUE only
2909             writeIterator = set.storedIterator(true);
2910             try {
2911                 if (testStore.isQueueOrRecno()) {
2912                     try {
2913                         map.append(makeVal(1));
2914                         fail();
2915                     } catch (IllegalStateException e) {}
2916                 } else {
2917                     map.append(makeVal(1));
2918                 }
2919             } finally {
2920                 StoredIterator.close(writeIterator);
2921             }
2922         }
2923     }
2924 
makeVal(int key)2925     Object makeVal(int key) {
2926 
2927         if (isEntityBinding) {
2928             return makeEntity(key);
2929         } else {
2930             return new Long(key + 100);
2931         }
2932     }
2933 
makeVal(int key, int val)2934     Object makeVal(int key, int val) {
2935 
2936         if (isEntityBinding) {
2937             return makeEntity(key, val);
2938         } else {
2939             return makeVal(val);
2940         }
2941     }
2942 
makeEntity(int key, int val)2943     Object makeEntity(int key, int val) {
2944 
2945         return new TestEntity(key, val + 100);
2946     }
2947 
intVal(Object val)2948     int intVal(Object val) {
2949 
2950         if (isEntityBinding) {
2951             return ((TestEntity) val).value - 100;
2952         } else {
2953             return ((Long) val).intValue() - 100;
2954         }
2955     }
2956 
intKey(Object key)2957     int intKey(Object key) {
2958 
2959         return ((Long) key).intValue();
2960     }
2961 
makeVal(Long key)2962     Object makeVal(Long key) {
2963 
2964         return makeVal(key.intValue());
2965     }
2966 
makeEntity(int key)2967     Object makeEntity(int key) {
2968 
2969         return makeEntity(key, key);
2970     }
2971 
makeEntity(Long key)2972     Object makeEntity(Long key) {
2973 
2974         return makeEntity(key.intValue());
2975     }
2976 
intIter(Collection coll, Object value)2977     int intIter(Collection coll, Object value) {
2978 
2979         if (coll instanceof StoredKeySet) {
2980             return intKey(value);
2981         } else {
2982             if (coll instanceof StoredEntrySet) {
2983                 value = ((Map.Entry) value).getValue();
2984             }
2985             return intVal(value);
2986         }
2987     }
2988 
mapEntry(Object key, Object val)2989     Map.Entry mapEntry(Object key, Object val) {
2990 
2991         return new MapEntryParameter(key, val);
2992     }
2993 
mapEntry(int key)2994     Map.Entry mapEntry(int key) {
2995 
2996         return new MapEntryParameter(makeKey(key), makeVal(key));
2997     }
2998 
makeKey(int key)2999     Long makeKey(int key) {
3000 
3001         return new Long(key);
3002     }
3003 
isSubMap()3004     boolean isSubMap() {
3005 
3006         return rangeType != NONE;
3007     }
3008 
checkDupsSize(int expected, Collection coll)3009     void checkDupsSize(int expected, Collection coll) {
3010 
3011         assertEquals(expected, coll.size());
3012         if (coll instanceof StoredCollection) {
3013             StoredIterator i = ((StoredCollection) coll).storedIterator(false);
3014             try {
3015                 int actual = 0;
3016                 if (i.hasNext()) {
3017                     i.next();
3018                     actual = i.count();
3019                 }
3020                 assertEquals(expected, actual);
3021             } finally {
3022                 StoredIterator.close(i);
3023             }
3024         }
3025     }
3026 
isListAddAllowed()3027     private boolean isListAddAllowed() {
3028 
3029         return list != null && testStore.isQueueOrRecno() &&
3030                list.areKeysRenumbered();
3031     }
3032 
countElements(Collection coll)3033     private int countElements(Collection coll) {
3034 
3035         int count = 0;
3036         Iterator iter = iterator(coll);
3037         try {
3038             while (iter.hasNext()) {
3039                 iter.next();
3040                 count += 1;
3041             }
3042         } finally {
3043             StoredIterator.close(iter);
3044         }
3045         return count;
3046     }
3047 }
3048