1 4 package com.tc.objectserver.tx; 5 6 import com.tc.net.protocol.tcm.ChannelID; 7 import com.tc.object.ObjectID; 8 import com.tc.object.dmi.DmiDescriptor; 9 import com.tc.object.dna.impl.ObjectStringSerializer; 10 import com.tc.object.lockmanager.api.LockID; 11 import com.tc.object.tx.TransactionID; 12 import com.tc.object.tx.TxnBatchID; 13 import com.tc.object.tx.TxnType; 14 import com.tc.objectserver.core.api.TestDNA; 15 import com.tc.test.TCTestCase; 16 import com.tc.util.Assert; 17 import com.tc.util.SequenceID; 18 19 import java.security.SecureRandom ; 20 import java.util.ArrayList ; 21 import java.util.Arrays ; 22 import java.util.Collections ; 23 import java.util.HashMap ; 24 import java.util.HashSet ; 25 import java.util.Iterator ; 26 import java.util.LinkedList ; 27 import java.util.List ; 28 import java.util.Map ; 29 import java.util.Random ; 30 import java.util.Set ; 31 32 public class TransactionSequencerTest extends TCTestCase { 33 34 private int sqID; 35 private int txnID; 36 private int batchID; 37 private ChannelID channelID; 38 private TransactionSequencer sequencer; 39 private int start; 40 41 public void setUp() throws Exception { 42 txnID = 100; 43 sqID = 100; 44 batchID = 100; 45 start = 1; 46 channelID = new ChannelID(0); 47 sequencer = new TransactionSequencer(); 48 } 49 50 public void testNoPendingDisjointTxn() throws Exception { 53 List txns = createDisjointTxns(5); 54 sequencer.addTransactions(txns); 55 assertEquals(txns, getAllTxnsPossible()); 56 assertFalse(sequencer.isPending(txns)); 57 } 58 59 public void testNoPendingJointTxn() throws Exception { 62 List txns = createIntersectingLocksTxns(5); 63 sequencer.addTransactions(txns); 64 assertEquals(txns, getAllTxnsPossible()); 65 assertFalse(sequencer.isPending(txns)); 66 } 67 68 public void testPendingDisJointTxn() throws Exception { 71 List txns = createDisjointTxns(5); 72 sequencer.addTransactions(txns); 73 ServerTransaction t1 = sequencer.getNextTxnToProcess(); 74 assertNotNull(t1); 75 sequencer.makePending(t1); 77 assertTrue(sequencer.isPending(txns)); 78 txns.remove(t1); 79 assertEquals(txns, getAllTxnsPossible()); 80 assertTrue(sequencer.isPending(Arrays.asList(new Object [] { t1 }))); 81 assertNull(sequencer.getNextTxnToProcess()); 83 sequencer.makeUnpending(t1); 84 assertFalse(sequencer.isPending(Arrays.asList(new Object [] { t1 }))); 85 assertNull(sequencer.getNextTxnToProcess()); 87 } 88 89 public void testPendingJointAtLocksTxn() throws Exception { 92 List txns = createIntersectingLocksTxns(5); 93 sequencer.addTransactions(txns); 94 ServerTransaction t1 = sequencer.getNextTxnToProcess(); 95 assertNotNull(t1); 96 sequencer.makePending(t1); 98 assertTrue(sequencer.isPending(txns)); 99 txns.remove(t1); 100 101 assertNull(sequencer.getNextTxnToProcess()); 103 assertTrue(sequencer.isPending(Arrays.asList(new Object [] { t1 }))); 104 sequencer.makeUnpending(t1); 105 assertFalse(sequencer.isPending(Arrays.asList(new Object [] { t1 }))); 106 assertEquals(txns, getAllTxnsPossible()); 108 } 109 110 public void testPendingJointAtObjectsTxn() throws Exception { 113 List txns = createIntersectingObjectsTxns(5); 114 sequencer.addTransactions(txns); 115 ServerTransaction t1 = sequencer.getNextTxnToProcess(); 116 assertNotNull(t1); 117 sequencer.makePending(t1); 119 assertTrue(sequencer.isPending(txns)); 120 txns.remove(t1); 121 122 assertNull(sequencer.getNextTxnToProcess()); 124 assertTrue(sequencer.isPending(Arrays.asList(new Object [] { t1 }))); 125 sequencer.makeUnpending(t1); 126 assertFalse(sequencer.isPending(Arrays.asList(new Object [] { t1 }))); 127 assertEquals(txns, getAllTxnsPossible()); 129 } 130 131 public void testPendingJointAtBothLocksAndObjectsTxn() throws Exception { 134 List txns = createIntersectingLocksObjectsTxns(5); 135 sequencer.addTransactions(txns); 136 ServerTransaction t1 = sequencer.getNextTxnToProcess(); 137 assertNotNull(t1); 138 sequencer.makePending(t1); 140 assertTrue(sequencer.isPending(txns)); 141 txns.remove(t1); 142 143 assertNull(sequencer.getNextTxnToProcess()); 145 assertTrue(sequencer.isPending(Arrays.asList(new Object [] { t1 }))); 146 sequencer.makeUnpending(t1); 147 assertFalse(sequencer.isPending(Arrays.asList(new Object [] { t1 }))); 148 assertEquals(txns, getAllTxnsPossible()); 150 } 151 152 public void testErrorConditions() throws Exception { 155 List txns = createDisjointTxns(5); 157 sequencer.addTransactions(txns); 158 ServerTransaction t1 = sequencer.getNextTxnToProcess(); 159 assertNotNull(t1); 160 sequencer.makePending(t1); 161 assertTrue(sequencer.isPending(txns)); 162 try { 163 sequencer.makePending(t1); 164 fail(); 165 } catch (Throwable t) { 166 } 168 169 ServerTransaction t2 = sequencer.getNextTxnToProcess(); 171 assertNotNull(t2); 172 try { 173 sequencer.makeUnpending(t2); 174 fail(); 175 } catch (Throwable t) { 176 } 178 sequencer.makeUnpending(t1); 179 } 180 181 public void testOrderingByOID() { 182 List txns = new ArrayList (); 183 184 int lock = 0; 185 186 ServerTransaction txn1 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(1), 187 new SequenceID(sqID++), createLocks(lock, lock++), channelID, 188 createDNAs(1, 1), new ObjectStringSerializer(), 189 Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList (), 190 DmiDescriptor.EMPTY_ARRAY); 191 192 ServerTransaction txn2 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(2), 193 new SequenceID(sqID++), createLocks(lock, lock++), channelID, 194 createDNAs(2, 2), new ObjectStringSerializer(), 195 Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList (), 196 DmiDescriptor.EMPTY_ARRAY); 197 198 ServerTransaction txn3 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(3), 199 new SequenceID(sqID++), createLocks(lock, lock++), channelID, 200 createDNAs(2, 3), new ObjectStringSerializer(), 201 Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList (), 202 DmiDescriptor.EMPTY_ARRAY); 203 204 ServerTransaction txn4 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(4), 205 new SequenceID(sqID++), createLocks(lock, lock++), channelID, 206 createDNAs(1, 2), new ObjectStringSerializer(), 207 Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList (), 208 DmiDescriptor.EMPTY_ARRAY); 209 210 txns.add(txn1); 211 txns.add(txn2); 212 txns.add(txn3); 213 txns.add(txn4); 214 sequencer.addTransactions(txns); 215 216 sequencer.makePending(sequencer.getNextTxnToProcess()); 217 sequencer.makePending(sequencer.getNextTxnToProcess()); 218 219 Object o; 220 o = sequencer.getNextTxnToProcess(); 221 Assert.assertNull(o); 222 o = sequencer.getNextTxnToProcess(); 223 Assert.assertNull(o); 224 225 sequencer.makeUnpending(txn2); 226 sequencer.makeUnpending(txn1); 227 228 ServerTransaction shouldBe3 = sequencer.getNextTxnToProcess(); 229 ServerTransaction shouldBe4 = sequencer.getNextTxnToProcess(); 230 231 Assert.assertEquals(txn3, shouldBe3); 232 Assert.assertEquals(txn4, shouldBe4); 233 } 234 235 public void testOrderingByLock() { 236 List txns = new ArrayList (); 237 238 int oid = 0; 239 240 ServerTransaction txn1 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(1), 241 new SequenceID(sqID++), createLocks(1, 1), channelID, 242 createDNAs(oid, oid++), new ObjectStringSerializer(), 243 Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList (), 244 DmiDescriptor.EMPTY_ARRAY); 245 246 ServerTransaction txn2 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(2), 247 new SequenceID(sqID++), createLocks(2, 2), channelID, 248 createDNAs(oid, oid++), new ObjectStringSerializer(), 249 Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList (), 250 DmiDescriptor.EMPTY_ARRAY); 251 252 ServerTransaction txn3 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(3), 253 new SequenceID(sqID++), createLocks(2, 3), channelID, 254 createDNAs(oid, oid++), new ObjectStringSerializer(), 255 Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList (), 256 DmiDescriptor.EMPTY_ARRAY); 257 258 ServerTransaction txn4 = new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(4), 259 new SequenceID(sqID++), createLocks(1, 2), channelID, 260 createDNAs(oid, oid++), new ObjectStringSerializer(), 261 Collections.EMPTY_MAP, TxnType.NORMAL, new LinkedList (), 262 DmiDescriptor.EMPTY_ARRAY); 263 264 txns.add(txn1); 265 txns.add(txn2); 266 txns.add(txn3); 267 txns.add(txn4); 268 sequencer.addTransactions(txns); 269 270 sequencer.makePending(sequencer.getNextTxnToProcess()); 271 sequencer.makePending(sequencer.getNextTxnToProcess()); 272 273 Object o; 274 o = sequencer.getNextTxnToProcess(); 275 Assert.assertNull(o); 276 o = sequencer.getNextTxnToProcess(); 277 Assert.assertNull(o); 278 279 sequencer.makeUnpending(txn2); 280 sequencer.makeUnpending(txn1); 281 282 ServerTransaction shouldBe3 = sequencer.getNextTxnToProcess(); 283 ServerTransaction shouldBe4 = sequencer.getNextTxnToProcess(); 284 285 Assert.assertEquals(txn3, shouldBe3); 286 Assert.assertEquals(txn4, shouldBe4); 287 } 288 289 public void testRandom() { 290 for (int i = 0; i < 100; i++) { 291 System.err.println("Running testRandom : " + i); 292 doRandom(); 293 sequencer = new TransactionSequencer(); 294 } 295 } 296 297 public void testRandomFailedSeed1() { 298 long seed = -7748167846395034562L; 299 System.err.println("Testing failed seed : " + seed); 300 doRandom(seed); 301 } 302 303 public void testRandomFailedSeed2() { 304 long seed = -149113776740941224L; 305 System.err.println("Testing failed seed : " + seed); 306 doRandom(seed); 307 } 308 309 private void doRandom() { 312 final long seed = new SecureRandom ().nextLong(); 313 System.err.println("seed is " + seed); 314 doRandom(seed); 315 } 316 317 private void doRandom(long seed) { 318 Random rnd = new Random (seed); 319 320 int lock = 0; 321 final int numObjects = 25; 322 long versionsIn[] = new long[numObjects]; 323 long versionsRecv[] = new long[numObjects]; 324 325 Set pending = new HashSet (); 326 327 for (int loop = 0; loop < 10000; loop++) { 328 List txns = new ArrayList (); 329 for (int i = 0, n = rnd.nextInt(3) + 1; i < n; i++) { 330 txns.add(createRandomTxn(rnd.nextInt(3) + 1, versionsIn, rnd, lock++)); 331 } 332 333 sequencer.addTransactions(txns); 334 335 ServerTransaction next = null; 336 while ((next = sequencer.getNextTxnToProcess()) != null) { 337 if (rnd.nextInt(3) == 0) { 338 sequencer.makePending(next); 339 pending.add(next); 340 continue; 341 } 342 343 processTransaction(next, versionsRecv); 344 345 if (pending.size() > 0 && rnd.nextInt(4) == 0) { 346 for (int i = 0, n = rnd.nextInt(pending.size()); i < n; i++) { 347 Iterator iter = pending.iterator(); 348 ServerTransaction pendingTxn = (ServerTransaction) iter.next(); 349 iter.remove(); 350 processTransaction(pendingTxn, versionsRecv); 351 sequencer.makeUnpending(pendingTxn); 352 } 353 } 354 } 355 356 } 357 } 358 359 private void processTransaction(ServerTransaction next, long[] versionsRecv) { 360 for (Iterator iter = next.getChanges().iterator(); iter.hasNext();) { 361 TestDNA dna = (TestDNA) iter.next(); 362 int oid = (int) dna.getObjectID().toLong(); 363 long ver = dna.version; 364 long expect = versionsRecv[oid] + 1; 365 if (expect != ver) { 366 throw new AssertionError (oid + " : Expected change to increment to version " + expect 368 + ", but change was to version " + ver); 369 } 370 versionsRecv[oid] = ver; 371 } 372 } 373 374 private ServerTransaction createRandomTxn(int numObjects, long[] versions, Random rnd, int lockID) { 375 Map dnas = new HashMap (); 376 while (numObjects > 0) { 377 int i = rnd.nextInt(versions.length); 378 if (!dnas.containsKey(new Integer (i))) { 379 TestDNA dna = new TestDNA(new ObjectID(i)); 380 dna.version = ++versions[i]; 381 dnas.put(new Integer (i), dna); 382 numObjects--; 383 } 384 } 385 386 return new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(txnID++), new SequenceID(sqID++), 387 createLocks(lockID, lockID), channelID, new ArrayList (dnas.values()), 388 new ObjectStringSerializer(), Collections.EMPTY_MAP, TxnType.NORMAL, 389 new LinkedList (), DmiDescriptor.EMPTY_ARRAY); 390 } 391 392 private List getAllTxnsPossible() { 393 List txns = new ArrayList (); 394 ServerTransaction txn; 395 while ((txn = sequencer.getNextTxnToProcess()) != null) { 396 txns.add(txn); 397 } 398 return txns; 399 } 400 401 private List createDisjointTxns(int count) { 402 List txns = new ArrayList (); 403 batchID++; 404 int j = 3; 405 while (count-- > 0) { 406 int e = start + j; 407 txns.add(new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(txnID++), new SequenceID(sqID++), 408 createLocks(start, e), channelID, createDNAs(start, e), 409 new ObjectStringSerializer(), Collections.EMPTY_MAP, TxnType.NORMAL, 410 new LinkedList (), DmiDescriptor.EMPTY_ARRAY)); 411 start = e + 1; 412 } 413 return txns; 414 } 415 416 private List createIntersectingLocksTxns(int count) { 417 List txns = new ArrayList (); 418 batchID++; 419 int j = 3; 420 while (count-- > 0) { 421 int e = start + j; 422 txns.add(new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(txnID++), new SequenceID(sqID++), 423 createLocks(start, e + j), channelID, createDNAs(start, e), 424 new ObjectStringSerializer(), Collections.EMPTY_MAP, TxnType.NORMAL, 425 new LinkedList (), DmiDescriptor.EMPTY_ARRAY)); 426 start = e + 1; 427 } 428 return txns; 429 } 430 431 private List createIntersectingObjectsTxns(int count) { 432 List txns = new ArrayList (); 433 batchID++; 434 int j = 3; 435 while (count-- > 0) { 436 int e = start + j; 437 txns.add(new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(txnID++), new SequenceID(sqID++), 438 createLocks(start, e), channelID, createDNAs(start, e + j), 439 new ObjectStringSerializer(), Collections.EMPTY_MAP, TxnType.NORMAL, 440 new LinkedList (), DmiDescriptor.EMPTY_ARRAY)); 441 start = e + 1; 442 } 443 return txns; 444 } 445 446 private List createIntersectingLocksObjectsTxns(int count) { 447 List txns = new ArrayList (); 448 batchID++; 449 int j = 3; 450 while (count-- > 0) { 451 int e = start + j; 452 txns.add(new ServerTransactionImpl(new TxnBatchID(batchID), new TransactionID(txnID++), new SequenceID(sqID++), 453 createLocks(start, e + j), channelID, createDNAs(start, e + j), 454 new ObjectStringSerializer(), Collections.EMPTY_MAP, TxnType.NORMAL, 455 new LinkedList (), DmiDescriptor.EMPTY_ARRAY)); 456 start = e + 1; 457 } 458 return txns; 459 } 460 461 private List createDNAs(int s, int e) { 462 List dnas = new ArrayList (); 463 for (int i = s; i <= e; i++) { 464 dnas.add(new TestDNA(new ObjectID(i))); 465 } 466 return dnas; 467 } 468 469 private LockID[] createLocks(int s, int e) { 470 LockID[] locks = new LockID[e - s + 1]; 471 for (int j = s; j <= e; j++) { 472 locks[j - s] = new LockID("@" + j); 473 } 474 return locks; 475 } 476 } 477 | Popular Tags |