blob: b771b8037129b13b8b3d7c3d95ea2348677747b1 [file] [log] [blame]
Yuta HIGUCHIa8016e72014-11-18 20:19:46 -08001/*
2 * Copyright 2014 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
17package org.onlab.onos.store.service.impl;
18
19import static com.google.common.base.Preconditions.checkNotNull;
20import static com.google.common.base.Predicates.notNull;
21
22import java.util.Map;
23
24import org.onlab.onos.store.serializers.StoreSerializer;
25import org.onlab.onos.store.service.DatabaseAdminService;
26import org.onlab.onos.store.service.DatabaseService;
27import org.onlab.onos.store.service.VersionedValue;
28
29import com.google.common.base.Function;
30import com.google.common.cache.CacheBuilder;
31import com.google.common.cache.CacheLoader;
32import com.google.common.cache.LoadingCache;
33import com.google.common.collect.FluentIterable;
34
35/**
36 * Map like interface wrapper around DatabaseService.
37 *
38 * @param <K> Key type of the map.
39 * The type must have toString(), which can uniquely identify the entry.
40 * @param <V> Value type
41 */
42public class CMap<K, V> {
43
44 @SuppressWarnings("unused")
45 private final DatabaseAdminService dbAdminService;
46
47 private final DatabaseService dbService;
48
49 private final String tableName;
50 private final StoreSerializer serializer;
51
52 private final LoadingCache<K, String> keyCache;
53
54 /**
55 * Creates a CMap instance.
56 * It will create the table if necessary.
57 *
58 * @param dbAdminService
59 * @param dbService
60 * @param tableName table which this Map corresponds to
61 * @param serializer Value serializer
62 */
63 public CMap(DatabaseAdminService dbAdminService,
64 DatabaseService dbService,
65 String tableName,
66 StoreSerializer serializer) {
67
68 this.dbAdminService = checkNotNull(dbAdminService);
69 this.dbService = checkNotNull(dbService);
70 this.tableName = checkNotNull(tableName);
71 this.serializer = checkNotNull(serializer);
72
73 if (!dbAdminService.listTables().contains(tableName)) {
74 dbAdminService.createTable(tableName);
75 }
76
77 keyCache = CacheBuilder.newBuilder()
78 .softValues()
79 .build(new CacheLoader<K, String>() {
80
81 @Override
82 public String load(K key) {
83 return key.toString();
84 }
85 });
86 }
87
88 protected String sK(K key) {
89 return keyCache.getUnchecked(key);
90 }
91
92 protected byte[] sV(V val) {
93 return serializer.encode(val);
94 }
95
96 protected V dV(byte[] valBytes) {
97 return serializer.decode(valBytes);
98 }
99
100 /**
101 * Puts an entry to the map, if not already present.
102 *
103 * @param key the key of the value to put if absent
104 * @param value the value to be put if previous value does not exist
105 * @return true if put was successful.
106 */
107 public boolean putIfAbsent(K key, V value) {
108 return dbService.putIfAbsent(tableName, sK(key), sV(value));
109 }
110
111 /**
112 * Removes an entry associated to specified key.
113 *
114 * @param key key of the value to remove
115 * @return previous value in the map for the key
116 */
117 public V remove(K key) {
118 VersionedValue removed = dbService.remove(tableName, sK(key));
119 if (removed == null) {
120 return null;
121 }
122 return dV(removed.value());
123 }
124
125 /**
126 * Returns the size of the map.
127 *
128 * @return size of the map
129 */
130 public long size() {
131 // TODO this is very inefficient
132 return dbService.getAll(tableName).size();
133 }
134
135 /**
136 * Returns all the values contained in the map.
137 *
138 * @return values containd in this map
139 */
140 public Iterable<V> values() {
141 Map<String, VersionedValue> all = dbService.getAll(tableName);
142 return FluentIterable.from(all.values())
143 .transform(new Function<VersionedValue, V>() {
144
145 @Override
146 public V apply(VersionedValue input) {
147 if (input == null) {
148 return null;
149 }
150 return dV(input.value());
151 }
152 })
153 .filter(notNull());
154 }
155
156 /**
157 * Gets the value in the map.
158 *
159 * @param key to get from the map
160 * @return value associated with the key, null if not such entry
161 */
162 public V get(K key) {
163 VersionedValue vv = dbService.get(tableName, sK(key));
164 if (vv == null) {
165 return null;
166 }
167 return dV(vv.value());
168 }
169
170 /**
171 * Replaces the value in the map if the value matches the expected.
172 *
173 * @param key of the entry to replace
174 * @param oldVal value expected to be in the map
175 * @param newVal value to be replaced with
176 * @return true if successfully replaced
177 */
178 public boolean replace(K key, V oldVal, V newVal) {
179 return dbService.putIfValueMatches(tableName, sK(key), sV(oldVal), sV(newVal));
180 }
181
182 /**
183 * Puts a value int the map.
184 *
185 * @param key key with which the specified value is to be associated
186 * @param value value to be associated with the specified key
187 * @return previous value or null if not such entry
188 */
189 public V put(K key, V value) {
190 VersionedValue vv = dbService.put(tableName, sK(key), sV(value));
191 if (vv == null) {
192 return null;
193 }
194 return dV(vv.value());
195 }
196}