*/
public class NormalizedNodePruner implements NormalizedNodeStreamWriter {
+ public static final URI BASE_NAMESPACE = URI.create("urn:ietf:params:xml:ns:netconf:base:1.0");
private final SimpleStack<NormalizedNodeBuilderWrapper> stack = new SimpleStack<>();
private NormalizedNode<?,?> normalizedNode;
private final Set<URI> validNamespaces;
public static Set<URI> namespaces(SchemaContext schemaContext){
Set<URI> namespaces = new HashSet<>(schemaContext.getModules().size());
+ namespaces.add(BASE_NAMESPACE);
for(org.opendaylight.yangtools.yang.model.api.Module module : schemaContext.getModules()){
namespaces.add(module.getNamespace());
}
+++ /dev/null
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-
-package org.opendaylight.controller.cluster.datastore;
-
-import com.google.common.base.Optional;
-import java.net.URI;
-import java.util.Set;
-import org.opendaylight.controller.cluster.datastore.utils.PruningDataTreeModification;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
-
-/**
- * The PruningShardDataTreeSnapshot returns a PruningDataTreeModification when a newModification is created
- */
-class PruningShardDataTreeSnapshot implements DataTreeSnapshot {
-
- private final DataTreeSnapshot dataTreeSnapshot;
- private final Set<URI> validNamespaces;
-
- public PruningShardDataTreeSnapshot(DataTreeSnapshot dataTreeSnapshot, Set<URI> validNamespaces) {
- this.dataTreeSnapshot = dataTreeSnapshot;
- this.validNamespaces = validNamespaces;
- }
-
- @Override
- public Optional<NormalizedNode<?, ?>> readNode(YangInstanceIdentifier yangInstanceIdentifier) {
- return this.dataTreeSnapshot.readNode(yangInstanceIdentifier);
- }
-
- @Override
- public DataTreeModification newModification() {
- return new PruningDataTreeModification(this.dataTreeSnapshot.newModification(), validNamespaces);
- }
-
-
-}
Dispatchers.DispatcherType.Transaction), self(), getContext(), shardMBean);
snapshotCohort = new ShardSnapshotCohort(transactionActorFactory, store, LOG, this.name);
+
+
}
private void setTransactionCommitTimeout() {
@Override
@Nonnull
protected RaftActorRecoveryCohort getRaftActorRecoveryCohort() {
- return new ShardRecoveryCoordinator(store, persistenceId(), LOG);
+ return new ShardRecoveryCoordinator(store, store.getSchemaContext(), persistenceId(), LOG);
}
@Override
protected void onRecoveryComplete() {
- store.recoveryDone();
//notify shard manager
getContext().parent().tell(new ActorInitialized(), getSelf());
*/
package org.opendaylight.controller.cluster.datastore;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
-import java.net.URI;
import java.util.AbstractMap.SimpleEntry;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Set;
import javax.annotation.concurrent.NotThreadSafe;
-import org.opendaylight.controller.cluster.datastore.node.utils.transformer.NormalizedNodePruner;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
private final ShardDataTreeChangePublisher treeChangePublisher = new ShardDataTreeChangePublisher();
private final ListenerTree listenerTree = ListenerTree.create();
private final TipProducingDataTree dataTree;
- private Set<URI> validNamespaces;
- private ShardDataTreeTransactionFactory transactionFactory = new RecoveryShardDataTreeTransactionFactory();
+ private SchemaContext schemaContext;
ShardDataTree(final SchemaContext schemaContext) {
dataTree = InMemoryDataTreeFactory.getInstance().create();
return dataTree;
}
+ SchemaContext getSchemaContext() {
+ return schemaContext;
+ }
+
void updateSchemaContext(final SchemaContext schemaContext) {
Preconditions.checkNotNull(schemaContext);
+ this.schemaContext = schemaContext;
dataTree.setSchemaContext(schemaContext);
- validNamespaces = NormalizedNodePruner.namespaces(schemaContext);
}
private ShardDataTreeTransactionChain ensureTransactionChain(final String chainId) {
ReadOnlyShardDataTreeTransaction newReadOnlyTransaction(final String txId, final String chainId) {
if (Strings.isNullOrEmpty(chainId)) {
- return transactionFactory.newReadOnlyTransaction(txId, chainId);
+ return new ReadOnlyShardDataTreeTransaction(txId, dataTree.takeSnapshot());
}
return ensureTransactionChain(chainId).newReadOnlyTransaction(txId);
ReadWriteShardDataTreeTransaction newReadWriteTransaction(final String txId, final String chainId) {
if (Strings.isNullOrEmpty(chainId)) {
- return transactionFactory.newReadWriteTransaction(txId, chainId);
+ return new ReadWriteShardDataTreeTransaction(ShardDataTree.this, txId, dataTree.takeSnapshot()
+ .newModification());
}
return ensureTransactionChain(chainId).newReadWriteTransaction(txId);
snapshot.ready();
return new SimpleShardDataTreeCohort(this, snapshot, transaction.getId());
}
-
- void recoveryDone(){
- transactionFactory = new RegularShardDataTreeTransactionFactory();
- }
-
- @VisibleForTesting
- ShardDataTreeTransactionFactory getTransactionFactory(){
- return transactionFactory;
- }
-
- @VisibleForTesting
- static interface ShardDataTreeTransactionFactory {
- ReadOnlyShardDataTreeTransaction newReadOnlyTransaction(final String txId, final String chainId);
-
- ReadWriteShardDataTreeTransaction newReadWriteTransaction(final String txId, final String chainId);
- }
-
- @VisibleForTesting
- class RecoveryShardDataTreeTransactionFactory implements ShardDataTreeTransactionFactory {
-
- @Override
- public ReadOnlyShardDataTreeTransaction newReadOnlyTransaction(String txId, String chainId) {
- return new ReadOnlyShardDataTreeTransaction(txId,
- new PruningShardDataTreeSnapshot(dataTree.takeSnapshot(), validNamespaces));
- }
-
- @Override
- public ReadWriteShardDataTreeTransaction newReadWriteTransaction(String txId, String chainId) {
- return new ReadWriteShardDataTreeTransaction(ShardDataTree.this, txId,
- new PruningShardDataTreeSnapshot(dataTree.takeSnapshot(), validNamespaces).newModification());
- }
- }
-
- @VisibleForTesting
- class RegularShardDataTreeTransactionFactory implements ShardDataTreeTransactionFactory {
-
- @Override
- public ReadOnlyShardDataTreeTransaction newReadOnlyTransaction(String txId, String chainId) {
- return new ReadOnlyShardDataTreeTransaction(txId, dataTree.takeSnapshot());
-
- }
-
- @Override
- public ReadWriteShardDataTreeTransaction newReadWriteTransaction(String txId, String chainId) {
- return new ReadWriteShardDataTreeTransaction(ShardDataTree.this, txId, dataTree.takeSnapshot()
- .newModification());
- }
- }
}
*/
package org.opendaylight.controller.cluster.datastore;
+import com.google.common.base.Preconditions;
import java.io.IOException;
+import java.net.URI;
+import java.util.Set;
import org.opendaylight.controller.cluster.datastore.modification.ModificationPayload;
import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification;
+import org.opendaylight.controller.cluster.datastore.node.utils.transformer.NormalizedNodePruner;
+import org.opendaylight.controller.cluster.datastore.utils.PruningDataTreeModification;
import org.opendaylight.controller.cluster.datastore.utils.SerializationUtils;
import org.opendaylight.controller.cluster.raft.RaftActorRecoveryCohort;
import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationByteStringPayload;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.slf4j.Logger;
/**
private final DataTree store;
private final String shardName;
private final Logger log;
- private DataTreeModification transaction;
+ private final Set<URI> validNamespaces;
+ private PruningDataTreeModification transaction;
private int size;
- ShardRecoveryCoordinator(ShardDataTree store, String shardName, Logger log) {
+ ShardRecoveryCoordinator(ShardDataTree store, SchemaContext schemaContext, String shardName, Logger log) {
this.store = store.getDataTree();
this.shardName = shardName;
this.log = log;
+ this.validNamespaces = NormalizedNodePruner.namespaces(schemaContext);
}
@Override
public void startLogRecoveryBatch(int maxBatchSize) {
log.debug("{}: starting log recovery batch with max size {}", shardName, maxBatchSize);
- transaction = store.takeSnapshot().newModification();
+ transaction = new PruningDataTreeModification(store.takeSnapshot().newModification(), validNamespaces);
size = 0;
}
@Override
public void appendRecoveredLogEntry(Payload payload) {
+ Preconditions.checkState(transaction != null, "call startLogRecovery before calling appendRecoveredLogEntry");
+
try {
if (payload instanceof DataTreeCandidatePayload) {
DataTreeCandidates.applyToModification(transaction, ((DataTreeCandidatePayload)payload).getCandidate());
}
}
- private void commitTransaction(DataTreeModification tx) throws DataValidationFailedException {
- tx.ready();
- store.validate(tx);
- store.commit(store.prepare(tx));
+ private void commitTransaction(PruningDataTreeModification tx) throws DataValidationFailedException {
+ DataTreeModification delegate = tx.getDelegate();
+ delegate.ready();
+ store.validate(delegate);
+ store.commit(store.prepare(delegate));
}
/**
*/
@Override
public void applyCurrentLogRecoveryBatch() {
+ Preconditions.checkState(transaction != null, "call startLogRecovery before calling applyCurrentLogRecoveryBatch");
+
log.debug("{}: Applying current log recovery batch with size {}", shardName, size);
try {
commitTransaction(transaction);
log.debug("{}: Applying recovered snapshot", shardName);
final NormalizedNode<?, ?> node = SerializationUtils.deserializeNormalizedNode(snapshotBytes);
- final DataTreeModification tx = store.takeSnapshot().newModification();
+ final PruningDataTreeModification tx = new PruningDataTreeModification(store.takeSnapshot().newModification(), validNamespaces);
tx.write(ROOT, node);
try {
commitTransaction(tx);
@Override
public void merge(YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
try {
- delegate.merge(yangInstanceIdentifier, normalizedNode);
+ if(YangInstanceIdentifier.EMPTY.equals(yangInstanceIdentifier)){
+ pruneAndMergeNode(yangInstanceIdentifier, normalizedNode);
+ } else {
+ delegate.merge(yangInstanceIdentifier, normalizedNode);
+ }
} catch (SchemaValidationFailedException e){
if(!isValidYangInstanceIdentifier(yangInstanceIdentifier)){
LOG.warn("Invalid node identifier {} ignoring merge", yangInstanceIdentifier);
return;
}
- LOG.warn("Node at path : {} was pruned during merge", yangInstanceIdentifier);
+ pruneAndMergeNode(yangInstanceIdentifier, normalizedNode);
+ }
+
+ }
- NormalizedNode<?,?> pruned = pruneNormalizedNode(normalizedNode);
+ private void pruneAndMergeNode(YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
+ LOG.warn("Node at path : {} was pruned during merge", yangInstanceIdentifier);
- if(pruned != null) {
- delegate.merge(yangInstanceIdentifier, pruned);
- }
- }
+ NormalizedNode<?,?> pruned = pruneNormalizedNode(normalizedNode);
+ if(pruned != null) {
+ delegate.merge(yangInstanceIdentifier, pruned);
+ }
}
@Override
public void write(YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
try {
- delegate.write(yangInstanceIdentifier, normalizedNode);
+ if(YangInstanceIdentifier.EMPTY.equals(yangInstanceIdentifier)){
+ pruneAndWriteNode(yangInstanceIdentifier, normalizedNode);
+ } else {
+ delegate.write(yangInstanceIdentifier, normalizedNode);
+ }
} catch (SchemaValidationFailedException e){
if(!isValidYangInstanceIdentifier(yangInstanceIdentifier)){
LOG.warn("Invalid node identifier {} ignoring write", yangInstanceIdentifier);
return;
}
- LOG.warn("Node at path : {} was pruned during write", yangInstanceIdentifier);
+ pruneAndWriteNode(yangInstanceIdentifier, normalizedNode);
+ }
+ }
+
+ private void pruneAndWriteNode(YangInstanceIdentifier yangInstanceIdentifier, NormalizedNode<?, ?> normalizedNode) {
+ LOG.warn("Node at path : {} was pruned during write", yangInstanceIdentifier);
- NormalizedNode<?,?> pruned = pruneNormalizedNode(normalizedNode);
+ NormalizedNode<?,?> pruned = pruneNormalizedNode(normalizedNode);
- if(pruned != null) {
- delegate.write(yangInstanceIdentifier, pruned);
- }
+ if(pruned != null) {
+ delegate.write(yangInstanceIdentifier, pruned);
}
}
+++ /dev/null
-package org.opendaylight.controller.cluster.datastore;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.verify;
-import java.net.URI;
-import java.util.Set;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.cluster.datastore.utils.PruningDataTreeModification;
-import org.opendaylight.controller.md.cluster.datastore.model.CarsModel;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
-
-public class PruningShardDataTreeSnapshotTest {
-
- @Mock
- DataTreeSnapshot dataTreeSnapshot;
-
- @Mock
- Set<URI> validNamespaces;
-
- @Before
- public void setUp(){
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void testNewModification(){
- PruningShardDataTreeSnapshot snapshot1
- = new PruningShardDataTreeSnapshot(dataTreeSnapshot, validNamespaces);
-
- DataTreeModification dataTreeModification1 = snapshot1.newModification();
-
- assertTrue(dataTreeModification1 instanceof PruningDataTreeModification);
- }
-
- @Test
- public void testReadNode(){
- PruningShardDataTreeSnapshot snapshot
- = new PruningShardDataTreeSnapshot(dataTreeSnapshot, validNamespaces);
-
- snapshot.readNode(CarsModel.BASE_PATH);
-
- verify(dataTreeSnapshot).readNode(CarsModel.BASE_PATH);
- }
-}
\ No newline at end of file
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
import com.google.common.base.Optional;
import java.util.concurrent.ExecutionException;
+import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.md.cluster.datastore.model.CarsModel;
import org.opendaylight.controller.md.cluster.datastore.model.PeopleModel;
public class ShardDataTreeTest {
- @Test
- public void testWrite() throws ExecutionException, InterruptedException {
+ SchemaContext fullSchema;
- SchemaContext schemaContext = SchemaContextHelper.full();
-
- modify(new ShardDataTree(schemaContext), false, true, true);
+ @Before
+ public void setUp(){
+ fullSchema = SchemaContextHelper.full();
}
@Test
- public void testWriteWithMissingSchema() throws ExecutionException, InterruptedException {
-
- SchemaContext schemaContext = SchemaContextHelper.select(SchemaContextHelper.ODL_DATASTORE_TEST_YANG, SchemaContextHelper.PEOPLE_YANG);
-
- modify(new ShardDataTree(schemaContext), false, false, true);
+ public void testWrite() throws ExecutionException, InterruptedException {
+ modify(new ShardDataTree(fullSchema), false, true, true);
}
@Test
public void testMerge() throws ExecutionException, InterruptedException {
-
- SchemaContext schemaContext = SchemaContextHelper.full();
-
- modify(new ShardDataTree(schemaContext), true, true, true);
+ modify(new ShardDataTree(fullSchema), true, true, true);
}
- @Test
- public void testMergeWithMissingSchema() throws ExecutionException, InterruptedException {
- SchemaContext schemaContext = SchemaContextHelper.select(SchemaContextHelper.ODL_DATASTORE_TEST_YANG, SchemaContextHelper.PEOPLE_YANG);
+ private void modify(ShardDataTree shardDataTree, boolean merge, boolean expectedCarsPresent, boolean expectedPeoplePresent) throws ExecutionException, InterruptedException {
- modify(new ShardDataTree(schemaContext), true, false, true);
- }
+ assertEquals(fullSchema, shardDataTree.getSchemaContext());
- private void modify(ShardDataTree shardDataTree, boolean merge, boolean expectedCarsPresent, boolean expectedPeoplePresent) throws ExecutionException, InterruptedException {
ReadWriteShardDataTreeTransaction transaction = shardDataTree.newReadWriteTransaction("txn-1", null);
DataTreeModification snapshot = transaction.getSnapshot();
}
- @Test(expected = IllegalArgumentException.class)
- public void testAfterRecoveryDone() throws ExecutionException, InterruptedException {
- SchemaContext schemaContext = SchemaContextHelper.select(SchemaContextHelper.ODL_DATASTORE_TEST_YANG, SchemaContextHelper.PEOPLE_YANG);
- ShardDataTree shardDataTree = new ShardDataTree(schemaContext);
- assertTrue("transaction factory must be the recovery transaction factory",
- shardDataTree.getTransactionFactory() instanceof ShardDataTree.RecoveryShardDataTreeTransactionFactory);
- shardDataTree.recoveryDone();
- assertTrue("transaction factory must be the regular transaction factory",
- shardDataTree.getTransactionFactory() instanceof ShardDataTree.RegularShardDataTreeTransactionFactory);
-
- modify(shardDataTree, true, false, true);
-
- }
-
}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.cluster.datastore;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import com.google.common.base.Optional;
+import java.io.IOException;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.modification.ModificationPayload;
+import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification;
+import org.opendaylight.controller.cluster.datastore.modification.WriteModification;
+import org.opendaylight.controller.cluster.datastore.utils.SerializationUtils;
+import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationByteStringPayload;
+import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationPayload;
+import org.opendaylight.controller.md.cluster.datastore.model.CarsModel;
+import org.opendaylight.controller.md.cluster.datastore.model.PeopleModel;
+import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateTip;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.SchemaValidationFailedException;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.LoggerFactory;
+
+public class ShardRecoveryCoordinatorTest {
+
+ private ShardDataTree peopleDataTree;
+ private SchemaContext peopleSchemaContext;
+ private SchemaContext carsSchemaContext;
+
+ @Before
+ public void setUp(){
+ peopleSchemaContext = SchemaContextHelper.select(SchemaContextHelper.PEOPLE_YANG);
+ carsSchemaContext = SchemaContextHelper.select(SchemaContextHelper.CARS_YANG);
+
+ peopleDataTree = new ShardDataTree(peopleSchemaContext);
+ }
+
+ @Test
+ public void testAppendRecoveredLogEntryDataTreeCandidatePayload(){
+ ShardRecoveryCoordinator coordinator = new ShardRecoveryCoordinator(peopleDataTree, peopleSchemaContext, "foobar", LoggerFactory.getLogger("foo"));
+ coordinator.startLogRecoveryBatch(10);
+ try {
+ coordinator.appendRecoveredLogEntry(DataTreeCandidatePayload.create(createCar()));
+ } catch(SchemaValidationFailedException e){
+ fail("SchemaValidationFailedException should not happen if pruning is done");
+ }
+
+ coordinator.applyCurrentLogRecoveryBatch();
+ }
+
+ @Test
+ public void testAppendRecoveredLogEntryModificationPayload() throws IOException {
+ ShardRecoveryCoordinator coordinator = new ShardRecoveryCoordinator(peopleDataTree, peopleSchemaContext, "foobar", LoggerFactory.getLogger("foo"));
+ coordinator.startLogRecoveryBatch(10);
+ try {
+ MutableCompositeModification modification = new MutableCompositeModification((short) 1);
+ modification.addModification(new WriteModification(CarsModel.BASE_PATH, CarsModel.create()));
+ coordinator.appendRecoveredLogEntry(new ModificationPayload(modification));
+ } catch(SchemaValidationFailedException e){
+ fail("SchemaValidationFailedException should not happen if pruning is done");
+ }
+ }
+
+ @Test
+ public void testAppendRecoveredLogEntryCompositeModificationPayload() throws IOException {
+ ShardRecoveryCoordinator coordinator = new ShardRecoveryCoordinator(peopleDataTree, peopleSchemaContext, "foobar", LoggerFactory.getLogger("foo"));
+ coordinator.startLogRecoveryBatch(10);
+ try {
+ MutableCompositeModification modification = new MutableCompositeModification((short) 1);
+ modification.addModification(new WriteModification(CarsModel.BASE_PATH, CarsModel.create()));
+ coordinator.appendRecoveredLogEntry(new CompositeModificationPayload(modification.toSerializable()));
+ } catch(SchemaValidationFailedException e){
+ fail("SchemaValidationFailedException should not happen if pruning is done");
+ }
+ }
+
+ @Test
+ public void testAppendRecoveredLogEntryCompositeModificationByteStringPayload() throws IOException {
+ ShardRecoveryCoordinator coordinator = new ShardRecoveryCoordinator(peopleDataTree, peopleSchemaContext, "foobar", LoggerFactory.getLogger("foo"));
+ coordinator.startLogRecoveryBatch(10);
+ try {
+ MutableCompositeModification modification = new MutableCompositeModification((short) 1);
+ modification.addModification(new WriteModification(CarsModel.BASE_PATH, CarsModel.create()));
+ coordinator.appendRecoveredLogEntry(new CompositeModificationByteStringPayload(modification.toSerializable()));
+ } catch(SchemaValidationFailedException e){
+ fail("SchemaValidationFailedException should not happen if pruning is done");
+ }
+
+ assertEquals(false, readCars(peopleDataTree).isPresent());
+ }
+
+ @Test
+ public void testApplyRecoverySnapshot(){
+ ShardRecoveryCoordinator coordinator = new ShardRecoveryCoordinator(peopleDataTree , peopleSchemaContext, "foobar", LoggerFactory.getLogger("foo"));
+ coordinator.startLogRecoveryBatch(10);
+
+ coordinator.applyRecoverySnapshot(createSnapshot());
+
+ assertEquals(false, readCars(peopleDataTree).isPresent());
+ assertEquals(true, readPeople(peopleDataTree).isPresent());
+ }
+
+
+ @Test
+ public void testApplyCurrentLogRecoveryBatch(){
+ ShardRecoveryCoordinator coordinator = new ShardRecoveryCoordinator(peopleDataTree, peopleSchemaContext, "foobar", LoggerFactory.getLogger("foo"));
+ coordinator.startLogRecoveryBatch(10);
+
+ try {
+ coordinator.applyCurrentLogRecoveryBatch();
+ } catch(IllegalArgumentException e){
+ fail("IllegalArgumentException should not happen - if the pruning modification delegate is passed");
+ }
+ }
+
+ private DataTreeCandidateTip createCar(){
+ TipProducingDataTree dataTree = InMemoryDataTreeFactory.getInstance().create();
+ dataTree.setSchemaContext(carsSchemaContext);
+
+ DataTreeSnapshot snapshot = dataTree.takeSnapshot();
+
+ DataTreeModification modification = snapshot.newModification();
+
+ modification.merge(CarsModel.BASE_PATH, CarsModel.create());
+
+ return dataTree.prepare(modification);
+ }
+
+ private Optional<NormalizedNode<?,?>> readCars(ShardDataTree shardDataTree){
+ TipProducingDataTree dataTree = shardDataTree.getDataTree();
+ dataTree.setSchemaContext(peopleSchemaContext);
+
+ DataTreeSnapshot snapshot = dataTree.takeSnapshot();
+
+ DataTreeModification modification = snapshot.newModification();
+
+ return modification.readNode(CarsModel.BASE_PATH);
+ }
+
+ private Optional<NormalizedNode<?,?>> readPeople(ShardDataTree shardDataTree){
+ TipProducingDataTree dataTree = shardDataTree.getDataTree();
+ dataTree.setSchemaContext(peopleSchemaContext);
+
+ DataTreeSnapshot snapshot = dataTree.takeSnapshot();
+
+ DataTreeModification modification = snapshot.newModification();
+
+ return modification.readNode(PeopleModel.BASE_PATH);
+ }
+
+
+
+ private byte[] createSnapshot(){
+ TipProducingDataTree dataTree = InMemoryDataTreeFactory.getInstance().create();
+ dataTree.setSchemaContext(SchemaContextHelper.select(SchemaContextHelper.CARS_YANG, SchemaContextHelper.PEOPLE_YANG));
+
+ DataTreeSnapshot snapshot = dataTree.takeSnapshot();
+
+ DataTreeModification modification = snapshot.newModification();
+
+ modification.merge(CarsModel.BASE_PATH, CarsModel.create());
+ modification.merge(PeopleModel.BASE_PATH, PeopleModel.create());
+
+ DataTreeCandidateTip prepare = dataTree.prepare(modification);
+
+ dataTree.commit(prepare);
+
+ snapshot = dataTree.takeSnapshot();
+
+ modification = snapshot.newModification();
+
+ Optional<NormalizedNode<?, ?>> optional = modification.readNode(YangInstanceIdentifier.EMPTY);
+
+ byte[] bytes = SerializationUtils.serializeNormalizedNode(optional.get());
+
+ return bytes;
+
+
+ }
+}
\ No newline at end of file