/** Asserts that the queue is empty and size estimate is zero. */ private void assertQueueIsEmpty() { assertTrue("Expected empty queue", queue.isEmpty()); assertEquals("Expected queue size zero", 0, queue.estimateSize()); }
/** * Push all deltas at startResend and after back into clientOperationQueue, * discarding their ack info. * * @param startMerge The starting index to the delta in the * {@link #inferredServerPath} to start to merge into clientOperationQueue. */ private void mergeToClientQueue(int startMerge) { List<WaveletDelta> deltas = CollectionUtils.newArrayList(); // Use the version at the resend if (startMerge < inferredServerPath.size()) { Iterator<AckedDelta> iter = inferredServerPath.listIterator(startMerge); while (iter.hasNext()) { deltas.add(iter.next().delta); iter.remove(); } } if (unacknowledged != null) { deltas.add(unacknowledged); unacknowledged = null; } Collections.reverse(deltas); for (WaveletDelta delta : deltas) { clientOperationQueue.insertHead(delta); } }
/** * Takes a delta full of operations by the same creator from the head of the * queue, removing those operations from the queue. It will contain all * operations from the head of the queue up until but not including the first * change in creator. Hence if all operations in the queue have the same * creator, it will contain all those operations and the queue will become * empty. * * @return A non-empty delta without signature or version information, * containing operations which all have the same creator address in * their context. * @throws NoSuchElementException If the queue is empty. */ public List<WaveletOperation> take() { Item item = takeMergedAndOptimisedItem(queue); if (isEmpty()) { tailCreator = null; } return item.opSequence; }
/** * Tests that the queue's size estimate is at least one per un-mergable delta. * Since it's an underestimate it must be exactly correct if each delta * contains one op. */ public void testQueueSizeEstimateIsAtLeastDeltaSize() { queue.add(BOB_A); queue.add(JIM_A); queue.add(BOB_B); queue.add(JIM_B); queue.add(BOB_C); queue.add(JIM_C); assertEquals(6, queue.estimateSize()); }
/** * Tests that deltas which are transformed make their way back into the queue, * replacing the untransformed versions and being sent out of take(). */ public void testTransformedDeltasReplaceOriginals() throws TransformException { queue.add(BOB_A); queue.add(BOB_B); queue.add(JIM_C); transformer.expect(BOB_A, BOB_B).transformTo(BOB_A); transformer.expect(JIM_C).echo(); assertEquals(transformer.getOutputServerDelta(), // \u2620 queue.transform(transformer.getInputServerDelta())); transformer.checkDone(); assertQueueSizeBetween(1, 2); assertEquals(list(BOB_A), copyList(queue.take())); assertEquals(list(JIM_C), copyList(queue.take())); assertQueueIsEmpty(); }
/** * Tests that a new head delta which is being inserted does not merge with the * existing head if the creators do not match, hence the old head is moved to * be the second delta but otherwise remains unmodified. */ public void testInsertHeadMakesNewDeltaIfCreatorDiffersFromExistingHead() { queue.add(BOB_C); MergingSequence head = new MergingSequence(); head.add(JIM_A); head.add(JIM_B); queue.insertHead(head); assertEquals(list(JIM_A, JIM_B), copyList(queue.take())); assertEquals(list(BOB_C), copyList(queue.take())); assertTrue(queue.isEmpty()); }
/** * Since transform and compose doesn't commute, test we don't compose operations after * we've sent the operation. So when we push to head, we shouldn't merge sent deltas. */ public void testNoCompositionWithInsertHead() throws TransformException { DeltaTestUtil util = new DeltaTestUtil(BOB); // Do 1 client op queue.add(util.noOpDocOp("blipA")); // Pushing an op to the head should never merge queue.insertHead(Arrays.asList(util.noOpDocOp("blipA"))); // Get a server op transformer.expect(util.noOpDocOp("blipA")).echo(); transformer.expect(util.noOpDocOp("blipA")).echo(); assertEquals(transformer.getOutputServerDelta(), // \u2620 queue.transform(transformer.getInputServerDelta())); // Should be 2 deltas a the first one is not mergable assertQueueSizeBetween(1, 2); assertEquals(list(util.noOpDocOp("blipA")), copyList(queue.take())); assertEquals(list(util.noOpDocOp("blipA")), copyList(queue.take())); assertQueueIsEmpty(); }
/** * Test operations are actually transformed. */ public void testOpsAreTransformed() throws TransformException { queue = new OperationQueue(); DeltaTestUtil bob = new DeltaTestUtil(BOB); DeltaTestUtil jim = new DeltaTestUtil(JIM); // Do bob client op 1 queue.add(bob.insert(1, "a", 1, null)); // Get delta 1 from jim queue.transform(Arrays.asList(jim.insert(1, "j", 1, null))); // Do bob client op 2 queue.add(bob.insert(1, "b", 3, null)); // Get delta 2 from jim queue.transform(Arrays.asList(jim.insert(1, "i", 2, null))); // check ops are transformed assertEquals(list(bob.insert(1, "ba", 3, null)), copyList(queue.take())); assertQueueIsEmpty(); }
/** * Tests that attempting to take a delta from an empty queue results in a * {@link NoSuchElementException} being thrown. */ public void testThrowsExceptionTakingFromEmptyQueue() { try { queue.take(); fail("take() from empty queue should fail"); } catch (NoSuchElementException expected) { } }
clientOperationQueue.transform(versionOps);
@Override public int estimateUnacknowledgedSize() { return clientOperationQueue.estimateSize() + inFlightSize(); }
/** * Closes this concurrency control. */ public void close() { if (unsavedDataListener != null) { unsavedDataListener.onClose(everythingIsCommitted()); } if (!clientOperationQueue.isEmpty()) { logger.error().log("Concurrency control closed with pending operations. Data has been lost"); } }
/** * Queues the client operations, and sends them to the server as a delta at * the first opportunity. Will call any registered UnsavedDataListeners before * returning. * * @param operations the operations to send, all of which must specify a creator */ public void onClientOperations(WaveletOperation operations[]) throws TransformException { DeltaPair transformedPair = (new DeltaPair(Arrays.asList(operations), serverOperations)).transform(); serverOperations = transformedPair.getServer(); for (WaveletOperation o : transformedPair.getClient()) { clientOperationQueue.add(o); } triggerUnsavedDataListener(); sendDelta(); }
@Override protected void setUp() { transformer = new MockDeltaTransformer(); queue = new OperationQueue(transformer); }
Item item = takeMergedAndOptimisedItem(queue); MergingSequence queuedDelta = item.opSequence;
/** * Tests that deltas which are transformed make their way back into the queue, * replacing the untransformed versions and being sent out of take(). */ public void testTransformedDeltasReplaceOriginals() throws TransformException { queue.add(BOB_A); queue.add(BOB_B); queue.add(JIM_C); transformer.expect(BOB_A, BOB_B).transformTo(BOB_A); transformer.expect(JIM_C).echo(); assertEquals(transformer.getOutputServerDelta(), // \u2620 queue.transform(transformer.getInputServerDelta())); transformer.checkDone(); assertQueueSizeBetween(1, 2); assertEquals(list(BOB_A), copyList(queue.take())); assertEquals(list(JIM_C), copyList(queue.take())); assertQueueIsEmpty(); }
/** * Tests that a new head delta which is being inserted does not merge with the * existing head if the creators do not match, hence the old head is moved to * be the second delta but otherwise remains unmodified. */ public void testInsertHeadMakesNewDeltaIfCreatorDiffersFromExistingHead() { queue.add(BOB_C); MergingSequence head = new MergingSequence(); head.add(JIM_A); head.add(JIM_B); queue.insertHead(head); assertEquals(list(JIM_A, JIM_B), copyList(queue.take())); assertEquals(list(BOB_C), copyList(queue.take())); assertTrue(queue.isEmpty()); }
/** * Since transform and compose doesn't commute, test we don't compose operations after * we've sent the operation. So when we push to head, we shouldn't merge sent deltas. */ public void testNoCompositionWithInsertHead() throws TransformException { DeltaTestUtil util = new DeltaTestUtil(BOB); // Do 1 client op queue.add(util.noOpDocOp("blipA")); // Pushing an op to the head should never merge queue.insertHead(Arrays.asList(util.noOpDocOp("blipA"))); // Get a server op transformer.expect(util.noOpDocOp("blipA")).echo(); transformer.expect(util.noOpDocOp("blipA")).echo(); assertEquals(transformer.getOutputServerDelta(), // \u2620 queue.transform(transformer.getInputServerDelta())); // Should be 2 deltas a the first one is not mergable assertQueueSizeBetween(1, 2); assertEquals(list(util.noOpDocOp("blipA")), copyList(queue.take())); assertEquals(list(util.noOpDocOp("blipA")), copyList(queue.take())); assertQueueIsEmpty(); }