e82ddb6d7624b41c1966df24a9d6a7093bca457f
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / persisted / ShardDataTreeSnapshot.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.datastore.persisted;
9
10 import com.google.common.annotations.Beta;
11 import java.io.ByteArrayInputStream;
12 import java.io.DataInputStream;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.io.OutputStream;
16 import java.util.Optional;
17 import org.opendaylight.controller.cluster.datastore.node.utils.stream.SerializationUtils;
18 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 /**
23  * Abstract base class for snapshots of the ShardDataTree.
24  *
25  * @author Robert Varga
26  */
27 @Beta
28 public abstract class ShardDataTreeSnapshot {
29     private static final Logger LOG = LoggerFactory.getLogger(ShardDataTreeSnapshot.class);
30
31     ShardDataTreeSnapshot() {
32         // Hidden to prevent subclassing from outside of this package
33     }
34
35     @Deprecated
36     public static ShardDataTreeSnapshot deserialize(final byte[] bytes) throws IOException {
37         /**
38          * Unfortunately versions prior to Boron did not include any way to evolve the snapshot format and contained
39          * only the raw data stored in the datastore. Furthermore utilities involved do not check if the array is
40          * completely consumed, which has a nasty side-effect when coupled with the fact that PayloadVersion writes
41          * a short value.
42          *
43          * Since our versions fit into a single byte, we end up writing the 0 as the first byte, which would be
44          * interpreted as 'not present' by the old snapshot format, which uses writeBoolean/readBoolean. A further
45          * complication is that readBoolean interprets any non-zero value as true, hence we cannot use a wild value
46          * to cause it to fail.
47          */
48         if (isLegacyStream(bytes)) {
49             return deserializeLegacy(bytes);
50         }
51
52         try {
53             try (InputStream is = new ByteArrayInputStream(bytes)) {
54                 return deserialize(is);
55             }
56         } catch (IOException e) {
57             LOG.debug("Failed to deserialize versioned stream, attempting pre-Lithium ProtoBuf", e);
58             return deserializeLegacy(bytes);
59         }
60     }
61
62     public static ShardDataTreeSnapshot deserialize(final InputStream is) throws IOException {
63         try (DataInputStream dis = new DataInputStream(is)) {
64             final ShardDataTreeSnapshot ret = AbstractVersionedShardDataTreeSnapshot.deserialize(dis);
65
66             // Make sure we consume all bytes, otherwise something went very wrong
67             final int bytesLeft = dis.available();
68             if (bytesLeft != 0) {
69                 throw new IOException("Deserialization left " + bytesLeft + " in the buffer");
70             }
71
72
73             return ret;
74         }
75     }
76
77     /**
78      * Get the root data node contained in this snapshot.
79      *
80      * @return An optional root node.
81      */
82     public abstract Optional<NormalizedNode<?, ?>> getRootNode();
83
84     public abstract void serialize(OutputStream os) throws IOException;
85
86     @Deprecated
87     private static boolean isLegacyStream(final byte[] bytes) {
88         if (bytes.length < 2) {
89             // Versioned streams have at least two bytes
90             return true;
91         }
92
93         /*
94          * The stream could potentially be a versioned stream. Here we rely on the signature marker available
95          * in org.opendaylight.controller.cluster.datastore.node.utils.stream.TokenTypes.
96          *
97          * For an old stream to be this long, the first byte has to be non-zero and the second byte has to be 0xAB.
98          *
99          * For a versioned stream, that translates to at least version 427 -- giving us at least 421 further versions
100          * before this check breaks.
101          */
102         return bytes[0] != 0 && bytes[1] == (byte)0xAB;
103     }
104
105     @Deprecated
106     private static ShardDataTreeSnapshot deserializeLegacy(final byte[] bytes) {
107         return new PreBoronShardDataTreeSnapshot(SerializationUtils.deserializeNormalizedNode(bytes));
108     }
109 }
110

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.