e62a2d5cb4378b36a40318d2e3e13cae5f4bdcd6
[onosfw.git] /
1 /*
2  * Copyright 2015 Open Networking Laboratory
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onosproject.store.ecmap;
18
19 import org.mapdb.DB;
20 import org.mapdb.DBMaker;
21 import org.mapdb.Hasher;
22 import org.mapdb.Serializer;
23 import org.onosproject.store.serializers.KryoSerializer;
24
25 import java.io.File;
26 import java.util.Map;
27 import java.util.concurrent.ExecutorService;
28
29 import static com.google.common.base.Preconditions.checkNotNull;
30
31 /**
32  * MapDB based implementation of a persistent store.
33  */
34 class MapDbPersistentStore<K, V> implements PersistentStore<K, V> {
35
36     private final ExecutorService executor;
37     private final KryoSerializer serializer;
38
39     private final DB database;
40
41     private final Map<byte[], byte[]> items;
42
43     /**
44      * Creates a new MapDB based persistent store.
45      *
46      * @param filename filename of the database on disk
47      * @param executor executor to use for tasks that write to the disk
48      * @param serializer serializer for keys and values
49      */
50     MapDbPersistentStore(String filename, ExecutorService executor,
51                          KryoSerializer serializer) {
52         this.executor = checkNotNull(executor);
53         this.serializer = checkNotNull(serializer);
54
55         File databaseFile = new File(filename);
56
57         database = DBMaker.newFileDB(databaseFile).make();
58
59         items = database.createHashMap("items")
60                 .keySerializer(Serializer.BYTE_ARRAY)
61                 .valueSerializer(Serializer.BYTE_ARRAY)
62                 .hasher(Hasher.BYTE_ARRAY)
63                 .makeOrGet();
64     }
65
66     @Override
67     public void readInto(Map<K, MapValue<V>> items) {
68         this.items.forEach((keyBytes, valueBytes) ->
69                               items.put(serializer.decode(keyBytes),
70                                         serializer.decode(valueBytes)));
71     }
72
73     @Override
74     public void update(K key, MapValue<V> value) {
75         executor.submit(() -> updateInternal(key, value));
76     }
77
78     @Override
79     public void remove(K key) {
80         executor.submit(() -> removeInternal(key));
81     }
82
83     private void updateInternal(K key, MapValue<V> newValue) {
84         byte[] keyBytes = serializer.encode(key);
85
86         items.compute(keyBytes, (k, existingBytes) -> {
87             MapValue<V> existing = existingBytes == null ? null :
88                                       serializer.decode(existingBytes);
89             if (existing == null || newValue.isNewerThan(existing)) {
90                 return serializer.encode(newValue);
91             } else {
92                 return existingBytes;
93             }
94         });
95         database.commit();
96     }
97
98     private void removeInternal(K key) {
99         byte[] keyBytes = serializer.encode(key);
100         items.remove(keyBytes);
101         database.commit();
102     }
103 }