Committed by
Gerrit Code Review
Creating persistence service.
Change-Id: Ib78b4001a24c71b4096e5a2a446dbd5009aa1090
Showing
18 changed files
with
1407 additions
and
4 deletions
... | @@ -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> | ... | ... |
... | @@ -100,4 +100,4 @@ class MapDbPersistentStore<K, V> implements PersistentStore<K, V> { | ... | @@ -100,4 +100,4 @@ class MapDbPersistentStore<K, V> implements PersistentStore<K, V> { |
100 | items.remove(keyBytes); | 100 | items.remove(keyBytes); |
101 | database.commit(); | 101 | database.commit(); |
102 | } | 102 | } |
103 | -} | 103 | +} |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
core/store/persistence/pom.xml
0 → 100644
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 |
core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceException.java
0 → 100644
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 | +} |
core/store/persistence/src/main/java/org/onosproject/persistence/impl/PersistenceManager.java
0 → 100644
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 |
core/store/persistence/src/main/java/org/onosproject/persistence/impl/test/PersistentMapTest.java
0 → 100644
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 |
core/store/persistence/src/main/java/org/onosproject/persistence/impl/test/PersistentSetTest.java
0 → 100644
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.Sets; | ||
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.PersistentSet; | ||
26 | +import org.onosproject.store.service.Serializer; | ||
27 | + | ||
28 | +import java.nio.file.Paths; | ||
29 | +import java.util.HashSet; | ||
30 | +import java.util.Set; | ||
31 | + | ||
32 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
33 | +import static org.junit.Assert.assertEquals; | ||
34 | +import static org.junit.Assert.assertFalse; | ||
35 | +import static org.junit.Assert.assertNotEquals; | ||
36 | +import static org.junit.Assert.assertNull; | ||
37 | +import static org.junit.Assert.assertTrue; | ||
38 | + | ||
39 | +/** | ||
40 | + * Test suite for Persistent Set. | ||
41 | + */ | ||
42 | +public class PersistentSetTest { | ||
43 | + | ||
44 | + private Set<Integer> set = null; | ||
45 | + private DB fakeDB = null; | ||
46 | + | ||
47 | + @Before | ||
48 | + public void setUp() throws Exception { | ||
49 | + //Creates a db, a set within it and a basic integer serializer (async writing is off) | ||
50 | + fakeDB = DBMaker | ||
51 | + .newFileDB(Paths.get("../testDb").toFile()) | ||
52 | + .asyncWriteEnable() | ||
53 | + .closeOnJvmShutdown() | ||
54 | + .make(); | ||
55 | + set = new PersistentSet<Integer>(new Serializer() { | ||
56 | + @Override | ||
57 | + public <T> byte[] encode(T object) { | ||
58 | + if (object == null) { | ||
59 | + return null; | ||
60 | + } | ||
61 | + int num = (Integer) object; | ||
62 | + byte[] result = new byte[4]; | ||
63 | + | ||
64 | + result[0] = (byte) (num >> 24); | ||
65 | + result[1] = (byte) (num >> 16); | ||
66 | + result[2] = (byte) (num >> 8); | ||
67 | + result[3] = (byte) num; | ||
68 | + return result; | ||
69 | + } | ||
70 | + | ||
71 | + @Override | ||
72 | + public <T> T decode(byte[] bytes) { | ||
73 | + if (bytes == null) { | ||
74 | + return null; | ||
75 | + } | ||
76 | + int num = 0x00000000; | ||
77 | + | ||
78 | + num = num | bytes[0] << 24; | ||
79 | + num = num | bytes[1] << 16; | ||
80 | + num = num | bytes[2] << 8; | ||
81 | + num = num | bytes[3]; | ||
82 | + | ||
83 | + return (T) new java.lang.Integer(num); | ||
84 | + } | ||
85 | + }, fakeDB, "set"); | ||
86 | + | ||
87 | + } | ||
88 | + | ||
89 | + @After | ||
90 | + public void tearDown() throws Exception { | ||
91 | + set.clear(); | ||
92 | + fakeDB.delete("map:map"); | ||
93 | + fakeDB.commit(); | ||
94 | + fakeDB.close(); | ||
95 | + //This is key to prevent artifacts persisting between tests. | ||
96 | + Paths.get("../testDB").toFile().delete(); | ||
97 | + } | ||
98 | + | ||
99 | + @Test | ||
100 | + public void testSize() throws Exception { | ||
101 | + //Check correct sizing throughout population | ||
102 | + for (int i = 0; i < 10; i++) { | ||
103 | + set.add(i); | ||
104 | + assertEquals("The set should have i + 1 entries.", i + 1, set.size()); | ||
105 | + } | ||
106 | + } | ||
107 | + | ||
108 | + @Test | ||
109 | + public void testIsEmpty() throws Exception { | ||
110 | + //test empty condition | ||
111 | + assertTrue("The set should be initialized empty.", set.isEmpty()); | ||
112 | + fillSet(5, this.set); | ||
113 | + assertFalse("The set should no longer be empty.", set.isEmpty()); | ||
114 | + set.clear(); | ||
115 | + assertTrue("The set should have been cleared.", set.isEmpty()); | ||
116 | + } | ||
117 | + | ||
118 | + @Test | ||
119 | + public void testContains() throws Exception { | ||
120 | + //Test contains | ||
121 | + assertFalse("The set should not contain anything", set.contains(1)); | ||
122 | + fillSet(10, this.set); | ||
123 | + for (int i = 0; i < 10; i++) { | ||
124 | + assertTrue("The set should contain all values 0-9.", set.contains(i)); | ||
125 | + } | ||
126 | + } | ||
127 | + | ||
128 | + @Test | ||
129 | + public void testIterator() throws Exception { | ||
130 | + //Test iterator behavior (no order guarantees are made) | ||
131 | + Set<Integer> validationSet = Sets.newHashSet(); | ||
132 | + fillSet(10, this.set); | ||
133 | + fillSet(10, validationSet); | ||
134 | + set.iterator().forEachRemaining(item -> assertTrue("Items were mismatched.", validationSet.remove(item))); | ||
135 | + //All values should have been seen and removed | ||
136 | + assertTrue("All entries in the validation set should have been removed.", validationSet.isEmpty()); | ||
137 | + } | ||
138 | + | ||
139 | + @Test | ||
140 | + public void testToArray() throws Exception { | ||
141 | + //Test creation of a new array of the values | ||
142 | + fillSet(10, set); | ||
143 | + Object[] arr = set.toArray(); | ||
144 | + assertEquals("The array should be of length 10.", 10, arr.length); | ||
145 | + for (int i = 0; i < 10; i++) { | ||
146 | + assertTrue("All elements of the array should be in the set.", set.contains((Integer) arr[i])); | ||
147 | + } | ||
148 | + } | ||
149 | + | ||
150 | + @Test | ||
151 | + public void testToArray1() throws Exception { | ||
152 | + //Test creation of a new array with the possibility of populating passed array if space allows | ||
153 | + Integer[] originalArray = new Integer[9]; | ||
154 | + fillSet(9, set); | ||
155 | + //Test the case where the array and set match in size | ||
156 | + Object[] retArray = set.toArray(originalArray); | ||
157 | + assertEquals("If the set can fit the array should be the one passed in.", originalArray, retArray); | ||
158 | + //Test the case where the passe array is too small to fit the set | ||
159 | + set.add(9); | ||
160 | + assertNotEquals("A new set should be generated if the contents will not fit in the passed set", | ||
161 | + set.toArray(originalArray), originalArray); | ||
162 | + //Now test the case where there should be a null terminator | ||
163 | + set.clear(); | ||
164 | + fillSet(5, set); | ||
165 | + assertNull("The character one after last should be null if the array is larger than the set.", | ||
166 | + set.toArray(originalArray)[5]); | ||
167 | + } | ||
168 | + | ||
169 | + @Test | ||
170 | + public void testAdd() throws Exception { | ||
171 | + //Test of add | ||
172 | + for (int i = 0; i < 10; i++) { | ||
173 | + assertEquals("The size of the set is wrong.", i, set.size()); | ||
174 | + assertTrue("The first add of an element should be true.", set.add(i)); | ||
175 | + assertFalse("The second add of an element should be false.", set.add(i)); | ||
176 | + } | ||
177 | + } | ||
178 | + | ||
179 | + @Test | ||
180 | + public void testRemove() throws Exception { | ||
181 | + //Test removal | ||
182 | + fillSet(10, set); | ||
183 | + for (int i = 0; i < 10; i++) { | ||
184 | + assertEquals("The size of the set is wrong.", 10 - i, set.size()); | ||
185 | + assertTrue("The first removal should be true.", set.remove(i)); | ||
186 | + assertFalse("The second removal should be false (item no longer contained).", set.remove(i)); | ||
187 | + } | ||
188 | + assertTrue("All elements should have been removed.", set.isEmpty()); | ||
189 | + } | ||
190 | + | ||
191 | + @Test | ||
192 | + public void testContainsAll() throws Exception { | ||
193 | + //Test contains with short circuiting | ||
194 | + Set<Integer> integersToCheck = Sets.newHashSet(); | ||
195 | + fillSet(10, integersToCheck); | ||
196 | + fillSet(10, set); | ||
197 | + assertTrue("The sets should be identical so mutual subsets.", set.containsAll(integersToCheck)); | ||
198 | + set.remove(9); | ||
199 | + assertFalse("The set should contain one fewer value.", set.containsAll(integersToCheck)); | ||
200 | + } | ||
201 | + | ||
202 | + @Test | ||
203 | + public void testAddAll() throws Exception { | ||
204 | + //Test multi-adds with change checking | ||
205 | + Set<Integer> integersToCheck = Sets.newHashSet(); | ||
206 | + fillSet(10, integersToCheck); | ||
207 | + assertFalse("Set should be empty and so integers to check should not be a subset.", | ||
208 | + set.containsAll(integersToCheck)); | ||
209 | + assertTrue("The set should have changed as a result of add all.", set.addAll(integersToCheck)); | ||
210 | + assertFalse("The set should not have changed as a result of add all a second time.", | ||
211 | + set.addAll(integersToCheck)); | ||
212 | + assertTrue("The sets should now be equivalent.", set.containsAll(integersToCheck)); | ||
213 | + assertTrue("The sets should now be equivalent.", integersToCheck.containsAll(set)); | ||
214 | + } | ||
215 | + | ||
216 | + @Test | ||
217 | + public void testRetainAll() throws Exception { | ||
218 | + //Test ability to generate the intersection set | ||
219 | + Set<Integer> retainSet = Sets.newHashSet(); | ||
220 | + fillSet(10, set); | ||
221 | + assertTrue("The set should have changed.", set.retainAll(retainSet)); | ||
222 | + assertTrue("The set should have been emptied.", set.isEmpty()); | ||
223 | + fillSet(10, set); | ||
224 | + fillSet(10, retainSet); | ||
225 | + Set<Integer> duplicateSet = new HashSet<>(set); | ||
226 | + assertFalse("The set should not have changed.", set.retainAll(retainSet)); | ||
227 | + assertEquals("The set should be the same as the duplicate.", duplicateSet, set); | ||
228 | + retainSet.remove(9); | ||
229 | + assertTrue("The set should have changed.", set.retainAll(retainSet)); | ||
230 | + duplicateSet.remove(9); | ||
231 | + assertEquals("The set should have had the nine element removed.", duplicateSet, set); | ||
232 | + } | ||
233 | + | ||
234 | + @Test | ||
235 | + public void testRemoveAll() throws Exception { | ||
236 | + //Test for mass removal and change checking | ||
237 | + Set<Integer> removeSet = Sets.newHashSet(); | ||
238 | + fillSet(10, set); | ||
239 | + Set<Integer> duplicateSet = Sets.newHashSet(set); | ||
240 | + assertFalse("No elements should change.", set.removeAll(removeSet)); | ||
241 | + assertEquals("Set should not have diverged from the duplicate.", duplicateSet, set); | ||
242 | + fillSet(5, removeSet); | ||
243 | + assertTrue("Elements should have been removed.", set.removeAll(removeSet)); | ||
244 | + assertNotEquals("Duplicate set should no longer be equivalent.", duplicateSet, set); | ||
245 | + assertEquals("Five elements should have been removed from set.", 5, set.size()); | ||
246 | + for (Integer item : removeSet) { | ||
247 | + assertFalse("No element of remove set should remain.", set.contains(item)); | ||
248 | + } | ||
249 | + } | ||
250 | + | ||
251 | + @Test | ||
252 | + public void testClear() throws Exception { | ||
253 | + //Test set emptying | ||
254 | + assertTrue("The set should be initialized empty.", set.isEmpty()); | ||
255 | + set.clear(); | ||
256 | + assertTrue("Clear should have no effect on an empty set.", set.isEmpty()); | ||
257 | + fillSet(10, set); | ||
258 | + assertFalse("The set should no longer be empty.", set.isEmpty()); | ||
259 | + set.clear(); | ||
260 | + assertTrue("The set should be empty after clear.", set.isEmpty()); | ||
261 | + } | ||
262 | + | ||
263 | + /** | ||
264 | + * Populated the map with integers from (0) up to (numEntries - 1). | ||
265 | + * | ||
266 | + * @param numEntries number of entries to add | ||
267 | + */ | ||
268 | + private void fillSet(int numEntries, Set<Integer> set) { | ||
269 | + checkNotNull(set); | ||
270 | + for (int i = 0; i < numEntries; i++) { | ||
271 | + set.add(i); | ||
272 | + } | ||
273 | + } | ||
274 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -33,7 +33,8 @@ | ... | @@ -33,7 +33,8 @@ |
33 | 33 | ||
34 | <modules> | 34 | <modules> |
35 | <module>dist</module> | 35 | <module>dist</module> |
36 | - <module>serializers</module> | 36 | + <module>persistence</module> |
37 | + <module>serializers</module> | ||
37 | </modules> | 38 | </modules> |
38 | 39 | ||
39 | <dependencies> | 40 | <dependencies> | ... | ... |
... | @@ -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> | ... | ... |
-
Please register or login to post a comment