pub mod db_element;
pub mod db_error;
pub mod db_f64;
pub mod db_id;
pub mod db_index;
pub mod db_key_order;
pub mod db_key_value;
pub mod db_type;
pub mod db_value;
mod db_search_handlers;
mod db_value_index;
use self::db_error::DbError;
use self::db_search_handlers::DefaultHandler;
use self::db_search_handlers::LimitHandler;
use self::db_search_handlers::LimitOffsetHandler;
use self::db_search_handlers::OffsetHandler;
use self::db_search_handlers::PathHandler;
use crate::DbId;
use crate::DbKeyValue;
use crate::DbValue;
use crate::QueryResult;
use crate::SearchQueryAlgorithm;
use crate::StorageData;
use crate::Transaction;
use crate::TransactionMut;
use crate::collections::indexed_map::DbIndexedMap;
use crate::command::Command;
use crate::db::db_index::DbIndexes;
use crate::db::db_key_value::DbKeyValues;
use crate::graph::DbGraph;
use crate::graph::GraphIndex;
use crate::graph_search::GraphSearch;
use crate::graph_search::SearchControl;
use crate::query::Query;
use crate::query::QueryMut;
use crate::query::query_condition::QueryCondition;
use crate::query::query_condition::QueryConditionData;
use crate::query::query_condition::QueryConditionLogic;
use crate::query::query_condition::QueryConditionModifier;
use crate::query::query_id::QueryId;
use crate::storage::Storage;
use crate::storage::StorageIndex;
use crate::storage::any_storage::AnyStorage;
use crate::storage::file_storage::FileStorage;
use crate::storage::file_storage_memory_mapped::FileStorageMemoryMapped;
use crate::storage::memory_storage::MemoryStorage;
use crate::utilities::serialize::Serialize;
use crate::utilities::serialize::SerializeStatic;
const CURRENT_VERSION: u64 = 1;
#[derive(Default)]
struct DbStorageIndex {
version: u64,
graph: StorageIndex,
aliases: (StorageIndex, StorageIndex),
indexes: StorageIndex,
values: StorageIndex,
}
impl Serialize for DbStorageIndex {
fn serialize(&self) -> Vec<u8> {
[
self.version.serialize(),
self.graph.serialize(),
self.aliases.0.serialize(),
self.aliases.1.serialize(),
self.indexes.serialize(),
self.values.serialize(),
]
.concat()
}
fn deserialize(bytes: &[u8]) -> Result<Self, DbError> {
let size = i64::serialized_size_static() as usize;
let version = u64::deserialize(bytes)?;
let graph = StorageIndex::deserialize(&bytes[size..])?;
let aliases_1 = StorageIndex::deserialize(&bytes[size * 2..])?;
let aliases_2 = StorageIndex::deserialize(&bytes[size * 3..])?;
let indexes = StorageIndex::deserialize(&bytes[size * 4..])?;
let values = StorageIndex::deserialize(&bytes[size * 5..])?;
Ok(Self {
version,
graph,
aliases: (aliases_1, aliases_2),
indexes,
values,
})
}
fn serialized_size(&self) -> u64 {
i64::serialized_size_static() * 6
}
}
pub struct DbImpl<Store: StorageData> {
storage: Storage<Store>,
graph: DbGraph<Store>,
aliases: DbIndexedMap<String, DbId, Store>,
indexes: DbIndexes<Store>,
values: DbKeyValues<Store>,
undo_stack: Vec<Command>,
}
pub type Db = DbImpl<FileStorageMemoryMapped>;
pub type DbTransaction<'a> = Transaction<'a, FileStorageMemoryMapped>;
pub type DbTransactionMut<'a> = TransactionMut<'a, FileStorageMemoryMapped>;
pub type DbFile = DbImpl<FileStorage>;
pub type DbFileTransaction<'a> = Transaction<'a, FileStorage>;
pub type DbFileTransactionMut<'a> = TransactionMut<'a, FileStorage>;
pub type DbMemory = DbImpl<MemoryStorage>;
pub type DbMemoryTransaction<'a> = Transaction<'a, MemoryStorage>;
pub type DbMemoryTransactionMut<'a> = TransactionMut<'a, MemoryStorage>;
pub type DbAny = DbImpl<AnyStorage>;
pub type DbAnyTransaction<'a> = Transaction<'a, AnyStorage>;
pub type DbAnyTransactionMut<'a> = TransactionMut<'a, AnyStorage>;
impl<Store: StorageData> std::fmt::Debug for DbImpl<Store> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("agdb::Db").finish_non_exhaustive()
}
}
impl<Store: StorageData> DbImpl<Store> {
pub fn new(filename: &str) -> Result<Self, DbError> {
match Self::try_new(filename) {
Ok(db) => Ok(db),
Err(error) => {
let mut db_error = DbError::from("Failed to create database");
db_error.cause = Some(Box::new(error));
Err(db_error)
}
}
}
pub fn with_data(data: Store) -> Result<Self, DbError> {
Self::try_new_with_storage(Storage::with_data(data)?)
}
pub fn backup(&self, filename: &str) -> Result<(), DbError> {
self.storage.backup(filename)
}
pub fn copy(&self, filename: &str) -> Result<Self, DbError> {
let storage = self.storage.copy(filename)?;
let index = storage.value::<DbStorageIndex>(StorageIndex(1))?;
let graph = DbGraph::from_storage(&storage, index.graph)?;
let aliases = DbIndexedMap::from_storage(&storage, index.aliases)?;
let indexes = DbIndexes::from_storage(&storage, index.indexes)?;
let values = DbKeyValues::from_storage(&storage, index.values)?;
Ok(Self {
storage,
graph,
aliases,
indexes,
values,
undo_stack: vec![],
})
}
pub fn exec<T: Query>(&self, query: T) -> Result<QueryResult, DbError> {
self.transaction(|transaction| transaction.exec(query))
}
pub fn exec_mut<T: QueryMut>(&mut self, query: T) -> Result<QueryResult, DbError> {
self.transaction_mut(|transaction| transaction.exec_mut(query))
}
pub fn filename(&self) -> &str {
self.storage.name()
}
pub fn optimize_storage(&mut self) -> Result<(), DbError> {
self.storage.optimize_storage()
}
pub fn rename(&mut self, filename: &str) -> Result<(), DbError> {
self.storage.rename(filename)
}
pub fn transaction<T, E>(
&self,
f: impl FnOnce(&Transaction<Store>) -> Result<T, E>,
) -> Result<T, E> {
let transaction = Transaction::new(self);
f(&transaction)
}
pub fn transaction_mut<T, E: From<DbError>>(
&mut self,
f: impl FnOnce(&mut TransactionMut<Store>) -> Result<T, E>,
) -> Result<T, E> {
let mut transaction = TransactionMut::new(&mut *self);
let result = f(&mut transaction);
if result.is_ok() {
transaction.commit()?;
} else {
transaction.rollback()?;
}
result
}
pub fn size(&self) -> u64 {
self.storage.len()
}
pub fn shrink_to_fit(&mut self) -> Result<(), DbError> {
self.graph.shrink_to_fit(&mut self.storage)?;
self.aliases.shrink_to_fit(&mut self.storage)?;
self.indexes.shrink_to_fit(&mut self.storage)?;
self.values.shrink_to_fit(&mut self.storage)?;
self.optimize_storage()
}
pub(crate) fn commit(&mut self) -> Result<(), DbError> {
self.undo_stack.clear();
Ok(())
}
pub(crate) fn rollback(&mut self) -> Result<(), DbError> {
let mut undo_stack = vec![];
std::mem::swap(&mut undo_stack, &mut self.undo_stack);
for command in undo_stack.iter().rev() {
match command {
Command::InsertAlias { id, alias } => {
self.aliases.insert(&mut self.storage, alias, id)?
}
Command::InsertEdge { from, to } => self
.graph
.insert_edge(&mut self.storage, *from, *to)
.map(|_| ())?,
Command::InsertIndex { key } => {
self.indexes.insert(&mut self.storage, key.clone())?;
}
Command::InsertToIndex { key, value, id } => self
.indexes
.index_mut(key)
.expect("index not found during rollback")
.ids_mut()
.insert(&mut self.storage, value, id)?,
Command::InsertKeyValue { id, key_value } => {
if let Some(index) = self.indexes.index_mut(&key_value.key) {
index
.ids_mut()
.insert(&mut self.storage, &key_value.value, id)?;
}
self.values
.insert_value(&mut self.storage, id.as_index(), key_value)?
}
Command::InsertNode => self.graph.insert_node(&mut self.storage).map(|_| ())?,
Command::RemoveAlias { alias } => {
self.aliases.remove_key(&mut self.storage, alias)?
}
Command::RemoveEdge { index } => {
self.graph.remove_edge(&mut self.storage, *index)?
}
Command::RemoveIndex { key } => self.indexes.remove(&mut self.storage, key)?,
Command::RemoveKeyValue { id, key_value } => {
if let Some(index) = self.indexes.index_mut(&key_value.key) {
index
.ids_mut()
.remove_value(&mut self.storage, &key_value.value, id)?;
}
self.values
.remove_value(&mut self.storage, id.as_index(), &key_value.key)?
}
Command::RemoveNode { index } => {
self.graph.remove_node(&mut self.storage, *index)?
}
Command::ReplaceKeyValue { id, key_value } => {
let old = self
.values
.insert_or_replace(&mut self.storage, id.as_index(), key_value)?
.expect("old value not found during rollback");
if let Some(index) = self.indexes.index_mut(&old.key) {
index
.ids_mut()
.remove_value(&mut self.storage, &old.value, id)?;
index
.ids_mut()
.insert(&mut self.storage, &key_value.value, id)?;
}
return Ok(());
}
}
}
Ok(())
}
pub(crate) fn alias(&self, db_id: DbId) -> Result<String, DbError> {
self.aliases
.key(&self.storage, &db_id)?
.ok_or(DbError::from(format!("Id '{}' not found", db_id.0)))
}
pub(crate) fn aliases(&self) -> Vec<(String, DbId)> {
self.aliases.iter(&self.storage).collect()
}
pub(crate) fn db_id(&self, query_id: &QueryId) -> Result<DbId, DbError> {
match query_id {
QueryId::Id(id) => Ok(DbId(self.graph_index(id.0)?.0)),
QueryId::Alias(alias) => Ok(self
.aliases
.value(&self.storage, alias)?
.ok_or(DbError::from(format!("Alias '{alias}' not found")))?),
}
}
pub(crate) fn edge_count(&self, db_id: DbId, from: bool, to: bool) -> Result<u64, DbError> {
let index = self.graph_index(db_id.0)?;
if let Some(node) = self.graph.node(&self.storage, index) {
return Ok(match (from, to) {
(true, true) => node.edge_count(),
(true, false) => node.edge_count_from(),
(false, true) => node.edge_count_to(),
(false, false) => 0,
});
}
Ok(0)
}
#[allow(clippy::wrong_self_convention)]
pub(crate) fn from_id(&self, id: DbId) -> Option<DbId> {
if id.0 < 0 {
Some(DbId(
self.graph.edge_from(&self.storage, GraphIndex(id.0)).0,
))
} else {
None
}
}
pub(crate) fn to_id(&self, id: DbId) -> Option<DbId> {
if id.0 < 0 {
Some(DbId(self.graph.edge_to(&self.storage, GraphIndex(id.0)).0))
} else {
None
}
}
pub(crate) fn indexes(&self) -> Vec<DbKeyValue> {
self.indexes
.indexes()
.iter()
.map(|index| DbKeyValue {
key: index.key().clone(),
value: index.ids().len().into(),
})
.collect()
}
pub(crate) fn insert_alias(&mut self, db_id: DbId, alias: &String) -> Result<(), DbError> {
if let Some(old_alias) = self.aliases.key(&self.storage, &db_id)? {
self.undo_stack.push(Command::InsertAlias {
id: db_id,
alias: old_alias.clone(),
});
self.aliases.remove_key(&mut self.storage, &old_alias)?;
self.aliases.remove_key(&mut self.storage, &old_alias)?;
}
self.undo_stack.push(Command::RemoveAlias {
alias: alias.clone(),
});
self.aliases.insert(&mut self.storage, alias, &db_id)
}
pub(crate) fn insert_edge(&mut self, from: DbId, to: DbId) -> Result<DbId, DbError> {
let index =
self.graph
.insert_edge(&mut self.storage, GraphIndex(from.0), GraphIndex(to.0))?;
self.undo_stack.push(Command::RemoveEdge { index });
Ok(DbId(index.0))
}
pub(crate) fn insert_index(&mut self, key: &DbValue) -> Result<u64, DbError> {
if self.indexes.index(key).is_some() {
return Err(DbError::from(format!("Index '{key}' already exists")));
}
self.undo_stack
.push(Command::RemoveIndex { key: key.clone() });
let index = self.indexes.insert(&mut self.storage, key.clone())?;
for i in 1..self.values.len() {
let kvs = self.values.values(&self.storage, i)?;
let db_id = if self
.graph
.node(&self.storage, GraphIndex(i as i64))
.is_some()
{
DbId(i as i64)
} else {
DbId(-(i as i64))
};
for kv in kvs {
if kv.key == *key {
index
.ids_mut()
.insert(&mut self.storage, &kv.value, &db_id)?;
}
}
}
Ok(index.ids().len())
}
pub(crate) fn insert_new_alias(&mut self, db_id: DbId, alias: &String) -> Result<(), DbError> {
self.undo_stack.push(Command::RemoveAlias {
alias: alias.clone(),
});
self.aliases.insert(&mut self.storage, alias, &db_id)?;
Ok(())
}
pub(crate) fn insert_node(&mut self) -> Result<DbId, DbError> {
let index = self.graph.insert_node(&mut self.storage)?;
self.undo_stack.push(Command::RemoveNode { index });
Ok(DbId(index.0))
}
pub(crate) fn insert_key_value(
&mut self,
db_id: DbId,
key_value: &DbKeyValue,
) -> Result<(), DbError> {
if let Some(index) = self.indexes.index_mut(&key_value.key) {
index
.ids_mut()
.insert(&mut self.storage, &key_value.value, &db_id)?;
}
self.undo_stack.push(Command::RemoveKeyValue {
id: db_id,
key_value: key_value.clone(),
});
self.values
.insert_value(&mut self.storage, db_id.as_index(), key_value)?;
Ok(())
}
pub(crate) fn insert_or_replace_key_value(
&mut self,
db_id: DbId,
key_value: &DbKeyValue,
) -> Result<(), DbError> {
if let Some(old) =
self.values
.insert_or_replace(&mut self.storage, db_id.as_index(), key_value)?
{
if let Some(index) = self.indexes.index_mut(&old.key) {
index
.ids_mut()
.remove_value(&mut self.storage, &old.value, &db_id)?;
index
.ids_mut()
.insert(&mut self.storage, &key_value.value, &db_id)?;
}
self.undo_stack.push(Command::ReplaceKeyValue {
id: db_id,
key_value: old,
});
} else {
if let Some(index) = self.indexes.index_mut(&key_value.key) {
index
.ids_mut()
.insert(&mut self.storage, &key_value.value, &db_id)?;
}
self.undo_stack.push(Command::RemoveKeyValue {
id: db_id,
key_value: key_value.clone(),
});
}
Ok(())
}
pub(crate) fn keys(&self, db_id: DbId) -> Result<Vec<DbValue>, DbError> {
self.values.keys(&self.storage, db_id.as_index())
}
pub(crate) fn key_count(&self, db_id: DbId) -> Result<u64, DbError> {
self.values.key_count(&self.storage, db_id.as_index())
}
pub(crate) fn node_count(&self) -> Result<u64, DbError> {
self.graph.node_count(&self.storage)
}
pub(crate) fn remove(&mut self, query_id: &QueryId) -> Result<bool, DbError> {
match query_id {
QueryId::Id(db_id) => self.remove_id(*db_id),
QueryId::Alias(alias) => {
if let Some(db_id) = self.aliases.value(&self.storage, alias)? {
self.remove_node(db_id, GraphIndex(db_id.0), Some(alias.clone()))?;
self.remove_all_values(db_id)?;
Ok(true)
} else {
Ok(false)
}
}
}
}
pub(crate) fn remove_id(&mut self, db_id: DbId) -> Result<bool, DbError> {
if let Ok(graph_index) = self.graph_index(db_id.0) {
if graph_index.is_node() {
self.remove_node(db_id, graph_index, self.aliases.key(&self.storage, &db_id)?)?;
} else {
self.remove_edge(graph_index)?;
}
self.remove_all_values(db_id)?;
return Ok(true);
}
Ok(false)
}
pub(crate) fn remove_alias(&mut self, alias: &String) -> Result<bool, DbError> {
if let Some(id) = self.aliases.value(&self.storage, alias)? {
self.undo_stack.push(Command::InsertAlias {
id,
alias: alias.clone(),
});
self.aliases.remove_key(&mut self.storage, alias)?;
self.aliases.remove_key(&mut self.storage, alias)?;
return Ok(true);
}
Ok(false)
}
pub(crate) fn remove_index(&mut self, key: &DbValue) -> Result<u64, DbError> {
let mut count = None;
if let Some(index) = self.indexes.index(key) {
for (value, id) in index.ids().iter(&self.storage) {
self.undo_stack.push(Command::InsertToIndex {
key: key.clone(),
value: value.clone(),
id,
});
}
count = Some(index.ids().len());
}
if let Some(count) = count {
self.undo_stack
.push(Command::InsertIndex { key: key.clone() });
self.indexes.remove(&mut self.storage, key)?;
Ok(count)
} else {
Ok(0)
}
}
pub(crate) fn reserve_key_value_capacity(
&mut self,
db_id: DbId,
additional: u64,
) -> Result<(), DbError> {
self.values
.reserve_capacity(&mut self.storage, db_id.as_index(), additional)
}
pub(crate) fn search_index(
&self,
key: &DbValue,
value: &DbValue,
) -> Result<Vec<DbId>, DbError> {
if let Some(index) = self.indexes.index(key) {
Ok(index.ids().values(&self.storage, value)?)
} else {
Err(DbError::from(format!("Index '{key}' not found")))
}
}
pub(crate) fn search_from(
&self,
from: DbId,
algorithm: SearchQueryAlgorithm,
limit: u64,
offset: u64,
conditions: &Vec<QueryCondition>,
) -> Result<Vec<DbId>, DbError> {
let search = GraphSearch::from((&self.graph, &self.storage));
let indexes = match (limit, offset) {
(0, 0) => match algorithm {
SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search(
GraphIndex(from.0),
DefaultHandler::new(self, conditions),
)?,
SearchQueryAlgorithm::DepthFirst => search.depth_first_search(
GraphIndex(from.0),
DefaultHandler::new(self, conditions),
)?,
_ => search.elements(DefaultHandler::new(self, conditions))?,
},
(_, 0) => match algorithm {
SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search(
GraphIndex(from.0),
LimitHandler::new(limit, self, conditions),
)?,
SearchQueryAlgorithm::DepthFirst => search.depth_first_search(
GraphIndex(from.0),
LimitHandler::new(limit, self, conditions),
)?,
_ => search.elements(LimitHandler::new(limit, self, conditions))?,
},
(0, _) => match algorithm {
SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search(
GraphIndex(from.0),
OffsetHandler::new(offset, self, conditions),
)?,
SearchQueryAlgorithm::DepthFirst => search.depth_first_search(
GraphIndex(from.0),
OffsetHandler::new(offset, self, conditions),
)?,
_ => search.elements(OffsetHandler::new(offset, self, conditions))?,
},
(_, _) => match algorithm {
SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search(
GraphIndex(from.0),
LimitOffsetHandler::new(limit, offset, self, conditions),
)?,
SearchQueryAlgorithm::DepthFirst => search.depth_first_search(
GraphIndex(from.0),
LimitOffsetHandler::new(limit, offset, self, conditions),
)?,
_ => search.elements(LimitOffsetHandler::new(limit, offset, self, conditions))?,
},
};
Ok(indexes.iter().map(|index| DbId(index.0)).collect())
}
pub(crate) fn search_to(
&self,
to: DbId,
algorithm: SearchQueryAlgorithm,
limit: u64,
offset: u64,
conditions: &Vec<QueryCondition>,
) -> Result<Vec<DbId>, DbError> {
let search = GraphSearch::from((&self.graph, &self.storage));
let indexes = match (limit, offset) {
(0, 0) => match algorithm {
SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search_reverse(
GraphIndex(to.0),
DefaultHandler::new(self, conditions),
)?,
_ => search.depth_first_search_reverse(
GraphIndex(to.0),
DefaultHandler::new(self, conditions),
)?,
},
(_, 0) => match algorithm {
SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search_reverse(
GraphIndex(to.0),
LimitHandler::new(limit, self, conditions),
)?,
_ => search.depth_first_search_reverse(
GraphIndex(to.0),
LimitHandler::new(limit, self, conditions),
)?,
},
(0, _) => match algorithm {
SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search_reverse(
GraphIndex(to.0),
OffsetHandler::new(offset, self, conditions),
)?,
_ => search.depth_first_search_reverse(
GraphIndex(to.0),
OffsetHandler::new(offset, self, conditions),
)?,
},
(_, _) => match algorithm {
SearchQueryAlgorithm::BreadthFirst => search.breadth_first_search_reverse(
GraphIndex(to.0),
LimitOffsetHandler::new(limit, offset, self, conditions),
)?,
_ => search.depth_first_search_reverse(
GraphIndex(to.0),
LimitOffsetHandler::new(limit, offset, self, conditions),
)?,
},
};
Ok(indexes.iter().map(|index| DbId(index.0)).collect())
}
pub(crate) fn search_from_to(
&self,
from: DbId,
to: DbId,
conditions: &Vec<QueryCondition>,
) -> Result<Vec<DbId>, DbError> {
Ok(GraphSearch::from((&self.graph, &self.storage))
.path(
GraphIndex(from.0),
GraphIndex(to.0),
PathHandler::new(self, conditions),
)?
.iter()
.map(|index| DbId(index.0))
.collect())
}
pub(crate) fn values(&self, db_id: DbId) -> Result<Vec<DbKeyValue>, DbError> {
self.values.values(&self.storage, db_id.as_index())
}
pub(crate) fn values_by_keys(
&self,
db_id: DbId,
keys: &[DbValue],
) -> Result<Vec<DbKeyValue>, DbError> {
self.values
.values_by_keys(&self.storage, db_id.as_index(), keys)
}
fn graph_index(&self, id: i64) -> Result<GraphIndex, DbError> {
match id.cmp(&0) {
std::cmp::Ordering::Less => {
if self.graph.edge(&self.storage, GraphIndex(id)).is_some() {
return Ok(GraphIndex(id));
}
}
std::cmp::Ordering::Equal => {}
std::cmp::Ordering::Greater => {
if self.graph.node(&self.storage, GraphIndex(id)).is_some() {
return Ok(GraphIndex(id));
}
}
}
Err(DbError::from(format!("Id '{id}' not found")))
}
fn node_edges(
&self,
graph_index: GraphIndex,
) -> Result<Vec<(GraphIndex, GraphIndex, GraphIndex)>, DbError> {
let mut edges = vec![];
let node = self
.graph
.node(&self.storage, graph_index)
.ok_or(DbError::from("Data integrity corrupted"))?;
for edge in node.edge_iter_from() {
edges.push((edge.index(), edge.index_from(), edge.index_to()));
}
for edge in node.edge_iter_to() {
let from = edge.index_from();
if from != graph_index {
edges.push((edge.index(), from, edge.index_to()));
}
}
Ok(edges)
}
fn remove_edge(&mut self, graph_index: GraphIndex) -> Result<(), DbError> {
let (from, to) = {
let edge = self
.graph
.edge(&self.storage, graph_index)
.ok_or(DbError::from("Graph integrity corrupted"))?;
(edge.index_from(), edge.index_to())
};
self.graph.remove_edge(&mut self.storage, graph_index)?;
self.undo_stack.push(Command::InsertEdge { from, to });
Ok(())
}
fn remove_node(
&mut self,
db_id: DbId,
graph_index: GraphIndex,
alias: Option<String>,
) -> Result<(), DbError> {
if let Some(alias) = alias {
self.undo_stack.push(Command::InsertAlias {
alias: alias.clone(),
id: db_id,
});
self.aliases.remove_key(&mut self.storage, &alias)?;
self.aliases.remove_key(&mut self.storage, &alias)?;
}
for edge in self.node_edges(graph_index)? {
self.graph.remove_edge(&mut self.storage, edge.0)?;
self.undo_stack.push(Command::InsertEdge {
from: edge.1,
to: edge.2,
});
self.remove_all_values(DbId(edge.0.0))?;
}
self.graph.remove_node(&mut self.storage, graph_index)?;
self.undo_stack.push(Command::InsertNode);
Ok(())
}
pub(crate) fn remove_keys(&mut self, db_id: DbId, keys: &[DbValue]) -> Result<i64, DbError> {
let mut result = 0;
for key_value in self.values.values(&self.storage, db_id.as_index())? {
if keys.contains(&key_value.key) {
if let Some(index) = self.indexes.index_mut(&key_value.key) {
index
.ids_mut()
.remove_value(&mut self.storage, &key_value.value, &db_id)?;
}
self.values
.remove_value(&mut self.storage, db_id.as_index(), &key_value.key)?;
self.undo_stack.push(Command::InsertKeyValue {
id: db_id,
key_value,
});
result -= 1;
}
}
Ok(result)
}
fn remove_all_values(&mut self, db_id: DbId) -> Result<(), DbError> {
for key_value in self.values.values(&self.storage, db_id.as_index())? {
if let Some(index) = self.indexes.index_mut(&key_value.key) {
index
.ids_mut()
.remove_value(&mut self.storage, &key_value.value, &db_id)?;
}
self.undo_stack.push(Command::InsertKeyValue {
id: db_id,
key_value,
});
}
self.values.remove(&mut self.storage, db_id.as_index())?;
Ok(())
}
fn try_new_with_storage(mut storage: Storage<Store>) -> Result<Self, DbError> {
let graph_storage;
let aliases_storage;
let indexes_storage;
let values_storage;
if storage.value_size(StorageIndex(1)).is_err() {
storage.insert(&DbStorageIndex::default())?;
graph_storage = DbGraph::new(&mut storage)?;
aliases_storage = DbIndexedMap::new(&mut storage)?;
indexes_storage = DbIndexes::new(&mut storage)?;
values_storage = DbKeyValues::new(&mut storage)?;
let db_storage_index = DbStorageIndex {
version: CURRENT_VERSION,
graph: graph_storage.storage_index(),
aliases: aliases_storage.storage_index(),
indexes: indexes_storage.storage_index(),
values: values_storage.storage_index(),
};
storage.insert_at(StorageIndex(1), 0, &db_storage_index)?;
} else {
let index = if let Ok(index) = storage.value::<DbStorageIndex>(StorageIndex(1)) {
index
} else {
legacy::convert_to_current_version(&mut storage)?;
storage.value::<DbStorageIndex>(StorageIndex(1))?
};
graph_storage = DbGraph::from_storage(&storage, index.graph)?;
aliases_storage = DbIndexedMap::from_storage(&storage, index.aliases)?;
indexes_storage = DbIndexes::from_storage(&storage, index.indexes)?;
values_storage = DbKeyValues::from_storage(&storage, index.values)?;
}
Ok(Self {
storage,
graph: graph_storage,
aliases: aliases_storage,
indexes: indexes_storage,
values: values_storage,
undo_stack: vec![],
})
}
fn try_new(filename: &str) -> Result<Self, DbError> {
Self::try_new_with_storage(Storage::new(filename)?)
}
pub(crate) fn evaluate_condition(
&self,
index: GraphIndex,
distance: u64,
condition: &QueryConditionData,
) -> Result<SearchControl, DbError> {
match condition {
QueryConditionData::Distance(value) => Ok(value.compare_distance(distance)),
QueryConditionData::Edge => Ok(SearchControl::Continue(index.is_edge())),
QueryConditionData::EdgeCount(value) => Ok(SearchControl::Continue(
if let Some(node) = self.graph.node(&self.storage, index) {
value.compare(node.edge_count())
} else {
false
},
)),
QueryConditionData::EdgeCountFrom(value) => Ok(SearchControl::Continue(
if let Some(node) = self.graph.node(&self.storage, index) {
value.compare(node.edge_count_from())
} else {
false
},
)),
QueryConditionData::EdgeCountTo(value) => Ok(SearchControl::Continue(
if let Some(node) = self.graph.node(&self.storage, index) {
value.compare(node.edge_count_to())
} else {
false
},
)),
QueryConditionData::Ids(values) => {
Ok(SearchControl::Continue(values.iter().any(|id| {
index.0
== match id {
QueryId::Id(id) => id.0,
QueryId::Alias(alias) => {
self.aliases
.value(&self.storage, alias)
.unwrap_or_default()
.unwrap_or_default()
.0
}
}
})))
}
QueryConditionData::KeyValue(kvc) => Ok(SearchControl::Continue(
if let Some(value) = self.values.value(&self.storage, index.as_u64(), &kvc.key)? {
kvc.value.compare(&value)
} else {
false
},
)),
QueryConditionData::Keys(values) => {
let keys = self.values.keys(&self.storage, index.as_u64())?;
Ok(SearchControl::Continue(
values.iter().all(|k| keys.contains(k)),
))
}
QueryConditionData::Node => Ok(SearchControl::Continue(index.is_node())),
QueryConditionData::Where(conditions) => {
self.evaluate_conditions(index, distance, conditions)
}
}
}
pub(crate) fn evaluate_conditions(
&self,
index: GraphIndex,
distance: u64,
conditions: &[QueryCondition],
) -> Result<SearchControl, DbError> {
let mut result = SearchControl::Continue(true);
for condition in conditions {
let mut control = self.evaluate_condition(index, distance, &condition.data)?;
match condition.modifier {
QueryConditionModifier::Beyond => {
if control.is_true() {
control = control.and(SearchControl::Continue(true));
} else {
control = SearchControl::Stop(true);
}
}
QueryConditionModifier::Not => control.flip(),
QueryConditionModifier::NotBeyond => {
if control.is_true() {
control = control.and(SearchControl::Stop(true));
} else {
control = SearchControl::Continue(true);
}
}
_ => {}
};
result = match condition.logic {
QueryConditionLogic::And => result.and(control),
QueryConditionLogic::Or => result.or(control),
};
}
Ok(result)
}
}
impl<Store: StorageData> Drop for DbImpl<Store> {
fn drop(&mut self) {
let _ = self.storage.optimize_storage();
}
}
impl DbAny {
pub fn new_file(filename: &str) -> Result<Self, DbError> {
Self::try_new_any(filename, Self::try_new_file)
}
pub fn new_mapped(filename: &str) -> Result<Self, DbError> {
Self::try_new_any(filename, Self::try_new_mapped)
}
pub fn new_memory(filename: &str) -> Result<Self, DbError> {
Self::try_new_any(filename, Self::try_new_memory)
}
fn try_new_any(
filename: &str,
init: fn(&str) -> Result<DbImpl<AnyStorage>, DbError>,
) -> Result<Self, DbError> {
match init(filename) {
Ok(db) => Ok(db),
Err(error) => {
let mut db_error = DbError::from("Failed to create database");
db_error.cause = Some(Box::new(error));
Err(db_error)
}
}
}
fn try_new_memory(filename: &str) -> Result<DbImpl<AnyStorage>, DbError> {
Self::try_new_with_storage(Storage::with_data(AnyStorage::Memory(MemoryStorage::new(
filename,
)?))?)
}
fn try_new_file(filename: &str) -> Result<DbImpl<AnyStorage>, DbError> {
Self::try_new_with_storage(Storage::with_data(AnyStorage::File(FileStorage::new(
filename,
)?))?)
}
fn try_new_mapped(filename: &str) -> Result<DbImpl<AnyStorage>, DbError> {
Self::try_new_with_storage(Storage::with_data(AnyStorage::MemoryMapped(
FileStorageMemoryMapped::new(filename)?,
))?)
}
}
mod legacy {
use crate::DbError;
use crate::DbId;
use crate::DbKeyValue;
use crate::StorageData;
use crate::collections::map::MapIterator;
use crate::collections::multi_map::MultiMapStorage;
use crate::db::CURRENT_VERSION;
use crate::db::DbStorageIndex;
use crate::db::db_key_value::DbKeyValues;
use crate::storage::Storage;
use crate::storage::StorageIndex;
use crate::utilities::serialize::Serialize;
use crate::utilities::serialize::SerializeStatic;
use std::marker::PhantomData;
pub(crate) struct DbStorageIndexLegacy {
pub(crate) graph: StorageIndex,
pub(crate) aliases: (StorageIndex, StorageIndex),
pub(crate) indexes: StorageIndex,
pub(crate) values: StorageIndex,
}
impl Serialize for DbStorageIndexLegacy {
fn serialize(&self) -> Vec<u8> {
[
self.graph.serialize(),
self.aliases.0.serialize(),
self.aliases.1.serialize(),
self.indexes.serialize(),
self.values.serialize(),
]
.concat()
}
fn deserialize(bytes: &[u8]) -> Result<Self, DbError> {
let size = i64::serialized_size_static() as usize;
let graph = StorageIndex::deserialize(bytes)?;
let aliases_1 = StorageIndex::deserialize(&bytes[size..])?;
let aliases_2 = StorageIndex::deserialize(&bytes[size * 2..])?;
let indexes = StorageIndex::deserialize(&bytes[size * 3..])?;
let values = StorageIndex::deserialize(&bytes[size * 4..])?;
Ok(Self {
graph,
aliases: (aliases_1, aliases_2),
indexes,
values,
})
}
fn serialized_size(&self) -> u64 {
i64::serialized_size_static() * 5
}
}
pub fn convert_to_current_version<D: StorageData>(
storage: &mut Storage<D>,
) -> Result<DbStorageIndex, DbError> {
let legacy_index = storage.value::<DbStorageIndexLegacy>(StorageIndex(1))?;
let legacy_values =
MultiMapStorage::<DbId, DbKeyValue, _>::from_storage(storage, legacy_index.values)?;
let t = storage.transaction();
let mut values = DbKeyValues::new(storage)?;
let mut pos = 0;
loop {
let mut it = MapIterator {
pos,
data: &legacy_values.data,
storage,
phantom_data: PhantomData,
};
if let Some((db_id, kv)) = it.next() {
pos = it.pos;
values.insert_value(storage, db_id.as_index(), &kv)?;
} else {
break;
}
}
legacy_values.remove_from_storage(storage)?;
let db_storage_index = DbStorageIndex {
version: CURRENT_VERSION,
graph: legacy_index.graph,
aliases: legacy_index.aliases,
indexes: legacy_index.indexes,
values: values.storage_index(),
};
storage.replace(StorageIndex(1), &db_storage_index)?;
storage.commit(t)?;
storage.optimize_storage()?;
Ok(db_storage_index)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utilities::test_file::TestFile;
#[test]
fn db_storage_index_serialized_size() {
assert_eq!(DbStorageIndex::default().serialized_size(), 48);
}
#[test]
fn derived_from_debug() {
let test_file = TestFile::new();
let db = Db::new(test_file.file_name()).unwrap();
let _ = format!("{db:?}");
}
#[test]
fn db_storage_index_legacy_serialization() {
let index = legacy::DbStorageIndexLegacy {
graph: StorageIndex(1),
aliases: (StorageIndex(2), StorageIndex(3)),
indexes: StorageIndex(4),
values: StorageIndex(5),
};
let serialized = index.serialize();
let deserialized = legacy::DbStorageIndexLegacy::deserialize(&serialized).unwrap();
assert_eq!(index.graph, deserialized.graph);
assert_eq!(index.aliases.0, deserialized.aliases.0);
assert_eq!(index.aliases.1, deserialized.aliases.1);
assert_eq!(index.indexes, deserialized.indexes);
assert_eq!(index.values, deserialized.values);
assert_eq!(index.serialized_size(), deserialized.serialized_size());
}
}