|
@@ -1,14 +1,14 @@
|
|
//! Rocks DB implementation of the storage layer
|
|
//! Rocks DB implementation of the storage layer
|
|
-use self::resultset::ResultSet;
|
|
|
|
|
|
+use self::iterators::WrapperIterator;
|
|
use crate::{secondary_index::SecondaryIndex, Error, Storage};
|
|
use crate::{secondary_index::SecondaryIndex, Error, Storage};
|
|
use nostr_rs_types::types::{Event, Filter, Tag};
|
|
use nostr_rs_types::types::{Event, Filter, Tag};
|
|
use rocksdb::{
|
|
use rocksdb::{
|
|
BoundColumnFamily, ColumnFamilyDescriptor, IteratorMode, Options, SliceTransform, WriteBatch,
|
|
BoundColumnFamily, ColumnFamilyDescriptor, IteratorMode, Options, SliceTransform, WriteBatch,
|
|
DB,
|
|
DB,
|
|
};
|
|
};
|
|
-use std::{collections::VecDeque, path::Path, sync::Arc};
|
|
|
|
|
|
+use std::{collections::VecDeque, ops::Deref, path::Path, sync::Arc};
|
|
|
|
|
|
-mod resultset;
|
|
|
|
|
|
+mod iterators;
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
enum ReferenceType {
|
|
enum ReferenceType {
|
|
@@ -18,6 +18,7 @@ enum ReferenceType {
|
|
RefEvent,
|
|
RefEvent,
|
|
Kind,
|
|
Kind,
|
|
LocalEvents,
|
|
LocalEvents,
|
|
|
|
+ Stream,
|
|
}
|
|
}
|
|
|
|
|
|
impl ReferenceType {
|
|
impl ReferenceType {
|
|
@@ -30,6 +31,7 @@ impl ReferenceType {
|
|
Self::RefEvent => "refs_by_ids",
|
|
Self::RefEvent => "refs_by_ids",
|
|
Self::Kind => "kinds",
|
|
Self::Kind => "kinds",
|
|
Self::LocalEvents => "local",
|
|
Self::LocalEvents => "local",
|
|
|
|
+ Self::Stream => "stream",
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -52,6 +54,7 @@ impl RocksDb {
|
|
ColumnFamilyDescriptor::new(ReferenceType::RefPublicKey.as_str(), options.clone()),
|
|
ColumnFamilyDescriptor::new(ReferenceType::RefPublicKey.as_str(), options.clone()),
|
|
ColumnFamilyDescriptor::new(ReferenceType::Kind.as_str(), options.clone()),
|
|
ColumnFamilyDescriptor::new(ReferenceType::Kind.as_str(), options.clone()),
|
|
ColumnFamilyDescriptor::new(ReferenceType::LocalEvents.as_str(), options.clone()),
|
|
ColumnFamilyDescriptor::new(ReferenceType::LocalEvents.as_str(), options.clone()),
|
|
|
|
+ ColumnFamilyDescriptor::new(ReferenceType::Stream.as_str(), options.clone()),
|
|
],
|
|
],
|
|
)?;
|
|
)?;
|
|
Ok(Self { db })
|
|
Ok(Self { db })
|
|
@@ -82,82 +85,81 @@ impl RocksDb {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-impl<'a> Storage<'a, ResultSet<'a>> for RocksDb {
|
|
|
|
- fn get_local_events<C>(&self, for_each: C) -> Result<(), Error>
|
|
|
|
- where
|
|
|
|
- C: Fn(Event) -> Result<(), Error>,
|
|
|
|
- {
|
|
|
|
|
|
+impl<'a> Storage<'a, WrapperIterator<'a>> for RocksDb {
|
|
|
|
+ fn get_local_events(&'a self, limit: Option<usize>) -> Result<WrapperIterator<'a>, Error> {
|
|
let cf_handle = self.reference_to_cf_handle(ReferenceType::LocalEvents)?;
|
|
let cf_handle = self.reference_to_cf_handle(ReferenceType::LocalEvents)?;
|
|
- self.db
|
|
|
|
- .iterator_cf(&cf_handle, IteratorMode::Start)
|
|
|
|
- .into_iter()
|
|
|
|
- .map(|res| {
|
|
|
|
- if let Ok((key, _)) = res {
|
|
|
|
- if let Ok(Some(event)) = self.get_event(&key) {
|
|
|
|
- for_each(event)
|
|
|
|
- } else {
|
|
|
|
- Ok(())
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- Ok(())
|
|
|
|
- }
|
|
|
|
- })
|
|
|
|
- .collect::<Result<Vec<_>, Error>>()?;
|
|
|
|
- Ok(())
|
|
|
|
|
|
+ Ok(WrapperIterator {
|
|
|
|
+ db: self,
|
|
|
|
+ filter: None,
|
|
|
|
+ namespace: None,
|
|
|
|
+ secondary_index_iterator: Some(self.db.iterator_cf(&cf_handle, IteratorMode::Start)),
|
|
|
|
+ current_prefix: vec![],
|
|
|
|
+ prefixes: VecDeque::new(),
|
|
|
|
+ limit,
|
|
|
|
+ returned: 0,
|
|
|
|
+ })
|
|
}
|
|
}
|
|
|
|
|
|
fn set_local_event(&self, event: &Event) -> Result<(), Error> {
|
|
fn set_local_event(&self, event: &Event) -> Result<(), Error> {
|
|
|
|
+ let event_id = &event.id;
|
|
|
|
+ let secondary_index = SecondaryIndex::new(event_id, event.created_at());
|
|
self.db.put_cf(
|
|
self.db.put_cf(
|
|
&self.reference_to_cf_handle(ReferenceType::LocalEvents)?,
|
|
&self.reference_to_cf_handle(ReferenceType::LocalEvents)?,
|
|
- *(event.id),
|
|
|
|
- &[],
|
|
|
|
|
|
+ secondary_index.index_by(&[]),
|
|
|
|
+ &event_id.deref(),
|
|
)?;
|
|
)?;
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
fn store(&self, event: &Event) -> Result<bool, Error> {
|
|
fn store(&self, event: &Event) -> Result<bool, Error> {
|
|
- let event_id = event.id.clone();
|
|
|
|
|
|
+ let event_id = &event.id;
|
|
|
|
|
|
if let Ok(Some(_)) = self.db.get_cf(
|
|
if let Ok(Some(_)) = self.db.get_cf(
|
|
&self.reference_to_cf_handle(ReferenceType::Events)?,
|
|
&self.reference_to_cf_handle(ReferenceType::Events)?,
|
|
- *event_id,
|
|
|
|
|
|
+ event_id.deref(),
|
|
) {
|
|
) {
|
|
return Ok(false);
|
|
return Ok(false);
|
|
}
|
|
}
|
|
- let secondary_index = SecondaryIndex::new(&event_id, event.created_at());
|
|
|
|
- let author_id = secondary_index.new_id(event.author());
|
|
|
|
|
|
+ let secondary_index = SecondaryIndex::new(event_id, event.created_at());
|
|
|
|
+ let author_id = secondary_index.index_by(event.author());
|
|
let json = serde_json::to_vec(event)?;
|
|
let json = serde_json::to_vec(event)?;
|
|
let kind: u32 = event.kind().into();
|
|
let kind: u32 = event.kind().into();
|
|
- let kind_id = secondary_index.new_id(&kind.to_be_bytes());
|
|
|
|
|
|
+ let kind_id = secondary_index.index_by(&kind.to_be_bytes());
|
|
|
|
|
|
let mut buffer = WriteBatch::default();
|
|
let mut buffer = WriteBatch::default();
|
|
|
|
|
|
buffer.put_cf(
|
|
buffer.put_cf(
|
|
&self.reference_to_cf_handle(ReferenceType::Events)?,
|
|
&self.reference_to_cf_handle(ReferenceType::Events)?,
|
|
- *event_id,
|
|
|
|
|
|
+ event_id.deref(),
|
|
json,
|
|
json,
|
|
);
|
|
);
|
|
buffer.put_cf(
|
|
buffer.put_cf(
|
|
&self.reference_to_cf_handle(ReferenceType::Author)?,
|
|
&self.reference_to_cf_handle(ReferenceType::Author)?,
|
|
author_id,
|
|
author_id,
|
|
- *event_id,
|
|
|
|
|
|
+ event_id.deref(),
|
|
);
|
|
);
|
|
buffer.put_cf(
|
|
buffer.put_cf(
|
|
&self.reference_to_cf_handle(ReferenceType::Kind)?,
|
|
&self.reference_to_cf_handle(ReferenceType::Kind)?,
|
|
kind_id,
|
|
kind_id,
|
|
- *event_id,
|
|
|
|
|
|
+ event_id.deref(),
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ buffer.put_cf(
|
|
|
|
+ &self.reference_to_cf_handle(ReferenceType::Stream)?,
|
|
|
|
+ secondary_index.index_by(&[]),
|
|
|
|
+ event_id.deref(),
|
|
);
|
|
);
|
|
|
|
|
|
for tag in event.tags().iter() {
|
|
for tag in event.tags().iter() {
|
|
match tag {
|
|
match tag {
|
|
Tag::PubKey(p) => {
|
|
Tag::PubKey(p) => {
|
|
- let foreign_id = secondary_index.new_id(&p.id);
|
|
|
|
- let local_id = secondary_index.new_id(&event_id);
|
|
|
|
|
|
+ let foreign_id = secondary_index.index_by(&p.id);
|
|
|
|
+ let local_id = secondary_index.index_by(&event_id);
|
|
|
|
|
|
buffer.put_cf(
|
|
buffer.put_cf(
|
|
&self.reference_to_cf_handle(ReferenceType::RefPublicKey)?,
|
|
&self.reference_to_cf_handle(ReferenceType::RefPublicKey)?,
|
|
foreign_id,
|
|
foreign_id,
|
|
- *event_id,
|
|
|
|
|
|
+ event_id.deref(),
|
|
);
|
|
);
|
|
buffer.put_cf(
|
|
buffer.put_cf(
|
|
&self.reference_to_cf_handle(ReferenceType::RefEvent)?,
|
|
&self.reference_to_cf_handle(ReferenceType::RefEvent)?,
|
|
@@ -166,13 +168,13 @@ impl<'a> Storage<'a, ResultSet<'a>> for RocksDb {
|
|
);
|
|
);
|
|
}
|
|
}
|
|
Tag::Event(e) => {
|
|
Tag::Event(e) => {
|
|
- let foreign_id = secondary_index.new_id(&e.id);
|
|
|
|
- let local_id = secondary_index.new_id(&event_id);
|
|
|
|
|
|
+ let foreign_id = secondary_index.index_by(&e.id);
|
|
|
|
+ let local_id = secondary_index.index_by(&event_id);
|
|
|
|
|
|
buffer.put_cf(
|
|
buffer.put_cf(
|
|
&self.reference_to_cf_handle(ReferenceType::RefEvent)?,
|
|
&self.reference_to_cf_handle(ReferenceType::RefEvent)?,
|
|
foreign_id,
|
|
foreign_id,
|
|
- *event_id,
|
|
|
|
|
|
+ event_id.deref(),
|
|
);
|
|
);
|
|
buffer.put_cf(
|
|
buffer.put_cf(
|
|
&self.reference_to_cf_handle(ReferenceType::RefEvent)?,
|
|
&self.reference_to_cf_handle(ReferenceType::RefEvent)?,
|
|
@@ -197,62 +199,68 @@ impl<'a> Storage<'a, ResultSet<'a>> for RocksDb {
|
|
.transpose()?)
|
|
.transpose()?)
|
|
}
|
|
}
|
|
|
|
|
|
- fn get_by_filter(&'a self, mut query: Filter) -> Result<ResultSet<'a>, Error> {
|
|
|
|
|
|
+ fn get_by_filter(&'a self, mut query: Filter) -> Result<WrapperIterator<'a>, Error> {
|
|
let limit = if query.limit == 0 {
|
|
let limit = if query.limit == 0 {
|
|
None
|
|
None
|
|
} else {
|
|
} else {
|
|
Some(query.limit.try_into()?)
|
|
Some(query.limit.try_into()?)
|
|
};
|
|
};
|
|
|
|
|
|
- let (namespace, prefixes) = if !query.references_to_event.is_empty() {
|
|
|
|
- let ns: Arc<BoundColumnFamily<'_>> =
|
|
|
|
- self.reference_to_cf_handle(ReferenceType::RefEvent)?;
|
|
|
|
- let keys = query
|
|
|
|
- .references_to_event
|
|
|
|
- .iter()
|
|
|
|
- .map(|c| c.as_ref().to_vec())
|
|
|
|
- .collect();
|
|
|
|
- query.references_to_event.clear();
|
|
|
|
- (Some(ns), keys)
|
|
|
|
- } else if !query.references_to_public_key.is_empty() {
|
|
|
|
- let ns = self.reference_to_cf_handle(ReferenceType::RefEvent)?;
|
|
|
|
- let keys = query
|
|
|
|
- .references_to_public_key
|
|
|
|
- .iter()
|
|
|
|
- .map(|c| c.as_ref().to_vec())
|
|
|
|
- .collect();
|
|
|
|
- query.references_to_public_key.clear();
|
|
|
|
- (Some(ns), keys)
|
|
|
|
- } else if !query.ids.is_empty() {
|
|
|
|
- let keys = query.ids.iter().map(|c| c.as_ref().to_vec()).collect();
|
|
|
|
- query.ids.clear();
|
|
|
|
- (None, keys)
|
|
|
|
- } else if !query.authors.is_empty() {
|
|
|
|
- let ns = self.reference_to_cf_handle(ReferenceType::Author)?;
|
|
|
|
- let keys = query.authors.iter().map(|c| c.as_ref().to_vec()).collect();
|
|
|
|
- query.authors.clear();
|
|
|
|
- (Some(ns), keys)
|
|
|
|
- } else if !query.kinds.is_empty() {
|
|
|
|
- let ns = self.reference_to_cf_handle(ReferenceType::Kind)?;
|
|
|
|
- let keys = query
|
|
|
|
- .kinds
|
|
|
|
- .iter()
|
|
|
|
- .map(|kind| {
|
|
|
|
- let kind: u32 = (*kind).into();
|
|
|
|
- kind.to_be_bytes().to_vec()
|
|
|
|
- })
|
|
|
|
- .collect();
|
|
|
|
- query.kinds.clear();
|
|
|
|
- (Some(ns), keys)
|
|
|
|
- } else {
|
|
|
|
- (None, VecDeque::new())
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- Ok(ResultSet {
|
|
|
|
|
|
+ let (namespace, secondary_index_iterator, prefixes) =
|
|
|
|
+ if !query.references_to_event.is_empty() {
|
|
|
|
+ let ns: Arc<BoundColumnFamily<'_>> =
|
|
|
|
+ self.reference_to_cf_handle(ReferenceType::RefEvent)?;
|
|
|
|
+ let keys = query
|
|
|
|
+ .references_to_event
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|c| c.as_ref().to_vec())
|
|
|
|
+ .collect();
|
|
|
|
+ query.references_to_event.clear();
|
|
|
|
+ (Some(ns), None, keys)
|
|
|
|
+ } else if !query.references_to_public_key.is_empty() {
|
|
|
|
+ let ns = self.reference_to_cf_handle(ReferenceType::RefEvent)?;
|
|
|
|
+ let keys = query
|
|
|
|
+ .references_to_public_key
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|c| c.as_ref().to_vec())
|
|
|
|
+ .collect();
|
|
|
|
+ query.references_to_public_key.clear();
|
|
|
|
+ (Some(ns), None, keys)
|
|
|
|
+ } else if !query.ids.is_empty() {
|
|
|
|
+ let keys = query.ids.iter().map(|c| c.as_ref().to_vec()).collect();
|
|
|
|
+ query.ids.clear();
|
|
|
|
+ (None, None, keys)
|
|
|
|
+ } else if !query.authors.is_empty() {
|
|
|
|
+ let ns = self.reference_to_cf_handle(ReferenceType::Author)?;
|
|
|
|
+ let keys = query.authors.iter().map(|c| c.as_ref().to_vec()).collect();
|
|
|
|
+ query.authors.clear();
|
|
|
|
+ (Some(ns), None, keys)
|
|
|
|
+ } else if !query.kinds.is_empty() {
|
|
|
|
+ let ns = self.reference_to_cf_handle(ReferenceType::Kind)?;
|
|
|
|
+ let keys = query
|
|
|
|
+ .kinds
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|kind| {
|
|
|
|
+ let kind: u32 = (*kind).into();
|
|
|
|
+ kind.to_be_bytes().to_vec()
|
|
|
|
+ })
|
|
|
|
+ .collect();
|
|
|
|
+ query.kinds.clear();
|
|
|
|
+ (Some(ns), None, keys)
|
|
|
|
+ } else {
|
|
|
|
+ let cf_handle = self.reference_to_cf_handle(ReferenceType::Stream)?;
|
|
|
|
+ (
|
|
|
|
+ None,
|
|
|
|
+ Some(self.db.iterator_cf(&cf_handle, IteratorMode::Start)),
|
|
|
|
+ VecDeque::new(),
|
|
|
|
+ )
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ Ok(WrapperIterator {
|
|
db: self,
|
|
db: self,
|
|
- filter: query.into(),
|
|
|
|
|
|
+ filter: Some(query.into()),
|
|
namespace,
|
|
namespace,
|
|
- secondary_index_lookup: None,
|
|
|
|
|
|
+ secondary_index_iterator,
|
|
current_prefix: vec![],
|
|
current_prefix: vec![],
|
|
prefixes,
|
|
prefixes,
|
|
returned: 0,
|
|
returned: 0,
|
|
@@ -342,4 +350,10 @@ mod test {
|
|
let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
|
|
let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
|
|
test::filter_by_author_and_kinds(&db)
|
|
test::filter_by_author_and_kinds(&db)
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ #[test]
|
|
|
|
+ fn get_local_events() {
|
|
|
|
+ let db = RocksDb::new(format!("tests/db/{}", unique_nanoseconds())).expect("db");
|
|
|
|
+ test::get_local_events(&db)
|
|
|
|
+ }
|
|
}
|
|
}
|