2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.cluster.datastore;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.fail;
14 import static org.mockito.Matchers.any;
15 import static org.mockito.Matchers.anyBoolean;
16 import static org.mockito.Matchers.eq;
17 import static org.mockito.Mockito.atLeastOnce;
18 import static org.mockito.Mockito.doNothing;
19 import static org.mockito.Mockito.doReturn;
20 import static org.mockito.Mockito.inOrder;
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.never;
23 import static org.mockito.Mockito.reset;
24 import static org.mockito.Mockito.verify;
25 import static org.mockito.Mockito.verifyNoMoreInteractions;
26 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.coordinatedCanCommit;
27 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.coordinatedCommit;
28 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.coordinatedPreCommit;
29 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.immediate3PhaseCommit;
30 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.immediateCanCommit;
31 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.immediateCommit;
32 import static org.opendaylight.controller.cluster.datastore.ShardDataTreeMocking.immediatePreCommit;
34 import com.google.common.base.Optional;
35 import com.google.common.base.Ticker;
36 import com.google.common.collect.Maps;
37 import com.google.common.primitives.UnsignedLong;
38 import com.google.common.util.concurrent.FutureCallback;
39 import java.math.BigInteger;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.List;
44 import java.util.concurrent.ExecutionException;
45 import java.util.function.Consumer;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.mockito.ArgumentCaptor;
49 import org.mockito.InOrder;
50 import org.mockito.Mockito;
51 import org.opendaylight.controller.cluster.datastore.jmx.mbeans.shard.ShardStats;
52 import org.opendaylight.controller.cluster.datastore.persisted.CommitTransactionPayload;
53 import org.opendaylight.controller.md.cluster.datastore.model.CarsModel;
54 import org.opendaylight.controller.md.cluster.datastore.model.PeopleModel;
55 import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper;
56 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
57 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
58 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
59 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
60 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
61 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
62 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
63 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
64 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
65 import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType;
66 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
68 public class ShardDataTreeTest extends AbstractTest {
70 private final Shard mockShard = Mockito.mock(Shard.class);
71 private ShardDataTree shardDataTree;
72 private SchemaContext fullSchema;
76 doReturn(true).when(mockShard).canSkipPayload();
77 doReturn(Ticker.systemTicker()).when(mockShard).ticker();
78 doReturn(Mockito.mock(ShardStats.class)).when(mockShard).getShardMBean();
80 fullSchema = SchemaContextHelper.full();
82 shardDataTree = new ShardDataTree(mockShard, fullSchema, TreeType.OPERATIONAL);
86 public void testWrite() throws ExecutionException, InterruptedException {
87 modify(false, true, true);
91 public void testMerge() throws ExecutionException, InterruptedException {
92 modify(true, true, true);
95 private void modify(final boolean merge, final boolean expectedCarsPresent, final boolean expectedPeoplePresent)
96 throws ExecutionException, InterruptedException {
98 assertEquals(fullSchema, shardDataTree.getSchemaContext());
100 final ReadWriteShardDataTreeTransaction transaction =
101 shardDataTree.newReadWriteTransaction(nextTransactionId());
103 final DataTreeModification snapshot = transaction.getSnapshot();
105 assertNotNull(snapshot);
108 snapshot.merge(CarsModel.BASE_PATH, CarsModel.create());
109 snapshot.merge(PeopleModel.BASE_PATH, PeopleModel.create());
111 snapshot.write(CarsModel.BASE_PATH, CarsModel.create());
112 snapshot.write(PeopleModel.BASE_PATH, PeopleModel.create());
115 final ShardDataTreeCohort cohort = shardDataTree.finishTransaction(transaction);
117 immediateCanCommit(cohort);
118 immediatePreCommit(cohort);
119 immediateCommit(cohort);
121 final ReadOnlyShardDataTreeTransaction readOnlyShardDataTreeTransaction =
122 shardDataTree.newReadOnlyTransaction(nextTransactionId());
124 final DataTreeSnapshot snapshot1 = readOnlyShardDataTreeTransaction.getSnapshot();
126 final Optional<NormalizedNode<?, ?>> optional = snapshot1.readNode(CarsModel.BASE_PATH);
128 assertEquals(expectedCarsPresent, optional.isPresent());
130 final Optional<NormalizedNode<?, ?>> optional1 = snapshot1.readNode(PeopleModel.BASE_PATH);
132 assertEquals(expectedPeoplePresent, optional1.isPresent());
136 public void bug4359AddRemoveCarOnce() throws ExecutionException, InterruptedException {
137 final List<DataTreeCandidate> candidates = new ArrayList<>();
138 candidates.add(addCar(shardDataTree));
139 candidates.add(removeCar(shardDataTree));
141 final NormalizedNode<?, ?> expected = getCars(shardDataTree);
143 applyCandidates(shardDataTree, candidates);
145 final NormalizedNode<?, ?> actual = getCars(shardDataTree);
147 assertEquals(expected, actual);
151 public void bug4359AddRemoveCarTwice() throws ExecutionException, InterruptedException {
152 final List<DataTreeCandidate> candidates = new ArrayList<>();
153 candidates.add(addCar(shardDataTree));
154 candidates.add(removeCar(shardDataTree));
155 candidates.add(addCar(shardDataTree));
156 candidates.add(removeCar(shardDataTree));
158 final NormalizedNode<?, ?> expected = getCars(shardDataTree);
160 applyCandidates(shardDataTree, candidates);
162 final NormalizedNode<?, ?> actual = getCars(shardDataTree);
164 assertEquals(expected, actual);
168 public void testListenerNotifiedOnApplySnapshot() throws Exception {
169 DOMDataTreeChangeListener listener = mock(DOMDataTreeChangeListener.class);
170 shardDataTree.registerTreeChangeListener(CarsModel.CAR_LIST_PATH.node(CarsModel.CAR_QNAME), listener);
172 addCar(shardDataTree, "optima");
174 verifyOnDataTreeChanged(listener, dtc -> {
175 assertEquals("getModificationType", ModificationType.WRITE, dtc.getRootNode().getModificationType());
176 assertEquals("getRootPath", CarsModel.newCarPath("optima"), dtc.getRootPath());
179 addCar(shardDataTree, "sportage");
181 verifyOnDataTreeChanged(listener, dtc -> {
182 assertEquals("getModificationType", ModificationType.WRITE, dtc.getRootNode().getModificationType());
183 assertEquals("getRootPath", CarsModel.newCarPath("sportage"), dtc.getRootPath());
186 ShardDataTree newDataTree = new ShardDataTree(mockShard, fullSchema, TreeType.OPERATIONAL);
187 addCar(newDataTree, "optima");
188 addCar(newDataTree, "murano");
190 shardDataTree.applySnapshot(newDataTree.takeStateSnapshot());
192 Map<YangInstanceIdentifier, ModificationType> expChanges = Maps.newHashMap();
193 expChanges.put(CarsModel.newCarPath("optima"), ModificationType.WRITE);
194 expChanges.put(CarsModel.newCarPath("murano"), ModificationType.WRITE);
195 expChanges.put(CarsModel.newCarPath("sportage"), ModificationType.DELETE);
196 verifyOnDataTreeChanged(listener, dtc -> {
197 ModificationType expType = expChanges.remove(dtc.getRootPath());
198 assertNotNull("Got unexpected change for " + dtc.getRootPath(), expType);
199 assertEquals("getModificationType", expType, dtc.getRootNode().getModificationType());
202 if (!expChanges.isEmpty()) {
203 fail("Missing change notifications: " + expChanges);
208 public void testPipelinedTransactionsWithCoordinatedCommits() throws Exception {
209 doReturn(false).when(mockShard).canSkipPayload();
211 final ShardDataTreeCohort cohort1 = newShardDataTreeCohort(snapshot ->
212 snapshot.write(CarsModel.BASE_PATH, CarsModel.emptyContainer()));
214 final ShardDataTreeCohort cohort2 = newShardDataTreeCohort(snapshot ->
215 snapshot.write(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode()));
217 NormalizedNode<?, ?> peopleNode = PeopleModel.create();
218 final ShardDataTreeCohort cohort3 = newShardDataTreeCohort(snapshot ->
219 snapshot.write(PeopleModel.BASE_PATH, peopleNode));
221 YangInstanceIdentifier carPath = CarsModel.newCarPath("optima");
222 MapEntryNode carNode = CarsModel.newCarEntry("optima", new BigInteger("100"));
223 final ShardDataTreeCohort cohort4 = newShardDataTreeCohort(snapshot -> snapshot.write(carPath, carNode));
225 immediateCanCommit(cohort1);
226 final FutureCallback<Void> canCommitCallback2 = coordinatedCanCommit(cohort2);
227 final FutureCallback<Void> canCommitCallback3 = coordinatedCanCommit(cohort3);
228 final FutureCallback<Void> canCommitCallback4 = coordinatedCanCommit(cohort4);
230 final FutureCallback<DataTreeCandidate> preCommitCallback1 = coordinatedPreCommit(cohort1);
231 verify(preCommitCallback1).onSuccess(cohort1.getCandidate());
232 verify(canCommitCallback2).onSuccess(null);
234 final FutureCallback<DataTreeCandidate> preCommitCallback2 = coordinatedPreCommit(cohort2);
235 verify(preCommitCallback2).onSuccess(cohort2.getCandidate());
236 verify(canCommitCallback3).onSuccess(null);
238 final FutureCallback<DataTreeCandidate> preCommitCallback3 = coordinatedPreCommit(cohort3);
239 verify(preCommitCallback3).onSuccess(cohort3.getCandidate());
240 verify(canCommitCallback4).onSuccess(null);
242 final FutureCallback<DataTreeCandidate> preCommitCallback4 = coordinatedPreCommit(cohort4);
243 verify(preCommitCallback4).onSuccess(cohort4.getCandidate());
245 final FutureCallback<UnsignedLong> commitCallback2 = coordinatedCommit(cohort2);
246 verify(mockShard, never()).persistPayload(eq(cohort1.getIdentifier()), any(CommitTransactionPayload.class),
248 verifyNoMoreInteractions(commitCallback2);
250 final FutureCallback<UnsignedLong> commitCallback4 = coordinatedCommit(cohort4);
251 verify(mockShard, never()).persistPayload(eq(cohort4.getIdentifier()), any(CommitTransactionPayload.class),
253 verifyNoMoreInteractions(commitCallback4);
255 final FutureCallback<UnsignedLong> commitCallback1 = coordinatedCommit(cohort1);
256 InOrder inOrder = inOrder(mockShard);
257 inOrder.verify(mockShard).persistPayload(eq(cohort1.getIdentifier()), any(CommitTransactionPayload.class),
259 inOrder.verify(mockShard).persistPayload(eq(cohort2.getIdentifier()), any(CommitTransactionPayload.class),
261 verifyNoMoreInteractions(commitCallback1);
262 verifyNoMoreInteractions(commitCallback2);
264 final FutureCallback<UnsignedLong> commitCallback3 = coordinatedCommit(cohort3);
265 inOrder = inOrder(mockShard);
266 inOrder.verify(mockShard).persistPayload(eq(cohort3.getIdentifier()), any(CommitTransactionPayload.class),
268 inOrder.verify(mockShard).persistPayload(eq(cohort4.getIdentifier()), any(CommitTransactionPayload.class),
270 verifyNoMoreInteractions(commitCallback3);
271 verifyNoMoreInteractions(commitCallback4);
273 final ShardDataTreeCohort cohort5 = newShardDataTreeCohort(snapshot ->
274 snapshot.merge(CarsModel.BASE_PATH, CarsModel.emptyContainer()));
275 final FutureCallback<Void> canCommitCallback5 = coordinatedCanCommit(cohort5);
277 // The payload instance doesn't matter - it just needs to be of type CommitTransactionPayload.
278 CommitTransactionPayload mockPayload = CommitTransactionPayload.create(nextTransactionId(),
279 cohort1.getCandidate());
280 shardDataTree.applyReplicatedPayload(cohort1.getIdentifier(), mockPayload);
281 shardDataTree.applyReplicatedPayload(cohort2.getIdentifier(), mockPayload);
282 shardDataTree.applyReplicatedPayload(cohort3.getIdentifier(), mockPayload);
283 shardDataTree.applyReplicatedPayload(cohort4.getIdentifier(), mockPayload);
285 inOrder = inOrder(commitCallback1, commitCallback2, commitCallback3, commitCallback4);
286 inOrder.verify(commitCallback1).onSuccess(any(UnsignedLong.class));
287 inOrder.verify(commitCallback2).onSuccess(any(UnsignedLong.class));
288 inOrder.verify(commitCallback3).onSuccess(any(UnsignedLong.class));
289 inOrder.verify(commitCallback4).onSuccess(any(UnsignedLong.class));
291 verify(canCommitCallback5).onSuccess(null);
293 final DataTreeSnapshot snapshot =
294 shardDataTree.newReadOnlyTransaction(nextTransactionId()).getSnapshot();
295 Optional<NormalizedNode<?, ?>> optional = snapshot.readNode(carPath);
296 assertEquals("Car node present", true, optional.isPresent());
297 assertEquals("Car node", carNode, optional.get());
299 optional = snapshot.readNode(PeopleModel.BASE_PATH);
300 assertEquals("People node present", true, optional.isPresent());
301 assertEquals("People node", peopleNode, optional.get());
305 public void testPipelinedTransactionsWithImmediateCommits() throws Exception {
306 doReturn(false).when(mockShard).canSkipPayload();
308 final ShardDataTreeCohort cohort1 = newShardDataTreeCohort(snapshot ->
309 snapshot.write(CarsModel.BASE_PATH, CarsModel.emptyContainer()));
311 final ShardDataTreeCohort cohort2 = newShardDataTreeCohort(snapshot ->
312 snapshot.write(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode()));
314 YangInstanceIdentifier carPath = CarsModel.newCarPath("optima");
315 MapEntryNode carNode = CarsModel.newCarEntry("optima", new BigInteger("100"));
316 final ShardDataTreeCohort cohort3 = newShardDataTreeCohort(snapshot -> snapshot.write(carPath, carNode));
318 final FutureCallback<UnsignedLong> commitCallback2 = immediate3PhaseCommit(cohort2);
319 final FutureCallback<UnsignedLong> commitCallback3 = immediate3PhaseCommit(cohort3);
320 final FutureCallback<UnsignedLong> commitCallback1 = immediate3PhaseCommit(cohort1);
322 InOrder inOrder = inOrder(mockShard);
323 inOrder.verify(mockShard).persistPayload(eq(cohort1.getIdentifier()), any(CommitTransactionPayload.class),
325 inOrder.verify(mockShard).persistPayload(eq(cohort2.getIdentifier()), any(CommitTransactionPayload.class),
327 inOrder.verify(mockShard).persistPayload(eq(cohort3.getIdentifier()), any(CommitTransactionPayload.class),
330 // The payload instance doesn't matter - it just needs to be of type CommitTransactionPayload.
331 CommitTransactionPayload mockPayload = CommitTransactionPayload.create(nextTransactionId(),
332 cohort1.getCandidate());
333 shardDataTree.applyReplicatedPayload(cohort1.getIdentifier(), mockPayload);
334 shardDataTree.applyReplicatedPayload(cohort2.getIdentifier(), mockPayload);
335 shardDataTree.applyReplicatedPayload(cohort3.getIdentifier(), mockPayload);
337 inOrder = inOrder(commitCallback1, commitCallback2, commitCallback3);
338 inOrder.verify(commitCallback1).onSuccess(any(UnsignedLong.class));
339 inOrder.verify(commitCallback2).onSuccess(any(UnsignedLong.class));
340 inOrder.verify(commitCallback3).onSuccess(any(UnsignedLong.class));
342 final DataTreeSnapshot snapshot =
343 shardDataTree.newReadOnlyTransaction(nextTransactionId()).getSnapshot();
344 Optional<NormalizedNode<?, ?>> optional = snapshot.readNode(carPath);
345 assertEquals("Car node present", true, optional.isPresent());
346 assertEquals("Car node", carNode, optional.get());
349 @SuppressWarnings("unchecked")
351 public void testAbortWithPendingCommits() throws Exception {
352 doReturn(false).when(mockShard).canSkipPayload();
354 final ShardDataTreeCohort cohort1 = newShardDataTreeCohort(snapshot ->
355 snapshot.write(CarsModel.BASE_PATH, CarsModel.emptyContainer()));
357 final ShardDataTreeCohort cohort2 = newShardDataTreeCohort(snapshot ->
358 snapshot.write(PeopleModel.BASE_PATH, PeopleModel.create()));
360 final ShardDataTreeCohort cohort3 = newShardDataTreeCohort(snapshot ->
361 snapshot.write(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode()));
363 YangInstanceIdentifier carPath = CarsModel.newCarPath("optima");
364 MapEntryNode carNode = CarsModel.newCarEntry("optima", new BigInteger("100"));
365 final ShardDataTreeCohort cohort4 = newShardDataTreeCohort(snapshot -> snapshot.write(carPath, carNode));
367 coordinatedCanCommit(cohort2);
368 immediateCanCommit(cohort1);
369 coordinatedCanCommit(cohort3);
370 coordinatedCanCommit(cohort4);
372 coordinatedPreCommit(cohort1);
373 coordinatedPreCommit(cohort2);
374 coordinatedPreCommit(cohort3);
376 FutureCallback<Void> mockAbortCallback = mock(FutureCallback.class);
377 doNothing().when(mockAbortCallback).onSuccess(null);
378 cohort2.abort(mockAbortCallback);
379 verify(mockAbortCallback).onSuccess(null);
381 coordinatedPreCommit(cohort4);
382 coordinatedCommit(cohort1);
383 coordinatedCommit(cohort3);
384 coordinatedCommit(cohort4);
386 InOrder inOrder = inOrder(mockShard);
387 inOrder.verify(mockShard).persistPayload(eq(cohort1.getIdentifier()), any(CommitTransactionPayload.class),
389 inOrder.verify(mockShard).persistPayload(eq(cohort3.getIdentifier()), any(CommitTransactionPayload.class),
391 inOrder.verify(mockShard).persistPayload(eq(cohort4.getIdentifier()), any(CommitTransactionPayload.class),
394 // The payload instance doesn't matter - it just needs to be of type CommitTransactionPayload.
395 CommitTransactionPayload mockPayload = CommitTransactionPayload.create(nextTransactionId(),
396 cohort1.getCandidate());
397 shardDataTree.applyReplicatedPayload(cohort1.getIdentifier(), mockPayload);
398 shardDataTree.applyReplicatedPayload(cohort3.getIdentifier(), mockPayload);
399 shardDataTree.applyReplicatedPayload(cohort4.getIdentifier(), mockPayload);
401 final DataTreeSnapshot snapshot =
402 shardDataTree.newReadOnlyTransaction(nextTransactionId()).getSnapshot();
403 Optional<NormalizedNode<?, ?>> optional = snapshot.readNode(carPath);
404 assertEquals("Car node present", true, optional.isPresent());
405 assertEquals("Car node", carNode, optional.get());
408 @SuppressWarnings("unchecked")
410 public void testAbortWithFailedRebase() throws Exception {
411 final ShardDataTreeCohort cohort1 = newShardDataTreeCohort(snapshot ->
412 snapshot.write(CarsModel.BASE_PATH, CarsModel.emptyContainer()));
414 final ShardDataTreeCohort cohort2 = newShardDataTreeCohort(snapshot ->
415 snapshot.write(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode()));
417 NormalizedNode<?, ?> peopleNode = PeopleModel.create();
418 final ShardDataTreeCohort cohort3 = newShardDataTreeCohort(snapshot ->
419 snapshot.write(PeopleModel.BASE_PATH, peopleNode));
421 immediateCanCommit(cohort1);
422 FutureCallback<Void> canCommitCallback2 = coordinatedCanCommit(cohort2);
424 coordinatedPreCommit(cohort1);
425 verify(canCommitCallback2).onSuccess(null);
427 FutureCallback<Void> mockAbortCallback = mock(FutureCallback.class);
428 doNothing().when(mockAbortCallback).onSuccess(null);
429 cohort1.abort(mockAbortCallback);
430 verify(mockAbortCallback).onSuccess(null);
432 FutureCallback<DataTreeCandidate> preCommitCallback2 = coordinatedPreCommit(cohort2);
433 verify(preCommitCallback2).onFailure(any(Throwable.class));
435 immediateCanCommit(cohort3);
436 immediatePreCommit(cohort3);
437 immediateCommit(cohort3);
439 final DataTreeSnapshot snapshot =
440 shardDataTree.newReadOnlyTransaction(nextTransactionId()).getSnapshot();
441 Optional<NormalizedNode<?, ?>> optional = snapshot.readNode(PeopleModel.BASE_PATH);
442 assertEquals("People node present", true, optional.isPresent());
443 assertEquals("People node", peopleNode, optional.get());
446 private ShardDataTreeCohort newShardDataTreeCohort(final DataTreeOperation operation) {
447 final ReadWriteShardDataTreeTransaction transaction =
448 shardDataTree.newReadWriteTransaction(nextTransactionId());
449 final DataTreeModification snapshot = transaction.getSnapshot();
450 operation.execute(snapshot);
451 return shardDataTree.finishTransaction(transaction);
454 @SuppressWarnings({ "rawtypes", "unchecked" })
455 private static void verifyOnDataTreeChanged(final DOMDataTreeChangeListener listener,
456 final Consumer<DataTreeCandidate> callback) {
457 ArgumentCaptor<Collection> changes = ArgumentCaptor.forClass(Collection.class);
458 verify(listener, atLeastOnce()).onDataTreeChanged(changes.capture());
459 for (Collection list : changes.getAllValues()) {
460 for (Object dtc : list) {
461 callback.accept((DataTreeCandidate)dtc);
468 private static NormalizedNode<?, ?> getCars(final ShardDataTree shardDataTree) {
469 final ReadOnlyShardDataTreeTransaction readOnlyShardDataTreeTransaction =
470 shardDataTree.newReadOnlyTransaction(nextTransactionId());
471 final DataTreeSnapshot snapshot1 = readOnlyShardDataTreeTransaction.getSnapshot();
473 final Optional<NormalizedNode<?, ?>> optional = snapshot1.readNode(CarsModel.BASE_PATH);
475 assertEquals(true, optional.isPresent());
477 return optional.get();
480 private static DataTreeCandidate addCar(final ShardDataTree shardDataTree)
481 throws ExecutionException, InterruptedException {
482 return addCar(shardDataTree, "altima");
485 private static DataTreeCandidate addCar(final ShardDataTree shardDataTree, final String name)
486 throws ExecutionException, InterruptedException {
487 return doTransaction(shardDataTree, snapshot -> {
488 snapshot.merge(CarsModel.BASE_PATH, CarsModel.emptyContainer());
489 snapshot.merge(CarsModel.CAR_LIST_PATH, CarsModel.newCarMapNode());
490 snapshot.write(CarsModel.newCarPath(name), CarsModel.newCarEntry(name, new BigInteger("100")));
494 private static DataTreeCandidate removeCar(final ShardDataTree shardDataTree)
495 throws ExecutionException, InterruptedException {
496 return doTransaction(shardDataTree, snapshot -> snapshot.delete(CarsModel.newCarPath("altima")));
500 private interface DataTreeOperation {
501 void execute(DataTreeModification snapshot);
504 private static DataTreeCandidate doTransaction(final ShardDataTree shardDataTree,
505 final DataTreeOperation operation) throws ExecutionException, InterruptedException {
506 final ReadWriteShardDataTreeTransaction transaction =
507 shardDataTree.newReadWriteTransaction(nextTransactionId());
508 final DataTreeModification snapshot = transaction.getSnapshot();
509 operation.execute(snapshot);
510 final ShardDataTreeCohort cohort = shardDataTree.finishTransaction(transaction);
512 immediateCanCommit(cohort);
513 immediatePreCommit(cohort);
514 final DataTreeCandidate candidate = cohort.getCandidate();
515 immediateCommit(cohort);
520 private static DataTreeCandidate applyCandidates(final ShardDataTree shardDataTree,
521 final List<DataTreeCandidate> candidates) throws ExecutionException, InterruptedException {
522 final ReadWriteShardDataTreeTransaction transaction =
523 shardDataTree.newReadWriteTransaction(nextTransactionId());
524 final DataTreeModification snapshot = transaction.getSnapshot();
525 for (final DataTreeCandidate candidateTip : candidates) {
526 DataTreeCandidates.applyToModification(snapshot, candidateTip);
528 final ShardDataTreeCohort cohort = shardDataTree.finishTransaction(transaction);
530 immediateCanCommit(cohort);
531 immediatePreCommit(cohort);
532 final DataTreeCandidate candidate = cohort.getCandidate();
533 immediateCommit(cohort);