blob: 05c577c0f3430a24e939cacddc40edbbbaf2f58b [file] [log] [blame]
Aaron Kruglikov92511f22015-10-12 14:39:04 -07001/*
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
17package org.onosproject.persistence.impl;
18
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Service;
23import org.mapdb.DB;
24import org.mapdb.DBMaker;
25import org.onosproject.persistence.PersistenceService;
26import org.onosproject.persistence.PersistentMapBuilder;
27import org.onosproject.persistence.PersistentSetBuilder;
28import org.slf4j.Logger;
29
30import java.io.IOException;
31import java.nio.file.Files;
32import java.nio.file.Path;
33import java.nio.file.Paths;
34import java.util.Map;
35import java.util.Set;
36import java.util.Timer;
37import java.util.TimerTask;
38
39import 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
47public class PersistenceManager implements PersistenceService {
48
Madan Jampani44d8fbb2015-12-04 12:54:39 -080049 private static final String DATABASE_PATH = "../data/localDB";
50 private static final String ENCLOSING_FOLDER = "../data";
Aaron Kruglikov92511f22015-10-12 14:39:04 -070051
52 static final String MAP_PREFIX = "map:";
53
54 static final String SET_PREFIX = "set:";
55
56 private final Logger log = getLogger(getClass());
57
58 private DB localDB = null;
59
60 private static final int FLUSH_FREQUENCY_MILLIS = 3000;
61
Aaron Kruglikovdfb325a2015-11-23 14:16:55 -080062 private Timer timer;
Aaron Kruglikov92511f22015-10-12 14:39:04 -070063
64 private final CommitTask commitTask = new CommitTask();
65
66 @Activate
67 public void activate() {
Aaron Kruglikovdfb325a2015-11-23 14:16:55 -080068 timer = new Timer();
Aaron Kruglikov92511f22015-10-12 14:39:04 -070069 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() {
Aaron Kruglikovdfb325a2015-11-23 14:16:55 -080099 timer.cancel();
Aaron Kruglikov92511f22015-10-12 14:39:04 -0700100 for (Map.Entry<String, Object> entry : localDB.getAll().entrySet()) {
101 String key = entry.getKey();
102 Object value = entry.getValue();
103 //This is a map implementation to be handled as such
104 if (value instanceof Map) {
105 Map asMap = (Map) value;
106 if (asMap.isEmpty()) {
107 //the map is empty and may be deleted
108 localDB.delete(key);
109 }
110 //This is a set implementation and can be handled as such
111 } else if (value instanceof Set) {
112 Set asSet = (Set) value;
113 if (asSet.isEmpty()) {
114 //the set is empty and may be deleted
115 localDB.delete(key);
116 }
117 }
118 }
119 localDB.commit();
120 localDB.close();
121 log.info("Stopped");
122 }
123
124 public <K, V> PersistentMapBuilder<K, V> persistentMapBuilder() {
125 return new DefaultPersistentMapBuilder<>(localDB);
126 }
127
128 public <E> PersistentSetBuilder<E> persistentSetBuilder() {
129 return new DefaultPersistentSetBuilder<>(localDB);
130 }
131
132 private class CommitTask extends TimerTask {
133
134 @Override
135 public void run() {
136 localDB.commit();
137 }
138 }
139}