Aaron Kruglikov
Committed by Gerrit Code Review

Creating persistence service.

Change-Id: Ib78b4001a24c71b4096e5a2a446dbd5009aa1090
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
19 <command> 19 <command>
20 <action class="org.onosproject.cli.SummaryCommand"/> 20 <action class="org.onosproject.cli.SummaryCommand"/>
21 </command> 21 </command>
22 -
23 <command> 22 <command>
24 <action class="org.onosproject.cli.security.ReviewCommand"/> 23 <action class="org.onosproject.cli.security.ReviewCommand"/>
25 <completers> 24 <completers>
......
...@@ -63,6 +63,11 @@ ...@@ -63,6 +63,11 @@
63 <artifactId>onlab-rest</artifactId> 63 <artifactId>onlab-rest</artifactId>
64 <version>${project.version}</version> 64 <version>${project.version}</version>
65 </dependency> 65 </dependency>
66 + <dependency>
67 + <groupId>org.mapdb</groupId>
68 + <artifactId>mapdb</artifactId>
69 + <version>1.0.8</version>
70 + </dependency>
66 </dependencies> 71 </dependencies>
67 72
68 </project> 73 </project>
......
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.persistence;
18 +
19 +/**
20 + * Service that allows for the creation of local disk backed map for instance specific values that persist across
21 + * restarts. Empty maps and sets are deleted on shutdown.
22 + */
23 +public interface PersistenceService {
24 + /**
25 + * A builder for the creation of local persistent maps backed by disk.
26 + *
27 + * @param <K> the type of keys in this map
28 + * @param <V> the type of values in this map
29 + * @return a persistent map builder
30 + */
31 + <K, V> PersistentMapBuilder<K, V> persistentMapBuilder();
32 +
33 + /**
34 + * A builder for the creation of local persistent sets backed by disk.
35 + *
36 + * @param <E> the type of the elements
37 + * @return a persistent set builder
38 + */
39 + <E> PersistentSetBuilder<E> persistentSetBuilder();
40 +}
...\ No newline at end of file ...\ No newline at end of file
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.persistence;
18 +
19 +
20 +import org.onosproject.store.service.Serializer;
21 +
22 +import java.util.Map;
23 +
24 +/**
25 + * The interface for a persistent map builder for use with mapDB.
26 + */
27 +public interface PersistentMapBuilder<K, V> {
28 +
29 + /**
30 + * Sets the name of this map.
31 + * @param name the string name of this map
32 + * @return a persistent map builder with the name option now set
33 + */
34 + PersistentMapBuilder<K, V> withName(String name);
35 +
36 + /**
37 + * Sets the key serializer to be used to serialize this map, this is a required parameter.
38 + * @param serializer the serializer to be used for keys
39 + * @return a persistent map builder with the key serializer set
40 + */
41 + PersistentMapBuilder<K, V> withSerializer(Serializer serializer);
42 +
43 + /**
44 + * Validates the map settings and then builds this map in the database. Throws an exception if invalid settings
45 + * are found.
46 + * @return The map that was created
47 + */
48 + Map<K, V> build();
49 +}
...\ No newline at end of file ...\ No newline at end of file
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.persistence;
18 +
19 +import org.onosproject.store.service.Serializer;
20 +
21 +import java.util.Set;
22 +
23 +/**
24 + * The default interface for the persistent set builder for use with mapDB.
25 + */
26 +public interface PersistentSetBuilder<E> {
27 +
28 + /**
29 + * Sets the name of this set.
30 + * @param name the string name of this set
31 + * @return a persistent set builder with the name option now set
32 + */
33 + PersistentSetBuilder<E> withName(String name);
34 +
35 + /**
36 + * Sets the serializer to be used to serialize this set, this is a required parameter.
37 + * @param serializer the serializer to be used
38 + * @return a persistent set builder with the serializer set
39 + */
40 + PersistentSetBuilder<E> withSerializer(Serializer serializer);
41 +
42 + /**
43 + * Validates the set settings and then builds this map in the database. Throws an exception if invalid settings
44 + * are found.
45 + * @return The set that was created
46 + */
47 + Set<E> build();
48 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
71 <dependency> 71 <dependency>
72 <groupId>org.mapdb</groupId> 72 <groupId>org.mapdb</groupId>
73 <artifactId>mapdb</artifactId> 73 <artifactId>mapdb</artifactId>
74 - <version>1.0.7</version> 74 + <version>1.0.8</version>
75 </dependency> 75 </dependency>
76 76
77 <dependency> 77 <dependency>
......
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<project xmlns="http://maven.apache.org/POM/4.0.0"
18 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
20 + <modelVersion>4.0.0</modelVersion>
21 + <repositories>
22 + <repository>
23 + <id>repository.springsource.com.release</id>
24 + <name>SpringSource OBR - Release</name>
25 + <url>http://repository.springsource.com/maven/bundles/release</url>
26 + </repository>
27 + <repository>
28 + <id>repository.springsource.com.external</id>
29 + <name>SpringSource OBR - External</name>
30 + <url>http://repository.springsource.com/maven/bundles/external</url>
31 + </repository>
32 + </repositories>
33 +
34 + <parent>
35 + <groupId>org.onosproject</groupId>
36 + <artifactId>onos-core-store</artifactId>
37 + <version>1.4.0-SNAPSHOT</version>
38 + <relativePath>../pom.xml</relativePath>
39 + </parent>
40 +
41 + <artifactId>onos-core-persistence</artifactId>
42 + <packaging>bundle</packaging>
43 +
44 + <description>ONOS Core persistent local store subsystem</description>
45 +
46 +
47 +
48 + <dependencies>
49 + <dependency>
50 + <groupId>org.onosproject</groupId>
51 + <artifactId>onos-api</artifactId>
52 + </dependency>
53 + <dependency>
54 + <groupId>org.mapdb</groupId>
55 + <artifactId>mapdb</artifactId>
56 + <version>1.0.8</version>
57 + </dependency>
58 + <dependency>
59 + <groupId>org.junit</groupId>
60 + <artifactId>com.springsource.org.junit</artifactId>
61 + <version>4.11.0</version>
62 + </dependency>
63 + </dependencies>
64 +
65 +</project>
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.persistence.impl;
18 +
19 +import org.mapdb.DB;
20 +import org.onosproject.persistence.PersistentMapBuilder;
21 +import org.onosproject.store.service.Serializer;
22 +
23 +import java.util.Map;
24 +
25 +import static com.google.common.base.Preconditions.checkArgument;
26 +import static com.google.common.base.Preconditions.checkNotNull;
27 +
28 +/**
29 + * Default builder for persistent maps stored in the mapDB local database via the persistence service.
30 + */
31 +public class DefaultPersistentMapBuilder<K, V> implements PersistentMapBuilder<K, V> {
32 +
33 + private final DB localDB;
34 +
35 + private String name = null;
36 +
37 + private Serializer serializer = null;
38 +
39 +
40 + public DefaultPersistentMapBuilder(DB localDB) {
41 + checkNotNull(localDB, "The local database cannot be null.");
42 + this.localDB = localDB;
43 + }
44 +
45 + public PersistentMapBuilder<K, V> withName(String name) {
46 + this.name = PersistenceManager.MAP_PREFIX + checkNotNull(name);
47 + return this;
48 + }
49 +
50 + public PersistentMapBuilder<K, V> withSerializer(Serializer serializer) {
51 + checkArgument(this.serializer == null);
52 + checkNotNull(serializer);
53 + this.serializer = serializer;
54 + return this;
55 + }
56 +
57 + public Map<K, V> build() {
58 + checkNotNull(name, "The name must be assigned.");
59 + checkNotNull(serializer, "The key serializer must be assigned.");
60 +
61 + return new PersistentMap<K, V>(serializer, localDB, name);
62 + }
63 +}
...\ No newline at end of file ...\ No newline at end of file
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.persistence.impl;
18 +
19 +import org.mapdb.DB;
20 +import org.onosproject.persistence.PersistentSetBuilder;
21 +import org.onosproject.store.service.Serializer;
22 +
23 +import static com.google.common.base.Preconditions.checkArgument;
24 +import static com.google.common.base.Preconditions.checkNotNull;
25 +
26 +/**
27 + * Default builder for persistent sets stored in the mapDB local database via the persistence service..
28 + */
29 +public class DefaultPersistentSetBuilder<E> implements PersistentSetBuilder<E> {
30 +
31 + private final DB localDB;
32 +
33 + private String name = null;
34 +
35 + private Serializer serializer = null;
36 +
37 + public DefaultPersistentSetBuilder(DB localDB) {
38 + this.localDB = checkNotNull(localDB, "The local database cannot be null.");
39 + }
40 +
41 + public PersistentSetBuilder<E> withName(String name) {
42 + this.name = PersistenceManager.SET_PREFIX + checkNotNull(name);
43 + return this;
44 + }
45 +
46 + public PersistentSetBuilder<E> withSerializer(Serializer serializer) {
47 + checkArgument(this.serializer == null);
48 + checkNotNull(serializer);
49 + this.serializer = serializer;
50 + return this;
51 + }
52 +
53 + public PersistentSet<E> build() {
54 + checkNotNull(name, "The name must be assigned.");
55 + checkNotNull(serializer, "The serializer must be assigned.");
56 +
57 + return new PersistentSet<E>(serializer, localDB, name);
58 + }
59 +}
...\ No newline at end of file ...\ No newline at end of file
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.persistence.impl;
18 +
19 +/**
20 + * An exception defined for failures of the local persistent store system.
21 + */
22 +
23 +/**
24 + * Throws an exception with the specified message.
25 + */
26 +public class PersistenceException extends RuntimeException {
27 + public PersistenceException(String s) {
28 + super(s);
29 + }
30 +}
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.persistence.impl;
18 +
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Service;
23 +import org.mapdb.DB;
24 +import org.mapdb.DBMaker;
25 +import org.onosproject.persistence.PersistenceService;
26 +import org.onosproject.persistence.PersistentMapBuilder;
27 +import org.onosproject.persistence.PersistentSetBuilder;
28 +import org.slf4j.Logger;
29 +
30 +import java.io.IOException;
31 +import java.nio.file.Files;
32 +import java.nio.file.Path;
33 +import java.nio.file.Paths;
34 +import java.util.Map;
35 +import java.util.Set;
36 +import java.util.Timer;
37 +import java.util.TimerTask;
38 +
39 +import static org.slf4j.LoggerFactory.getLogger;
40 +
41 +/**
42 + * Service that maintains local disk backed maps and sets. This implementation automatically deletes empty structures
43 + * on shutdown.
44 + */
45 +@Component(immediate = true)
46 +@Service
47 +public class PersistenceManager implements PersistenceService {
48 +
49 + private static final String DATABASE_PATH = "../data/localDB";
50 +
51 + private static final String ENCLOSING_FOLDER = "../data";
52 +
53 + static final String MAP_PREFIX = "map:";
54 +
55 + static final String SET_PREFIX = "set:";
56 +
57 + private final Logger log = getLogger(getClass());
58 +
59 + private DB localDB = null;
60 +
61 + private static final int FLUSH_FREQUENCY_MILLIS = 3000;
62 +
63 + private final Timer timer = new Timer();
64 +
65 + private final CommitTask commitTask = new CommitTask();
66 +
67 + @Activate
68 + public void activate() {
69 + Path dbPath = Paths.get(DATABASE_PATH);
70 + Path dbFolderPath = Paths.get(ENCLOSING_FOLDER);
71 + //Make sure the directory exists, if it does not, make it.
72 + if (!dbFolderPath.toFile().isDirectory()) {
73 + log.info("The specified folder location for the database did not exist and will be created.");
74 + try {
75 + Files.createDirectories(dbFolderPath);
76 + } catch (IOException e) {
77 + log.error("Could not create the required folder for the database.");
78 + throw new PersistenceException("Database folder could not be created.");
79 + }
80 + }
81 + //Notify if the database file does not exist.
82 + boolean dbFound = Files.exists(dbPath);
83 + if (!dbFound) {
84 + log.info("The database file could not be located, a new database will be constructed.");
85 +
86 + } else {
87 + log.info("A previous database file has been found.");
88 + }
89 + localDB = DBMaker.newFileDB(dbPath.toFile())
90 + .asyncWriteEnable()
91 + .closeOnJvmShutdown()
92 + .make();
93 + timer.schedule(commitTask, FLUSH_FREQUENCY_MILLIS, FLUSH_FREQUENCY_MILLIS);
94 + log.info("Started");
95 + }
96 +
97 + @Deactivate
98 + public void deactivate() {
99 + for (Map.Entry<String, Object> entry : localDB.getAll().entrySet()) {
100 + String key = entry.getKey();
101 + Object value = entry.getValue();
102 + //This is a map implementation to be handled as such
103 + if (value instanceof Map) {
104 + Map asMap = (Map) value;
105 + if (asMap.isEmpty()) {
106 + //the map is empty and may be deleted
107 + localDB.delete(key);
108 + }
109 + //This is a set implementation and can be handled as such
110 + } else if (value instanceof Set) {
111 + Set asSet = (Set) value;
112 + if (asSet.isEmpty()) {
113 + //the set is empty and may be deleted
114 + localDB.delete(key);
115 + }
116 + }
117 + }
118 + localDB.commit();
119 + localDB.close();
120 + log.info("Stopped");
121 + }
122 +
123 + public <K, V> PersistentMapBuilder<K, V> persistentMapBuilder() {
124 + return new DefaultPersistentMapBuilder<>(localDB);
125 + }
126 +
127 + public <E> PersistentSetBuilder<E> persistentSetBuilder() {
128 + return new DefaultPersistentSetBuilder<>(localDB);
129 + }
130 +
131 + private class CommitTask extends TimerTask {
132 +
133 + @Override
134 + public void run() {
135 + localDB.commit();
136 + }
137 + }
138 +}
...\ No newline at end of file ...\ No newline at end of file
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.persistence.impl;
18 +
19 +import com.google.common.collect.Maps;
20 +import com.google.common.collect.Sets;
21 +import org.mapdb.DB;
22 +import org.mapdb.Hasher;
23 +import org.onosproject.store.service.Serializer;
24 +
25 +import java.util.Collection;
26 +import java.util.Map;
27 +import java.util.Set;
28 +
29 +import 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 + */
35 +public 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.");
121 + return serializer.decode(items.get(serializer.encode(key)));
122 + }
123 +
124 + @Override
125 + public V put(K key, V value) {
126 + checkNotNull(key, "Key cannot be null.");
127 + checkNotNull(value, "Value cannot be null.");
128 + byte[] prevVal = items.put(serializer.encode(key), serializer.encode(value));
129 + if (prevVal == null) {
130 + return null;
131 + }
132 + return serializer.decode(prevVal);
133 + }
134 +
135 + @Override
136 + public void putAll(Map<? extends K, ? extends V> m) {
137 + checkNotNull(m, "The passed in map cannot be null.");
138 + m.forEach((k, v) -> items.put(serializer.encode(k), serializer.encode(v)));
139 + }
140 +
141 + @Override
142 + public void clear() {
143 + items.clear();
144 + }
145 +
146 + @Override
147 + public Set<K> keySet() {
148 + Set<K> keys = Sets.newHashSet();
149 + items.keySet().forEach(k -> keys.add(serializer.decode(k)));
150 + return keys;
151 + }
152 +
153 + @Override
154 + public Collection<V> values() {
155 + Collection<V> values = Sets.newHashSet();
156 + items.values().forEach(v -> values.add(serializer.decode(v)));
157 + return values;
158 + }
159 +
160 + @Override
161 + public Set<Entry<K, V>> entrySet() {
162 + Set<Entry<K, V>> entries = Sets.newHashSet();
163 + items.entrySet().
164 + forEach(e -> entries.add(Maps.immutableEntry(serializer.decode(e.getKey()),
165 + serializer.decode(e.getValue()))));
166 + return entries;
167 + }
168 +
169 + @Override
170 + public boolean equals(Object map) {
171 + //This is not threadsafe and on larger maps incurs a significant processing cost
172 + if (!(map instanceof Map)) {
173 + return false;
174 + }
175 + Map asMap = (Map) map;
176 + if (this.size() != asMap.size()) {
177 + return false;
178 + }
179 + for (Entry entry : this.entrySet()) {
180 + Object key = entry.getKey();
181 + if (!asMap.containsKey(key) || !asMap.get(key).equals(entry.getValue())) {
182 + return false;
183 + }
184 + }
185 + return true;
186 + }
187 +
188 + @Override
189 + public int hashCode() {
190 + return super.hashCode();
191 + }
192 +}
...\ No newline at end of file ...\ No newline at end of file
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.persistence.impl;
18 +
19 +import com.google.common.collect.Iterators;
20 +import org.mapdb.DB;
21 +import org.mapdb.Hasher;
22 +import org.mapdb.Serializer;
23 +
24 +import java.util.Collection;
25 +import java.util.Iterator;
26 +import java.util.Set;
27 +
28 +import static com.google.common.base.Preconditions.checkNotNull;
29 +
30 +/**
31 + * A set implementation that gets and receives all data from a serialized internal set.
32 + */
33 +//TODO add locking for reads and writes
34 +public class PersistentSet<E> implements Set<E> {
35 +
36 + private final org.onosproject.store.service.Serializer serializer;
37 +
38 + private final org.mapdb.DB database;
39 +
40 + private final Set<byte[]> items;
41 +
42 + private final String name;
43 +
44 + public PersistentSet(org.onosproject.store.service.Serializer serializer, DB database, String name) {
45 + this.serializer = checkNotNull(serializer);
46 + this.database = checkNotNull(database);
47 + this.name = checkNotNull(name);
48 +
49 + items = database
50 + .createHashSet(name)
51 + .serializer(Serializer.BYTE_ARRAY)
52 + .hasher(Hasher.BYTE_ARRAY)
53 + .makeOrGet();
54 + }
55 +
56 + public void readInto(Set<E> items) {
57 + this.items.forEach(item -> items.add(serializer.decode(item)));
58 + }
59 +
60 + @Override
61 + public int size() {
62 + return items.size();
63 + }
64 +
65 + @Override
66 + public boolean isEmpty() {
67 + return items.isEmpty();
68 + }
69 +
70 + @Override
71 + public boolean contains(Object o) {
72 + checkNotNull(o, "The argument cannot be null");
73 + return items.contains(serializer.encode(o));
74 + }
75 +
76 + @Override
77 + public Iterator<E> iterator() {
78 + return Iterators.transform(items.iterator(), serializer::decode);
79 + }
80 +
81 + @Override
82 + public Object[] toArray() {
83 + Object[] retArray = new Object[items.size()];
84 + int index = 0;
85 + Iterator<byte[]> iterator = items.iterator();
86 + while (iterator.hasNext()) {
87 + retArray[index] = serializer.decode(iterator.next());
88 + index++;
89 + }
90 + return retArray;
91 + }
92 +
93 + @Override
94 + public <T> T[] toArray(T[] a) {
95 + checkNotNull(a, "The passed in array cannot be null.");
96 + int index = 0;
97 + Iterator<byte[]> iterator = items.iterator();
98 + T[] retArray;
99 + if (a.length >= items.size()) {
100 + retArray = a;
101 + } else {
102 + retArray = (T[]) new Object[items.size()];
103 + }
104 + while (iterator.hasNext()) {
105 + retArray[index++] = serializer.decode(iterator.next());
106 + }
107 + if (retArray.length > items.size()) {
108 + retArray[index] = null;
109 + }
110 + return retArray;
111 + }
112 +
113 + @Override
114 + public boolean add(E item) {
115 + checkNotNull("Item to be added cannot be null.");
116 + return items.add(serializer.encode(item));
117 + }
118 +
119 + @Override
120 + public boolean remove(Object o) {
121 + checkNotNull(o, "Item to be removed cannot be null.");
122 + return items.remove(serializer.encode(o));
123 + }
124 +
125 + @Override
126 + public boolean containsAll(Collection<?> c) {
127 + checkNotNull(c, "Collection cannot be internal.");
128 + for (Object item : c) {
129 + if (!items.contains(serializer.encode(item))) {
130 + return false;
131 + }
132 + }
133 + return true;
134 + }
135 +
136 + @Override
137 + public boolean addAll(Collection<? extends E> c) {
138 + checkNotNull(c, "The collection to be added cannot be null.");
139 + boolean changed = false;
140 + for (Object item : c) {
141 + changed = items.add(serializer.encode(item)) || changed;
142 + }
143 + return changed;
144 + }
145 +
146 + @Override
147 + public boolean retainAll(Collection<?> c) {
148 + boolean changed = false;
149 + for (byte[] item : items) {
150 + E deserialized = serializer.decode(item);
151 + if (!c.contains(deserialized)) {
152 + changed = items.remove(item) || changed;
153 + }
154 + }
155 + return changed;
156 + }
157 +
158 + @Override
159 + public boolean removeAll(Collection<?> c) {
160 + boolean changed = false;
161 + for (Object item : c) {
162 + changed = items.remove(serializer.encode(item)) || changed;
163 + }
164 + return changed;
165 + }
166 +
167 + @Override
168 + public void clear() {
169 + items.clear();
170 + }
171 +
172 + @Override
173 + public boolean equals(Object set) {
174 + //This is not threadsafe and on larger sets incurs a significant processing cost
175 + if (!(set instanceof Set)) {
176 + return false;
177 + }
178 + Set asSet = (Set) set;
179 + if (asSet.size() != this.size()) {
180 + return false;
181 + }
182 + for (Object item : this) {
183 + if (!asSet.contains(item)) {
184 + return false;
185 + }
186 + }
187 + return true;
188 + }
189 +
190 + @Override
191 + public int hashCode() {
192 + return super.hashCode();
193 + }
194 +}
...\ No newline at end of file ...\ No newline at end of file
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.persistence.impl.test;
18 +
19 +import com.google.common.collect.Maps;
20 +import org.junit.After;
21 +import org.junit.Before;
22 +import org.junit.Test;
23 +import org.mapdb.DB;
24 +import org.mapdb.DBMaker;
25 +import org.onosproject.persistence.impl.PersistentMap;
26 +import org.onosproject.store.service.Serializer;
27 +
28 +import java.nio.file.Paths;
29 +import java.util.Map;
30 +import java.util.Set;
31 +
32 +import static org.junit.Assert.assertEquals;
33 +import static org.junit.Assert.assertFalse;
34 +import static org.junit.Assert.assertNull;
35 +import static org.junit.Assert.assertTrue;
36 +
37 +/**
38 + * Test suite for Persistent Map.
39 + */
40 +public class PersistentMapTest {
41 +
42 + private Map<Integer, Integer> map = null;
43 + private DB fakeDB = null;
44 +
45 +
46 + /**
47 + * Set up the database, create a map and a direct executor to handle it.
48 + *
49 + * @throws Exception if instantiation fails
50 + */
51 + @Before
52 + public void setUp() throws Exception {
53 + //Creates a db, a map within it and a basic integer serializer (async writing is off)
54 + fakeDB = DBMaker
55 + .newFileDB(Paths.get("../testDb").toFile())
56 + .asyncWriteEnable()
57 + .closeOnJvmShutdown()
58 + .make();
59 + map = new PersistentMap<Integer, Integer>(new Serializer() {
60 + @Override
61 + public <T> byte[] encode(T object) {
62 + if (object == null) {
63 + return null;
64 + }
65 + int num = (Integer) object;
66 + byte[] result = new byte[4];
67 +
68 + result[0] = (byte) (num >> 24);
69 + result[1] = (byte) (num >> 16);
70 + result[2] = (byte) (num >> 8);
71 + result[3] = (byte) num;
72 + return result;
73 + }
74 +
75 + @Override
76 + public <T> T decode(byte[] bytes) {
77 + if (bytes == null) {
78 + return null;
79 + }
80 + int num = 0x00000000;
81 +
82 + num = num | bytes[0] << 24;
83 + num = num | bytes[1] << 16;
84 + num = num | bytes[2] << 8;
85 + num = num | bytes[3];
86 +
87 + return (T) new java.lang.Integer(num);
88 + }
89 + }, fakeDB, "map");
90 + }
91 +
92 + /**
93 + * Clears and deletes the map, closes the datbase and deletes the file.
94 + *
95 + * @throws Exception if shutdown fails
96 + */
97 + @After
98 + public void tearDown() throws Exception {
99 + map.clear();
100 + fakeDB.delete("map:map");
101 + fakeDB.commit();
102 + fakeDB.close();
103 + //This is key to prevent artifacts persisting between tests.
104 + Paths.get("../testDB").toFile().delete();
105 +
106 +
107 + }
108 +
109 + @Test
110 + public void testRemove() throws Exception {
111 + //Checks removal and return values
112 + fillMap(10);
113 + assertEquals(10, map.size());
114 + for (int i = 0; i < 10; i++) {
115 + assertEquals("The previous value was wrong.", new Integer(i), map.remove(i));
116 + assertNull("The previous value was wrong.", map.remove(i));
117 + //(i+1) compensates for base zero.
118 + assertEquals("The size was wrong.", 10 - (i + 1), map.size());
119 + }
120 + }
121 +
122 + @Test
123 + public void testSize() throws Exception {
124 + //Checks size values throughout addition and removal
125 + for (int i = 0; i < 10; i++) {
126 + map.put(i, i);
127 + assertEquals("The map size is wrong.", i + 1, map.size());
128 + }
129 + for (int i = 0; i < 10; i++) {
130 + map.remove(i);
131 + assertEquals("The map size is wrong.", 9 - i, map.size());
132 + }
133 + }
134 +
135 + @Test
136 + public void testIsEmpty() throws Exception {
137 + //Checks empty condition
138 + //asserts that the map starts out empty
139 + assertTrue("Map should be empty", map.isEmpty());
140 + map.put(1, 1);
141 + assertFalse("Map shouldn't be empty.", map.isEmpty());
142 + map.remove(1);
143 + assertTrue("Map should be empty", map.isEmpty());
144 + }
145 +
146 + @Test
147 + public void testContains() throws Exception {
148 + //Checks both containsKey and containsValue be aware the implementations vary widely (value does not use mapDB
149 + //due to object '=='being an insufficient check)
150 + for (int i = 0; i < 10; i++) {
151 + assertFalse("Map should not contain the key", map.containsKey(i));
152 + assertFalse("Map should not contain the value", map.containsValue(i));
153 + map.put(i, i);
154 + assertTrue("Map should contain the key", map.containsKey(i));
155 + assertTrue("Map should contain the value", map.containsValue(i));
156 + }
157 + }
158 +
159 + @Test
160 + public void testGet() throws Exception {
161 + //Tests value retrieval and nonexistent key return values
162 + for (int i = 0; i < 10; i++) {
163 + map.put(i, i);
164 + for (int j = 0; j <= i; j++) {
165 + assertEquals("The value was wrong.", new Integer(j), map.get(j));
166 + }
167 + }
168 + assertNull("Null return value for nonexistent keys.", map.get(10));
169 + }
170 +
171 + @Test
172 + public void testPutAll() throws Exception {
173 + //Tests adding of an outside map
174 + Map<Integer, Integer> testMap = Maps.newHashMap();
175 + fillMap(10);
176 + map.putAll(testMap);
177 + for (int i = 0; i < 10; i++) {
178 + assertTrue("The map should contain the current 'i' value.", map.containsKey(i));
179 + assertTrue("The map should contain the current 'i' value.", map.containsValue(i));
180 + }
181 + }
182 +
183 + @Test
184 + public void testClear() throws Exception {
185 + //Tests clearing the map
186 + assertTrue("Map was initialized incorrectly, should be empty.", map.isEmpty());
187 + fillMap(10);
188 + assertFalse("Map should contain entries now.", map.isEmpty());
189 + map.clear();
190 + assertTrue("Map should have been cleared of entries.", map.isEmpty());
191 +
192 + }
193 +
194 + @Test
195 + public void testKeySet() throws Exception {
196 + //Tests key set generation
197 + fillMap(10);
198 + Set<Integer> keys = map.keySet();
199 + for (int i = 0; i < 10; i++) {
200 + assertTrue("The key set doesn't contain all keys 0-9", keys.contains(i));
201 + }
202 + assertEquals("The key set has an incorrect number of entries", 10, keys.size());
203 + }
204 +
205 + @Test
206 + public void testValues() throws Exception {
207 + //Tests value set generation
208 + fillMap(10);
209 + Set<Integer> values = (Set<Integer>) map.values();
210 + for (int i = 0; i < 10; i++) {
211 + assertTrue("The key set doesn't contain all keys 0-9", values.contains(i));
212 + }
213 + assertEquals("The key set has an incorrect number of entries", 10, values.size());
214 + }
215 +
216 + @Test
217 + public void testEntrySet() throws Exception {
218 + //Test entry set generation (violates abstraction by knowing the type of the returned entries)
219 + fillMap(10);
220 + Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
221 + for (int i = 0; i < 10; i++) {
222 + assertTrue("The key set doesn't contain all keys 0-9", entries.contains(Maps.immutableEntry(i, i)));
223 + }
224 + assertEquals("The key set has an incorrect number of entries", 10, entries.size());
225 + }
226 +
227 + @Test public void testPut() throws Exception {
228 + //Tests insertion behavior (particularly the returning of previous value)
229 + fillMap(10);
230 + for (int i = 0; i < 10; i++) {
231 + assertEquals("Put should return the previous value", new Integer(i), map.put(i, i + 1));
232 + }
233 + assertNull(map.put(11, 11));
234 + }
235 +
236 + /**
237 + * Populated the map with pairs of integers from (0, 0) up to (numEntries - 1, numEntries -1).
238 + * @param numEntries number of entries to add
239 + */
240 + private void fillMap(int numEntries) {
241 + for (int i = 0; i < numEntries; i++) {
242 + map.put(i, i);
243 + }
244 + }
245 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
33 33
34 <modules> 34 <modules>
35 <module>dist</module> 35 <module>dist</module>
36 + <module>persistence</module>
36 <module>serializers</module> 37 <module>serializers</module>
37 </modules> 38 </modules>
38 39
......
...@@ -96,6 +96,7 @@ ...@@ -96,6 +96,7 @@
96 <bundle>mvn:org.onosproject/onos-core-net/@ONOS-VERSION</bundle> 96 <bundle>mvn:org.onosproject/onos-core-net/@ONOS-VERSION</bundle>
97 <bundle>mvn:org.onosproject/onos-core-common/@ONOS-VERSION</bundle> 97 <bundle>mvn:org.onosproject/onos-core-common/@ONOS-VERSION</bundle>
98 <bundle>mvn:org.onosproject/onos-core-dist/@ONOS-VERSION</bundle> 98 <bundle>mvn:org.onosproject/onos-core-dist/@ONOS-VERSION</bundle>
99 + <bundle>mvn:org.onosproject/onos-core-persistence/@ONOS-VERSION</bundle>
99 <bundle>mvn:org.onosproject/onos-core-serializers/@ONOS-VERSION</bundle> 100 <bundle>mvn:org.onosproject/onos-core-serializers/@ONOS-VERSION</bundle>
100 <bundle>mvn:org.onosproject/onlab-netty/@ONOS-VERSION</bundle> 101 <bundle>mvn:org.onosproject/onlab-netty/@ONOS-VERSION</bundle>
101 </feature> 102 </feature>
......