blob: 0f291d5547fe5e1d78dd724e3ee07f9fff523b94 [file] [log] [blame]
Aaron Kruglikov92511f22015-10-12 14:39:04 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Aaron Kruglikov92511f22015-10-12 14:39:04 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.persistence.impl;
18
Aaron Kruglikov92511f22015-10-12 14:39:04 -070019import org.mapdb.DB;
20import org.mapdb.DBMaker;
21import org.onosproject.persistence.PersistenceService;
22import org.onosproject.persistence.PersistentMapBuilder;
23import org.onosproject.persistence.PersistentSetBuilder;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070024import org.osgi.service.component.annotations.Activate;
25import org.osgi.service.component.annotations.Component;
26import org.osgi.service.component.annotations.Deactivate;
Aaron Kruglikov92511f22015-10-12 14:39:04 -070027import org.slf4j.Logger;
28
Yuta HIGUCHI7f2c6f92016-07-04 19:52:52 -070029import java.io.File;
Aaron Kruglikov92511f22015-10-12 14:39:04 -070030import java.io.IOException;
31import java.nio.file.Files;
32import java.nio.file.Path;
Aaron Kruglikov92511f22015-10-12 14:39:04 -070033import java.util.Map;
34import java.util.Set;
35import java.util.Timer;
36import java.util.TimerTask;
37
Heedo Kang4a47a302016-02-29 17:40:23 +090038import static org.onosproject.security.AppGuard.checkPermission;
39import static org.onosproject.security.AppPermission.Type.PERSISTENCE_WRITE;
Aaron Kruglikov92511f22015-10-12 14:39:04 -070040import static org.slf4j.LoggerFactory.getLogger;
41
42/**
Thomas Vachuska58bf4912017-10-31 12:00:32 -070043 * Service that maintains local disk backed maps and sets.
44 * This implementation automatically deletes empty structures on shutdown.
Aaron Kruglikov92511f22015-10-12 14:39:04 -070045 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070046@Component(immediate = true, service = PersistenceService.class)
Aaron Kruglikov92511f22015-10-12 14:39:04 -070047public class PersistenceManager implements PersistenceService {
48
Thomas Vachuska58bf4912017-10-31 12:00:32 -070049 private static final String DATABASE_ROOT =
50 System.getProperty("karaf.data") + "/db/local/";
51
52 private static final String DATABASE_PATH = "cache";
Aaron Kruglikov92511f22015-10-12 14:39:04 -070053
54 static final String MAP_PREFIX = "map:";
Aaron Kruglikov92511f22015-10-12 14:39:04 -070055 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
Aaron Kruglikovdfb325a2015-11-23 14:16:55 -080063 private Timer timer;
Aaron Kruglikov92511f22015-10-12 14:39:04 -070064
65 private final CommitTask commitTask = new CommitTask();
66
67 @Activate
Thomas Vachuska58bf4912017-10-31 12:00:32 -070068 public void activate() {
Aaron Kruglikovdfb325a2015-11-23 14:16:55 -080069 timer = new Timer();
Thomas Vachuska58bf4912017-10-31 12:00:32 -070070
71 File dbFolderPath = new File(DATABASE_ROOT);
Yuta HIGUCHI7f2c6f92016-07-04 19:52:52 -070072 Path dbPath = dbFolderPath.toPath().resolve(DATABASE_PATH);
73 log.debug("dbPath: {}", dbPath);
74
Aaron Kruglikov92511f22015-10-12 14:39:04 -070075 //Make sure the directory exists, if it does not, make it.
Yuta HIGUCHI7f2c6f92016-07-04 19:52:52 -070076 if (!dbFolderPath.isDirectory()) {
Aaron Kruglikov92511f22015-10-12 14:39:04 -070077 log.info("The specified folder location for the database did not exist and will be created.");
78 try {
Yuta HIGUCHI7f2c6f92016-07-04 19:52:52 -070079 Files.createDirectories(dbFolderPath.toPath());
Aaron Kruglikov92511f22015-10-12 14:39:04 -070080 } catch (IOException e) {
81 log.error("Could not create the required folder for the database.");
82 throw new PersistenceException("Database folder could not be created.");
83 }
84 }
85 //Notify if the database file does not exist.
86 boolean dbFound = Files.exists(dbPath);
87 if (!dbFound) {
88 log.info("The database file could not be located, a new database will be constructed.");
89
90 } else {
91 log.info("A previous database file has been found.");
92 }
93 localDB = DBMaker.newFileDB(dbPath.toFile())
94 .asyncWriteEnable()
95 .closeOnJvmShutdown()
96 .make();
97 timer.schedule(commitTask, FLUSH_FREQUENCY_MILLIS, FLUSH_FREQUENCY_MILLIS);
98 log.info("Started");
99 }
100
101 @Deactivate
102 public void deactivate() {
Aaron Kruglikovdfb325a2015-11-23 14:16:55 -0800103 timer.cancel();
Aaron Kruglikov92511f22015-10-12 14:39:04 -0700104 for (Map.Entry<String, Object> entry : localDB.getAll().entrySet()) {
105 String key = entry.getKey();
106 Object value = entry.getValue();
Aaron Kruglikov92511f22015-10-12 14:39:04 -0700107 if (value instanceof Map) {
Thomas Vachuska58bf4912017-10-31 12:00:32 -0700108 // This is a map implementation to be handled as such
Aaron Kruglikov92511f22015-10-12 14:39:04 -0700109 Map asMap = (Map) value;
110 if (asMap.isEmpty()) {
111 //the map is empty and may be deleted
112 localDB.delete(key);
113 }
Aaron Kruglikov92511f22015-10-12 14:39:04 -0700114 } else if (value instanceof Set) {
Thomas Vachuska58bf4912017-10-31 12:00:32 -0700115 // This is a set implementation and can be handled as such
Aaron Kruglikov92511f22015-10-12 14:39:04 -0700116 Set asSet = (Set) value;
117 if (asSet.isEmpty()) {
118 //the set is empty and may be deleted
119 localDB.delete(key);
120 }
121 }
122 }
123 localDB.commit();
124 localDB.close();
125 log.info("Stopped");
126 }
127
Yuta HIGUCHI7f2c6f92016-07-04 19:52:52 -0700128 @Override
Aaron Kruglikov92511f22015-10-12 14:39:04 -0700129 public <K, V> PersistentMapBuilder<K, V> persistentMapBuilder() {
Heedo Kang4a47a302016-02-29 17:40:23 +0900130 checkPermission(PERSISTENCE_WRITE);
Aaron Kruglikov92511f22015-10-12 14:39:04 -0700131 return new DefaultPersistentMapBuilder<>(localDB);
132 }
133
Yuta HIGUCHI7f2c6f92016-07-04 19:52:52 -0700134 @Override
Aaron Kruglikov92511f22015-10-12 14:39:04 -0700135 public <E> PersistentSetBuilder<E> persistentSetBuilder() {
Heedo Kang4a47a302016-02-29 17:40:23 +0900136 checkPermission(PERSISTENCE_WRITE);
Aaron Kruglikov92511f22015-10-12 14:39:04 -0700137 return new DefaultPersistentSetBuilder<>(localDB);
138 }
139
140 private class CommitTask extends TimerTask {
141
142 @Override
143 public void run() {
144 localDB.commit();
145 }
146 }
147}