1 8 9 package com.sleepycat.je.test; 10 11 import junit.framework.Test; 12 13 import com.sleepycat.je.Cursor; 14 import com.sleepycat.je.Database; 15 import com.sleepycat.je.DatabaseConfig; 16 import com.sleepycat.je.DatabaseEntry; 17 import com.sleepycat.je.DatabaseException; 18 import com.sleepycat.je.DbInternal; 19 import com.sleepycat.je.EnvironmentConfig; 20 import com.sleepycat.je.JoinConfig; 21 import com.sleepycat.je.JoinCursor; 22 import com.sleepycat.je.LockMode; 23 import com.sleepycat.je.OperationStatus; 24 import com.sleepycat.je.SecondaryConfig; 25 import com.sleepycat.je.SecondaryCursor; 26 import com.sleepycat.je.SecondaryDatabase; 27 import com.sleepycat.je.SecondaryKeyCreator; 28 import com.sleepycat.je.Transaction; 29 import com.sleepycat.je.util.TestUtils; 30 31 public class JoinTest extends MultiKeyTxnTestCase { 32 33 51 private static final int[][][] ALL = { 52 53 { 54 {1, 1, 1}, {11}, 55 {2, 2, 2}, {12}, 56 {3, 3, 3}, {13}, 57 }, { 58 {1, 1, 1}, {11}, 59 {2, 2, 2}, {12}, 60 {3, 3, 3}, {13}, 61 {1, 2, 3}, {}, 62 {1, 1, 2}, {}, 63 {3, 2, 2}, {}, 64 }, 65 67 { 68 {1, 1, 0}, {11}, 69 {2, 0, 2}, {12}, 70 {0, 3, 3}, {13}, 71 {3, 2, 1}, {14}, 72 }, { 73 {1, 1, 1}, {}, 74 {2, 2, 2}, {}, 75 {3, 3, 3}, {}, 76 }, 77 79 { 80 {1, 0, 0}, {11}, 81 {1, 1, 0}, {12}, 82 {1, 1, 1}, {13}, 83 {0, 0, 0}, {14}, 84 }, { 85 {1, 1, 1}, {13}, 86 }, 87 89 { 90 {1, 2, 3}, {11}, 91 {1, 1, 3}, {12}, 92 {1, 1, 1}, {13}, 93 {3, 2, 1}, {14}, 94 }, { 95 {1, 1, 1}, {13}, 96 }, 97 99 { 100 {1, 2, 3}, {11}, 101 {1, 1, 3}, {12}, 102 {1, 1, 1}, {13}, 103 {1, 2, 3}, {14}, 104 }, { 105 {1, 2, 3}, {11, 14}, 106 }, 107 109 { 110 {1, 2, 3}, {11}, 111 {1, 1, 3}, {12}, 112 {1, 1, 1}, {13}, 113 {1, 2, 3}, {14}, 114 {1, 1, 1}, {15}, 115 {1, 0, 0}, {16}, 116 {1, 1, 0}, {17}, 117 {1, 1, 1}, {18}, 118 {0, 0, 0}, {19}, 119 {3, 2, 1}, {20}, 120 }, { 121 {1, 1, 1}, {13, 15, 18}, 122 }, 123 124 { 125 {1, 2, 3}, {11}, 126 {1, 2, 3}, {12}, 127 {1, 2, 3}, {13}, 128 }, { 129 {1, 2, 3}, {11, 12, 13}, 130 }, 131 }; 132 133 134 private static final int CURSOR_ORDER_SET = 6; 135 private static final int[] CURSOR_ORDER = {2, 1, 0}; 136 137 private static EnvironmentConfig envConfig = TestUtils.initEnvConfig(); 138 static { 139 envConfig.setAllowCreate(true); 140 } 141 142 private static JoinConfig joinConfigNoSort = new JoinConfig(); 143 static { 144 joinConfigNoSort.setNoSort(true); 145 } 146 147 public static Test suite() { 148 return multiKeyTxnTestSuite(JoinTest.class, envConfig, null); 149 } 150 151 public void testJoin() 152 throws DatabaseException { 153 154 for (int i = 0; i < ALL.length; i += 2) { 155 doJoin(ALL[i], ALL[i + 1], (i / 2) + 1); 156 } 157 } 158 159 private void doJoin(int[][] dataSet, int[][] joinSet, int setNum) 160 throws DatabaseException { 161 162 String name = "Set#" + setNum; 163 Database priDb = openPrimary("pri"); 164 SecondaryDatabase secDb0 = openSecondary(priDb, "sec0", true, 0); 165 SecondaryDatabase secDb1 = openSecondary(priDb, "sec1", true, 1); 166 SecondaryDatabase secDb2 = openSecondary(priDb, "sec2", true, 2); 167 168 OperationStatus status; 169 DatabaseEntry key = new DatabaseEntry(); 170 DatabaseEntry data = new DatabaseEntry(); 171 Transaction txn; 172 txn = txnBegin(); 173 174 for (int i = 0; i < dataSet.length; i += 2) { 175 int[] vals = dataSet[i]; 176 setData(data, vals[0], vals[1], vals[2]); 177 setKey(key, dataSet[i + 1][0]); 178 status = priDb.put(txn, key, data); 179 assertEquals(name, OperationStatus.SUCCESS, status); 180 } 181 182 txnCommit(txn); 183 txn = txnBeginCursor(); 184 185 SecondaryCursor c0 = secDb0.openSecondaryCursor(txn, null); 186 SecondaryCursor c1 = secDb1.openSecondaryCursor(txn, null); 187 SecondaryCursor c2 = secDb2.openSecondaryCursor(txn, null); 188 SecondaryCursor[] cursors = {c0, c1, c2}; 189 190 for (int i = 0; i < joinSet.length; i += 2) { 191 int[] indexKeys = joinSet[i]; 192 int[] priKeys = joinSet[i + 1]; 193 String prefix = name + " row=" + i; 194 for (int k = 0; k < 3; k += 1) { 195 String msg = prefix + " k=" + k + " ikey=" + indexKeys[k]; 196 setKey(key, indexKeys[k]); 197 status = cursors[k].getSearchKey(key, data, 198 LockMode.DEFAULT); 199 assertEquals(msg, OperationStatus.SUCCESS, status); 200 } 201 for (int j = 0; j < 2; j += 1) { 202 boolean withData = (j == 0); 203 JoinConfig config = (j == 0) ? null : joinConfigNoSort; 204 JoinCursor jc = priDb.join(cursors, config); 205 assertSame(priDb, jc.getDatabase()); 206 for (int k = 0; k < priKeys.length; k += 1) { 207 String msg = prefix + " k=" + k + " pkey=" + priKeys[k]; 208 if (withData) { 209 status = jc.getNext(key, data, LockMode.DEFAULT); 210 } else { 211 status = jc.getNext(key, LockMode.DEFAULT); 212 } 213 assertEquals(msg, OperationStatus.SUCCESS, status); 214 assertEquals(msg, priKeys[k], (int) key.getData()[0]); 215 if (withData) { 216 boolean dataFound = false; 217 for (int m = 0; m < dataSet.length; m += 2) { 218 int[] vals = dataSet[m]; 219 int priKey = dataSet[m + 1][0]; 220 if (priKey == priKeys[k]) { 221 for (int n = 0; n < 3; n += 1) { 222 assertEquals(msg, vals[n], 223 (int) data.getData()[n]); 224 dataFound = true; 225 } 226 } 227 } 228 assertTrue(msg, dataFound); 229 } 230 } 231 String msg = prefix + " no more expected"; 232 if (withData) { 233 status = jc.getNext(key, data, LockMode.DEFAULT); 234 } else { 235 status = jc.getNext(key, LockMode.DEFAULT); 236 } 237 assertEquals(msg, OperationStatus.NOTFOUND, status); 238 239 Cursor[] sorted = DbInternal.getSortedCursors(jc); 240 assertEquals(CURSOR_ORDER.length, sorted.length); 241 if (config == joinConfigNoSort) { 242 Database db0 = sorted[0].getDatabase(); 243 Database db1 = sorted[1].getDatabase(); 244 Database db2 = sorted[2].getDatabase(); 245 assertSame(db0, secDb0); 246 assertSame(db1, secDb1); 247 assertSame(db2, secDb2); 248 } else if (setNum == CURSOR_ORDER_SET) { 249 Database db0 = sorted[CURSOR_ORDER[0]].getDatabase(); 250 Database db1 = sorted[CURSOR_ORDER[1]].getDatabase(); 251 Database db2 = sorted[CURSOR_ORDER[2]].getDatabase(); 252 assertSame(db0, secDb0); 253 assertSame(db1, secDb1); 254 assertSame(db2, secDb2); 255 } 256 jc.close(); 257 } 258 } 259 260 c0.close(); 261 c1.close(); 262 c2.close(); 263 txnCommit(txn); 264 265 secDb0.close(); 266 secDb1.close(); 267 secDb2.close(); 268 priDb.close(); 269 270 271 txn = txnBegin(); 272 env.removeDatabase(txn, "pri"); 273 env.removeDatabase(txn, "sec0"); 274 env.removeDatabase(txn, "sec1"); 275 env.removeDatabase(txn, "sec2"); 276 txnCommit(txn); 277 } 278 279 285 public void testWriteDuringJoin() 286 throws DatabaseException { 287 288 Database priDb = openPrimary("pri"); 289 SecondaryDatabase secDb0 = openSecondary(priDb, "sec0", true, 0); 290 SecondaryDatabase secDb1 = openSecondary(priDb, "sec1", true, 1); 291 SecondaryDatabase secDb2 = openSecondary(priDb, "sec2", true, 2); 292 293 OperationStatus status; 294 DatabaseEntry key = new DatabaseEntry(); 295 DatabaseEntry data = new DatabaseEntry(); 296 Transaction txn; 297 txn = txnBegin(); 298 299 setKey(key, 13); 300 setData(data, 1, 1, 1); 301 status = priDb.put(txn, key, data); 302 assertEquals(OperationStatus.SUCCESS, status); 303 setKey(key, 14); 304 setData(data, 1, 1, 1); 305 status = priDb.put(txn, key, data); 306 assertEquals(OperationStatus.SUCCESS, status); 307 308 txnCommit(txn); 309 txn = txnBeginCursor(); 310 311 SecondaryCursor c0 = secDb0.openSecondaryCursor(txn, null); 312 SecondaryCursor c1 = secDb1.openSecondaryCursor(txn, null); 313 SecondaryCursor c2 = secDb2.openSecondaryCursor(txn, null); 314 SecondaryCursor[] cursors = {c0, c1, c2}; 315 316 for (int i = 0; i < 3; i += 1) { 317 setKey(key, 1); 318 status = cursors[i].getSearchKey(key, data, LockMode.DEFAULT); 319 assertEquals(OperationStatus.SUCCESS, status); 320 } 321 322 323 JoinCursor jc = priDb.join(cursors, null); 324 325 329 Transaction writerTxn = txnBegin(); 330 setKey(key, 12); 331 setData(data, 1, 1, 1); 332 status = priDb.put(writerTxn, key, data); 333 assertEquals(OperationStatus.SUCCESS, status); 334 335 336 status = jc.getNext(key, data, LockMode.DEFAULT); 337 assertEquals(OperationStatus.SUCCESS, status); 338 assertEquals(13, (int) key.getData()[0]); 339 status = jc.getNext(key, data, LockMode.DEFAULT); 340 assertEquals(OperationStatus.SUCCESS, status); 341 assertEquals(14, (int) key.getData()[0]); 342 status = jc.getNext(key, data, LockMode.DEFAULT); 343 assertEquals(OperationStatus.NOTFOUND, status); 344 345 346 setKey(key, 11); 347 setData(data, 1, 1, 1); 348 status = priDb.put(writerTxn, key, data); 349 assertEquals(OperationStatus.SUCCESS, status); 350 txnCommit(writerTxn); 351 352 jc.close(); 353 354 c0.close(); 355 c1.close(); 356 c2.close(); 357 txnCommit(txn); 358 359 secDb0.close(); 360 secDb1.close(); 361 secDb2.close(); 362 priDb.close(); 363 } 364 365 private Database openPrimary(String name) 366 throws DatabaseException { 367 368 DatabaseConfig dbConfig = new DatabaseConfig(); 369 dbConfig.setTransactional(isTransactional); 370 dbConfig.setAllowCreate(true); 371 372 Transaction txn = txnBegin(); 373 try { 374 return env.openDatabase(txn, name, dbConfig); 375 } finally { 376 txnCommit(txn); 377 } 378 } 379 380 private SecondaryDatabase openSecondary(Database priDb, String dbName, 381 boolean dups, int keyId) 382 throws DatabaseException { 383 384 SecondaryConfig dbConfig = new SecondaryConfig(); 385 dbConfig.setTransactional(isTransactional); 386 dbConfig.setAllowCreate(true); 387 dbConfig.setSortedDuplicates(dups); 388 if (useMultiKey) { 389 dbConfig.setMultiKeyCreator 390 (new SimpleMultiKeyCreator(new MyKeyCreator(keyId))); 391 } else { 392 dbConfig.setKeyCreator(new MyKeyCreator(keyId)); 393 } 394 395 Transaction txn = txnBegin(); 396 try { 397 return env.openSecondaryDatabase(txn, dbName, priDb, dbConfig); 398 } finally { 399 txnCommit(txn); 400 } 401 } 402 403 private static void setKey(DatabaseEntry key, int priKey) { 404 405 byte[] a = new byte[1]; 406 a[0] = (byte) priKey; 407 key.setData(a); 408 } 409 410 private static void setData(DatabaseEntry data, 411 int key1, int key2, int key3) { 412 413 byte[] a = new byte[4]; 414 a[0] = (byte) key1; 415 a[1] = (byte) key2; 416 a[2] = (byte) key3; 417 data.setData(a); 418 } 419 420 private static class MyKeyCreator implements SecondaryKeyCreator { 421 422 private int keyId; 423 424 MyKeyCreator(int keyId) { 425 426 this.keyId = keyId; 427 } 428 429 public boolean createSecondaryKey(SecondaryDatabase secondary, 430 DatabaseEntry key, 431 DatabaseEntry data, 432 DatabaseEntry result) 433 throws DatabaseException { 434 435 byte val = data.getData()[keyId]; 436 if (val != 0) { 437 result.setData(new byte[] { val }); 438 return true; 439 } else { 440 return false; 441 } 442 } 443 } 444 } 445 | Popular Tags |