KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > test > ToManyTest


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: ToManyTest.java,v 1.4 2006/10/30 21:14:50 bostic Exp $
7  */

8
9 package com.sleepycat.je.test;
10
11 import java.util.HashMap JavaDoc;
12 import java.util.HashSet JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.Map JavaDoc;
15 import java.util.Set JavaDoc;
16
17 import junit.framework.Test;
18
19 import com.sleepycat.je.Cursor;
20 import com.sleepycat.je.Database;
21 import com.sleepycat.je.DatabaseConfig;
22 import com.sleepycat.je.DatabaseEntry;
23 import com.sleepycat.je.DatabaseException;
24 import com.sleepycat.je.OperationStatus;
25 import com.sleepycat.je.SecondaryConfig;
26 import com.sleepycat.je.SecondaryCursor;
27 import com.sleepycat.je.SecondaryDatabase;
28 import com.sleepycat.je.SecondaryMultiKeyCreator;
29 import com.sleepycat.je.Transaction;
30
31 /**
32  * Tests multi-key secondary operations. Exhaustive API testing of multi-key
33  * secondaries is part of SecondaryTest and ForeignKeyTest, which test the use
34  * of a single key with SecondaryMultiKeyCreator. This class adds tests for
35  * multiple keys per record.
36  */

37 public class ToManyTest extends TxnTestCase {
38
39     /*
40      * The primary database has a single byte key and byte[] array data. Each
41      * byte of the data array is a secondary key in the to-many index.
42      *
43      * The primary map mirrors the primary database and contains Byte keys and
44      * a set of Byte objects for each map entry value. The secondary map
45      * mirrors the secondary database, and for every secondary key (Byte)
46      * contains a set of primary keys (set of Byte).
47      */

48     private Map JavaDoc priMap0 = new HashMap JavaDoc();
49     private Map JavaDoc secMap0 = new HashMap JavaDoc();
50     private Database priDb;
51     private SecondaryDatabase secDb;
52
53     public static Test suite() {
54
55         /*
56          * This test does not work with TXN_NULL because with transactions we
57          * cannot abort the update in a one-to-many test when secondary key
58          * already exists in another primary record.
59          */

60         return txnTestSuite(ToManyTest.class, null,
61                             new String JavaDoc[] {TxnTestCase.TXN_USER,
62                                           TxnTestCase.TXN_AUTO});
63     }
64
65     public void tearDown()
66         throws Exception JavaDoc {
67
68         super.tearDown();
69         priMap0 = null;
70         secMap0 = null;
71         priDb = null;
72         secDb = null;
73     }
74
75     public void testManyToMany()
76         throws DatabaseException {
77
78         priDb = openPrimary("pri");
79         secDb = openSecondary(priDb, "sec", true /*dups*/);
80
81         writeAndVerify((byte) 0, new byte[] {});
82         writeAndVerify((byte) 0, null);
83         writeAndVerify((byte) 0, new byte[] {0, 1, 2});
84         writeAndVerify((byte) 0, null);
85         writeAndVerify((byte) 0, new byte[] {});
86         writeAndVerify((byte) 0, new byte[] {0});
87         writeAndVerify((byte) 0, new byte[] {0, 1});
88         writeAndVerify((byte) 0, new byte[] {0, 1, 2});
89         writeAndVerify((byte) 0, new byte[] {1, 2});
90         writeAndVerify((byte) 0, new byte[] {2});
91         writeAndVerify((byte) 0, new byte[] {});
92         writeAndVerify((byte) 0, null);
93
94         writeAndVerify((byte) 0, new byte[] {0, 1, 2});
95         writeAndVerify((byte) 1, new byte[] {1, 2, 3});
96         writeAndVerify((byte) 0, null);
97         writeAndVerify((byte) 1, null);
98         writeAndVerify((byte) 0, new byte[] {0, 1, 2});
99         writeAndVerify((byte) 1, new byte[] {1, 2, 3});
100         writeAndVerify((byte) 0, new byte[] {0});
101         writeAndVerify((byte) 1, new byte[] {3});
102         writeAndVerify((byte) 0, null);
103         writeAndVerify((byte) 1, null);
104
105         secDb.close();
106         priDb.close();
107     }
108
109     public void testOneToMany()
110         throws DatabaseException {
111
112         priDb = openPrimary("pri");
113         secDb = openSecondary(priDb, "sec", false /*dups*/);
114         
115         writeAndVerify((byte) 0, new byte[] {1, 5});
116         writeAndVerify((byte) 1, new byte[] {2, 4});
117         writeAndVerify((byte) 0, new byte[] {0, 1, 5, 6});
118         writeAndVerify((byte) 1, new byte[] {2, 3, 4});
119         write((byte) 0, new byte[] {3}, true /*expectException*/);
120         writeAndVerify((byte) 1, new byte[] {});
121         writeAndVerify((byte) 0, new byte[] {0, 1, 2, 3, 4, 5, 6});
122         writeAndVerify((byte) 0, null);
123         writeAndVerify((byte) 1, new byte[] {0, 1, 2, 3, 4, 5, 6});
124         writeAndVerify((byte) 1, null);
125
126         secDb.close();
127         priDb.close();
128     }
129
130     /**
131      * Puts or deletes a single primary record, updates the maps, and verifies
132      * that the maps match the databases.
133      */

134     private void writeAndVerify(byte priKey, byte[] priData)
135         throws DatabaseException {
136
137         write(priKey, priData, false /*expectException*/);
138         updateMaps(new Byte JavaDoc(priKey), bytesToSet(priData));
139         verify();
140     }
141
142     /**
143      * Puts or deletes a single primary record.
144      */

145     private void write(byte priKey, byte[] priData, boolean expectException)
146         throws DatabaseException {
147
148         DatabaseEntry keyEntry = new DatabaseEntry(new byte[] { priKey });
149         DatabaseEntry dataEntry = new DatabaseEntry(priData);
150
151         Transaction txn = txnBegin();
152         try {
153             OperationStatus status;
154             if (priData != null) {
155                 status = priDb.put(txn, keyEntry, dataEntry);
156             } else {
157                 status = priDb.delete(txn, keyEntry);
158             }
159             assertSame(OperationStatus.SUCCESS, status);
160             txnCommit(txn);
161             assertTrue(!expectException);
162         } catch (Exception JavaDoc e) {
163             txnAbort(txn);
164             assertTrue(e.toString(), expectException);
165         }
166     }
167
168     /**
169      * Updates map 0 to reflect a record added to the primary database.
170      */

171     private void updateMaps(Byte JavaDoc priKey, Set JavaDoc newPriData) {
172
173         /* Remove old secondary keys. */
174         Set JavaDoc oldPriData = (Set JavaDoc) priMap0.get(priKey);
175         if (oldPriData != null) {
176             for (Iterator JavaDoc i = oldPriData.iterator(); i.hasNext();) {
177                 Byte JavaDoc secKey = (Byte JavaDoc) i.next();
178                 Set JavaDoc priKeySet = (Set JavaDoc) secMap0.get(secKey);
179                 assertNotNull(priKeySet);
180                 assertTrue(priKeySet.remove(priKey));
181                 if (priKeySet.isEmpty()) {
182                     secMap0.remove(secKey);
183                 }
184             }
185         }
186
187         if (newPriData != null) {
188             /* Put primary entry. */
189             priMap0.put(priKey, newPriData);
190             /* Add new secondary keys. */
191             for (Iterator JavaDoc i = newPriData.iterator(); i.hasNext();) {
192                 Byte JavaDoc secKey = (Byte JavaDoc) i.next();
193                 Set JavaDoc priKeySet = (Set JavaDoc) secMap0.get(secKey);
194                 if (priKeySet == null) {
195                     priKeySet = new HashSet JavaDoc();
196                     secMap0.put(secKey, priKeySet);
197                 }
198                 assertTrue(priKeySet.add(priKey));
199             }
200         } else {
201             /* Remove primary entry. */
202             priMap0.remove(priKey);
203         }
204     }
205
206     /**
207      * Verifies that the maps match the databases.
208      */

209     private void verify()
210         throws DatabaseException {
211
212         Transaction txn = txnBeginCursor();
213         DatabaseEntry priKeyEntry = new DatabaseEntry();
214         DatabaseEntry secKeyEntry = new DatabaseEntry();
215         DatabaseEntry dataEntry = new DatabaseEntry();
216         Map JavaDoc priMap1 = new HashMap JavaDoc();
217         Map JavaDoc priMap2 = new HashMap JavaDoc();
218         Map JavaDoc secMap1 = new HashMap JavaDoc();
219         Map JavaDoc secMap2 = new HashMap JavaDoc();
220
221         /* Build map 1 from the primary database. */
222         priMap2 = new HashMap JavaDoc();
223         Cursor priCursor = priDb.openCursor(txn, null);
224         while (priCursor.getNext(priKeyEntry, dataEntry, null) ==
225                OperationStatus.SUCCESS) {
226             Byte JavaDoc priKey = new Byte JavaDoc(priKeyEntry.getData()[0]);
227             Set JavaDoc priData = bytesToSet(dataEntry.getData());
228
229             /* Update primary map. */
230             priMap1.put(priKey, priData);
231
232             /* Update secondary map. */
233             for (Iterator JavaDoc i = priData.iterator(); i.hasNext();) {
234                 Byte JavaDoc secKey = (Byte JavaDoc) i.next();
235                 Set JavaDoc priKeySet = (Set JavaDoc) secMap1.get(secKey);
236                 if (priKeySet == null) {
237                     priKeySet = new HashSet JavaDoc();
238                     secMap1.put(secKey, priKeySet);
239                 }
240                 assertTrue(priKeySet.add(priKey));
241             }
242
243             /*
244              * Add empty primary records to priMap2 while we're here, since
245              * they cannot be built from the secondary database.
246              */

247             if (priData.isEmpty()) {
248                 priMap2.put(priKey, priData);
249             }
250         }
251         priCursor.close();
252
253         /* Build map 2 from the secondary database. */
254         SecondaryCursor secCursor = secDb.openSecondaryCursor(txn, null);
255         while (secCursor.getNext(secKeyEntry, priKeyEntry, dataEntry, null) ==
256                OperationStatus.SUCCESS) {
257             Byte JavaDoc priKey = new Byte JavaDoc(priKeyEntry.getData()[0]);
258             Byte JavaDoc secKey = new Byte JavaDoc(secKeyEntry.getData()[0]);
259
260             /* Update primary map. */
261             Set JavaDoc priData = (Set JavaDoc) priMap2.get(priKey);
262             if (priData == null) {
263                 priData = new HashSet JavaDoc();
264                 priMap2.put(priKey, priData);
265             }
266             priData.add(secKey);
267
268             /* Update secondary map. */
269             Set JavaDoc secData = (Set JavaDoc) secMap2.get(secKey);
270             if (secData == null) {
271                 secData = new HashSet JavaDoc();
272                 secMap2.put(secKey, secData);
273             }
274             secData.add(priKey);
275         }
276         secCursor.close();
277
278         /* Compare. */
279         assertEquals(priMap0, priMap1);
280         assertEquals(priMap1, priMap2);
281         assertEquals(secMap0, secMap1);
282         assertEquals(secMap1, secMap2);
283
284         txnCommit(txn);
285     }
286
287     private Set JavaDoc bytesToSet(byte[] bytes) {
288         Set JavaDoc set = null;
289         if (bytes != null) {
290             set = new HashSet JavaDoc();
291             for (int i = 0; i < bytes.length; i += 1) {
292                 set.add(new Byte JavaDoc(bytes[i]));
293             }
294         }
295         return set;
296     }
297
298     private Database openPrimary(String JavaDoc name)
299         throws DatabaseException {
300
301         DatabaseConfig dbConfig = new DatabaseConfig();
302         dbConfig.setTransactional(isTransactional);
303         dbConfig.setAllowCreate(true);
304
305         Transaction txn = txnBegin();
306         try {
307             return env.openDatabase(txn, name, dbConfig);
308         } finally {
309             txnCommit(txn);
310         }
311     }
312
313     private SecondaryDatabase openSecondary(Database priDb,
314                                             String JavaDoc dbName,
315                                             boolean dups)
316         throws DatabaseException {
317
318         SecondaryConfig dbConfig = new SecondaryConfig();
319         dbConfig.setTransactional(isTransactional);
320         dbConfig.setAllowCreate(true);
321         dbConfig.setSortedDuplicates(dups);
322         dbConfig.setMultiKeyCreator(new MyKeyCreator());
323
324         Transaction txn = txnBegin();
325         try {
326             return env.openSecondaryDatabase(txn, dbName, priDb, dbConfig);
327         } finally {
328             txnCommit(txn);
329         }
330     }
331
332     private static class MyKeyCreator implements SecondaryMultiKeyCreator {
333
334         public void createSecondaryKeys(SecondaryDatabase secondary,
335                                         DatabaseEntry key,
336                                         DatabaseEntry data,
337                                         Set JavaDoc results)
338             throws DatabaseException {
339
340             for (int i = 0; i < data.getSize(); i+= 1) {
341                 results.add(new DatabaseEntry(data.getData(), i, 1));
342             }
343         }
344     }
345 }
346
Popular Tags