/**
* 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.deephacks.confit.internal.mapdb;
import org.deephacks.confit.model.Bean;
import org.deephacks.confit.model.BeanId;
import org.deephacks.confit.model.BeanId.BinaryBeanId;
import org.deephacks.confit.model.Schema;
import org.deephacks.confit.spi.SchemaManager;
import org.mapdb.DB;
import org.mapdb.TxMaker;
import org.mapdb.TxRollbackException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.concurrent.ConcurrentNavigableMap;
public class MapDB {
public static final String BEANS = "confit.beans";
public static final String ID_TO_NAME = "confit.id_to_name";
public static final String NAME_TO_ID = "confit.name_to_id";
public static final String PROPERTY_COUNTER = "confit.property_counter";
private static final SchemaManager schemaManager = SchemaManager.lookup();
private final TxMaker txMaker;
private static final ThreadLocal<DB> tx = new ThreadLocal<>();
public MapDB(TxMaker txMaker) {
this.txMaker = txMaker;
}
private ConcurrentNavigableMap<BinaryBeanId, byte[]> getBeanStorage() {
DB db = getDb();
return db.getTreeMap(BEANS);
}
private ConcurrentNavigableMap<Long, String> getIdToName() {
DB db = getDb();
return db.getTreeMap(ID_TO_NAME);
}
private ConcurrentNavigableMap<String, Long> getNameToId() {
DB db = getDb();
return db.getTreeMap(NAME_TO_ID);
}
private Long incrementPropertyCounter() {
DB db = getDb();
ConcurrentNavigableMap<String, Long> counters = db.getTreeMap(PROPERTY_COUNTER);
Long value = counters.get(PROPERTY_COUNTER);
if (value == null) {
value = 0L;
}
value++;
counters.put(PROPERTY_COUNTER, value);
return value;
}
public String getNameFromStorage(long id) {
String name = getIdToName().get(id);
if (name != null) {
return name;
}
throw new IllegalArgumentException("Id not found " + id);
}
public Long getIdFromStorage(String name) {
Long id = getNameToId().get(name);
if (id != null) {
return id;
}
id = incrementPropertyCounter();
getNameToId().put(name, id);
getIdToName().put(id, name);
return id;
}
public void commit() {
try {
DB db = getDb();
db.commit();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
tx.set(null);
}
}
public void rollback(Throwable e) {
try {
if (e instanceof TxRollbackException) {
e.printStackTrace();
return;
}
DB db = getDb();
db.rollback();
} finally {
tx.set(null);
}
}
private DB getDb() {
DB db = tx.get();
if (db == null) {
db = txMaker.makeTx();
tx.set(db);
}
return db;
}
public Bean get(BeanId id) {
byte[] data = getBeanStorage().get(new BinaryBeanId(id));
if (data == null) {
return null;
}
Schema schema = schemaManager.getSchema(id.getSchemaName());
id.set(schema);
return Bean.read(id, data);
}
public Collection<Bean> values() {
ArrayList<Bean> beans = new ArrayList<>();
for (BinaryBeanId id : getBeanStorage().keySet()) {
Bean bean = toBean(id.getBeanId());
beans.add(bean);
}
return beans;
}
public Collection<Bean> list(String schemaName) {
ArrayList<Bean> beans = new ArrayList<>();
BinaryBeanId min = BinaryBeanId.getMinId(schemaName);
BinaryBeanId max = BinaryBeanId.getMaxId(schemaName);
final ConcurrentNavigableMap<BinaryBeanId, byte[]> schemaInstances
= getBeanStorage().subMap(min, true, max, true);
for (BinaryBeanId id : schemaInstances.keySet()) {
Bean bean = toBean(id.getBeanId());
beans.add(bean);
}
return beans;
}
public LinkedHashMap<BeanId, byte[]> listBinary(String schemaName) {
LinkedHashMap<BeanId, byte[]> beans = new LinkedHashMap<>();
BinaryBeanId min = BinaryBeanId.getMinId(schemaName);
BinaryBeanId max = BinaryBeanId.getMaxId(schemaName);
final ConcurrentNavigableMap<BinaryBeanId, byte[]> schemaInstances
= getBeanStorage().subMap(min, true, max, true);
for (BinaryBeanId id : schemaInstances.keySet()) {
beans.put(id.getBeanId(), schemaInstances.get(id));
}
return beans;
}
private Bean toBean(BeanId id) {
byte[] data = getBeanStorage().get(new BinaryBeanId(id));
if (data == null) {
return null;
}
Schema schema = schemaManager.getSchema(id.getSchemaName());
id.set(schema);
return Bean.read(id, data);
}
public Bean remove(BeanId id) {
Bean bean = get(id);
getBeanStorage().remove(new BinaryBeanId(id));
return bean;
}
public void put(Bean bean) {
getBeanStorage().put(new BinaryBeanId(bean.getId()), bean.write());
}
public void clear() {
getBeanStorage().clear();
}
}