blob: 64a8683a9eedea32d82ec1879dd3d6b638dc6a0a [file] [log] [blame]
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.persistence.impl;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
import org.mapdb.DB;
import org.mapdb.DBMaker;
import org.onosproject.persistence.PersistenceService;
import org.onosproject.persistence.PersistentMapBuilder;
import org.onosproject.persistence.PersistentSetBuilder;
import org.slf4j.Logger;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Service that maintains local disk backed maps and sets. This implementation automatically deletes empty structures
* on shutdown.
*/
@Component(immediate = true)
@Service
public class PersistenceManager implements PersistenceService {
private static final String DATABASE_PATH = "../data/localDB";
private static final String ENCLOSING_FOLDER = "../data";
static final String MAP_PREFIX = "map:";
static final String SET_PREFIX = "set:";
private final Logger log = getLogger(getClass());
private DB localDB = null;
private static final int FLUSH_FREQUENCY_MILLIS = 3000;
private final Timer timer = new Timer();
private final CommitTask commitTask = new CommitTask();
@Activate
public void activate() {
Path dbPath = Paths.get(DATABASE_PATH);
Path dbFolderPath = Paths.get(ENCLOSING_FOLDER);
//Make sure the directory exists, if it does not, make it.
if (!dbFolderPath.toFile().isDirectory()) {
log.info("The specified folder location for the database did not exist and will be created.");
try {
Files.createDirectories(dbFolderPath);
} catch (IOException e) {
log.error("Could not create the required folder for the database.");
throw new PersistenceException("Database folder could not be created.");
}
}
//Notify if the database file does not exist.
boolean dbFound = Files.exists(dbPath);
if (!dbFound) {
log.info("The database file could not be located, a new database will be constructed.");
} else {
log.info("A previous database file has been found.");
}
localDB = DBMaker.newFileDB(dbPath.toFile())
.asyncWriteEnable()
.closeOnJvmShutdown()
.make();
timer.schedule(commitTask, FLUSH_FREQUENCY_MILLIS, FLUSH_FREQUENCY_MILLIS);
log.info("Started");
}
@Deactivate
public void deactivate() {
for (Map.Entry<String, Object> entry : localDB.getAll().entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
//This is a map implementation to be handled as such
if (value instanceof Map) {
Map asMap = (Map) value;
if (asMap.isEmpty()) {
//the map is empty and may be deleted
localDB.delete(key);
}
//This is a set implementation and can be handled as such
} else if (value instanceof Set) {
Set asSet = (Set) value;
if (asSet.isEmpty()) {
//the set is empty and may be deleted
localDB.delete(key);
}
}
}
localDB.commit();
localDB.close();
log.info("Stopped");
}
public <K, V> PersistentMapBuilder<K, V> persistentMapBuilder() {
return new DefaultPersistentMapBuilder<>(localDB);
}
public <E> PersistentSetBuilder<E> persistentSetBuilder() {
return new DefaultPersistentSetBuilder<>(localDB);
}
private class CommitTask extends TimerTask {
@Override
public void run() {
localDB.commit();
}
}
}