blob: 23095f46a84e4ead0f47c491228d9804f794dd7c [file] [log] [blame]
Aaron Kruglikov92511f22015-10-12 14:39:04 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Aaron Kruglikov92511f22015-10-12 14:39:04 -07003 *
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
17package org.onosproject.persistence.impl;
18
19import com.google.common.collect.Maps;
20import com.google.common.collect.Sets;
21import org.mapdb.DB;
22import org.mapdb.Hasher;
23import org.onosproject.store.service.Serializer;
24
25import java.util.Collection;
26import java.util.Map;
27import java.util.Set;
28
29import static com.google.common.base.Preconditions.checkNotNull;
30
31
32/**
33 * A map implementation that stores and receives all data from a serialized internal map.
34 */
35public class PersistentMap<K, V> implements Map<K, V> {
36
37 private final Serializer serializer;
38
39 private final org.mapdb.DB database;
40
41 private final Map<byte[], byte[]> items;
42
43 private final String name;
44
45 public PersistentMap(Serializer serializer, DB database, String name) {
46 this.serializer = checkNotNull(serializer);
47 this.database = checkNotNull(database);
48 this.name = checkNotNull(name);
49
50 items = database
51 .createHashMap(name)
52 .keySerializer(org.mapdb.Serializer.BYTE_ARRAY)
53 .valueSerializer(org.mapdb.Serializer.BYTE_ARRAY)
54 .hasher(Hasher.BYTE_ARRAY)
55 .makeOrGet();
56 }
57
58 /**
59 * Reads this set in deserialized form into the provided map.
60 *
61 * @param items the map to be populated
62 */
63 public void readInto(Map<K, V> items) {
64 this.items.forEach((keyBytes, valueBytes) ->
65 items.put(serializer.decode(keyBytes),
66 serializer.decode(valueBytes)));
67 }
68
69 @Override
70 public V remove(Object key) {
71 checkNotNull(key, "Key can not be null.");
72 V removed = get(key);
73 items.remove(serializer.encode(key));
74 return removed;
75 }
76
77 @Override
78 public int size() {
79 return items.size();
80 }
81
82 @Override
83 public boolean isEmpty() {
84 return items.isEmpty();
85 }
86
87 @Override
88 public boolean containsKey(Object key) {
89 checkNotNull(key, "Key cannot be null.");
90 return items.containsKey(serializer.encode(key));
91 }
92
93 @Override
94 public boolean containsValue(Object value) {
95 checkNotNull(value, "Value cannot be null.");
96 byte[] serialized = serializer.encode(value);
97 for (byte[] compareValue : items.values()) {
98 boolean same = true;
99 if (compareValue == null) {
100 same = false;
101 } else if (compareValue.length != serialized.length) {
102 same = false;
103 } else {
104 for (int i = 0; i < serialized.length; i++) {
105 if (serialized[i] != compareValue[i]) {
106 same = false;
107 break;
108 }
109 }
110 }
111 if (same) {
112 return true;
113 }
114 }
115 return false;
116 }
117
118 @Override
119 public V get(Object key) {
120 checkNotNull(key, "Key cannot be null.");
Thomas Vachuska764a7132016-11-22 17:07:22 -0800121 byte[] bytes = items.get(serializer.encode(key));
122 return bytes == null ? null : serializer.decode(bytes);
Aaron Kruglikov92511f22015-10-12 14:39:04 -0700123 }
124
125 @Override
126 public V put(K key, V value) {
127 checkNotNull(key, "Key cannot be null.");
128 checkNotNull(value, "Value cannot be null.");
129 byte[] prevVal = items.put(serializer.encode(key), serializer.encode(value));
130 if (prevVal == null) {
131 return null;
132 }
133 return serializer.decode(prevVal);
134 }
135
136 @Override
137 public void putAll(Map<? extends K, ? extends V> m) {
138 checkNotNull(m, "The passed in map cannot be null.");
139 m.forEach((k, v) -> items.put(serializer.encode(k), serializer.encode(v)));
140 }
141
142 @Override
143 public void clear() {
144 items.clear();
145 }
146
147 @Override
148 public Set<K> keySet() {
149 Set<K> keys = Sets.newHashSet();
150 items.keySet().forEach(k -> keys.add(serializer.decode(k)));
151 return keys;
152 }
153
154 @Override
155 public Collection<V> values() {
156 Collection<V> values = Sets.newHashSet();
157 items.values().forEach(v -> values.add(serializer.decode(v)));
158 return values;
159 }
160
161 @Override
162 public Set<Entry<K, V>> entrySet() {
163 Set<Entry<K, V>> entries = Sets.newHashSet();
164 items.entrySet().
165 forEach(e -> entries.add(Maps.immutableEntry(serializer.decode(e.getKey()),
166 serializer.decode(e.getValue()))));
167 return entries;
168 }
169
170 @Override
171 public boolean equals(Object map) {
172 //This is not threadsafe and on larger maps incurs a significant processing cost
173 if (!(map instanceof Map)) {
174 return false;
175 }
176 Map asMap = (Map) map;
177 if (this.size() != asMap.size()) {
178 return false;
179 }
180 for (Entry entry : this.entrySet()) {
181 Object key = entry.getKey();
182 if (!asMap.containsKey(key) || !asMap.get(key).equals(entry.getValue())) {
183 return false;
184 }
185 }
186 return true;
187 }
188
189 @Override
190 public int hashCode() {
191 return super.hashCode();
192 }
193}