Skip to content

Commit 2439a3d

Browse files
committed
nostr: move tag::indexes to nostr-database
Remove `Filter::match_event` and everything related.
1 parent 0663ced commit 2439a3d

File tree

11 files changed

+83
-332
lines changed

11 files changed

+83
-332
lines changed

Cargo.lock

Lines changed: 6 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindings/nostr-ffi/src/message/subscription.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use uniffi::{Enum, Object};
1111

1212
use crate::error::Result;
1313
use crate::helper::unwrap_or_clone_arc;
14-
use crate::{Event, EventId, PublicKey, Timestamp};
14+
use crate::{EventId, PublicKey, Timestamp};
1515

1616
#[derive(Enum)]
1717
pub enum Alphabet {
@@ -324,10 +324,6 @@ impl Filter {
324324
Arc::new(builder)
325325
}
326326

327-
pub fn match_event(&self, event: Arc<Event>) -> bool {
328-
self.inner.match_event(event.as_ref().deref())
329-
}
330-
331327
pub fn is_empty(&self) -> bool {
332328
self.inner.is_empty()
333329
}

crates/nostr-database/src/index.rs

Lines changed: 52 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,19 @@
55
//! Nostr Database Indexes
66
77
use std::cmp::Ordering;
8-
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
9-
//use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
8+
use std::collections::{BTreeSet, HashMap, HashSet};
109
use std::sync::Arc;
1110

1211
use nostr::event::id;
1312
use nostr::nips::nip01::Coordinate;
1413
use nostr::secp256k1::XOnlyPublicKey;
15-
use nostr::{
16-
Alphabet, Event, EventId, Filter, GenericTagValue, Kind, TagIndexValues, TagIndexes, Timestamp,
17-
};
14+
use nostr::{Alphabet, Event, EventId, Filter, GenericTagValue, Kind, Timestamp};
1815
use rayon::prelude::*;
1916
use thiserror::Error;
2017
use tokio::sync::RwLock;
2118

2219
use crate::raw::RawEvent;
20+
use crate::tag_indexes::{TagIndexValues, TagIndexes};
2321

2422
/// Public Key Prefix Size
2523
const PUBLIC_KEY_PREFIX_SIZE: usize = 8;
@@ -81,32 +79,11 @@ impl From<&Event> for EventIndex {
8179
event_id: e.id,
8280
pubkey: PublicKeyPrefix::from(e.pubkey),
8381
kind: e.kind,
84-
tags: e.build_tags_index(),
82+
tags: TagIndexes::from(e.tags.iter().map(|t| t.as_vec())),
8583
}
8684
}
8785
}
8886

89-
impl EventIndex {
90-
fn filter_tags_match(&self, filter: &FilterIndex) -> bool {
91-
if filter.generic_tags.is_empty() {
92-
return true;
93-
}
94-
95-
if self.tags.is_empty() {
96-
return false;
97-
}
98-
99-
filter.generic_tags.iter().all(|(tagname, set)| {
100-
self.tags.get(tagname).map_or(false, |valset| {
101-
TagIndexValues::iter(set)
102-
.filter(|t| valset.contains(t))
103-
.count()
104-
> 0
105-
})
106-
})
107-
}
108-
}
109-
11087
/// Public Key prefix
11188
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
11289
struct PublicKeyPrefix([u8; PUBLIC_KEY_PREFIX_SIZE]);
@@ -134,12 +111,12 @@ impl From<[u8; 32]> for PublicKeyPrefix {
134111

135112
#[derive(Default)]
136113
struct FilterIndex {
137-
ids: BTreeSet<EventId>,
138-
authors: BTreeSet<PublicKeyPrefix>,
139-
kinds: BTreeSet<Kind>,
114+
ids: HashSet<EventId>,
115+
authors: HashSet<PublicKeyPrefix>,
116+
kinds: HashSet<Kind>,
140117
since: Option<Timestamp>,
141118
until: Option<Timestamp>,
142-
generic_tags: BTreeMap<Alphabet, BTreeSet<GenericTagValue>>,
119+
generic_tags: HashMap<Alphabet, BTreeSet<GenericTagValue>>,
143120
}
144121

145122
impl FilterIndex {
@@ -167,21 +144,60 @@ impl FilterIndex {
167144
.insert(identifier);
168145
self
169146
}
147+
148+
fn ids_match(&self, event: &EventIndex) -> bool {
149+
self.ids.is_empty() || self.ids.contains(&event.event_id)
150+
}
151+
152+
fn authors_match(&self, event: &EventIndex) -> bool {
153+
self.authors.is_empty() || self.authors.contains(&event.pubkey)
154+
}
155+
156+
fn tag_match(&self, event: &EventIndex) -> bool {
157+
if self.generic_tags.is_empty() {
158+
return true;
159+
}
160+
if event.tags.is_empty() {
161+
return false;
162+
}
163+
164+
self.generic_tags.iter().all(|(tagname, set)| {
165+
event.tags.get(tagname).map_or(false, |valset| {
166+
TagIndexValues::iter(set.iter())
167+
.filter(|t| valset.contains(t))
168+
.count()
169+
> 0
170+
})
171+
})
172+
}
173+
174+
fn kind_match(&self, kind: &Kind) -> bool {
175+
self.kinds.is_empty() || self.kinds.contains(kind)
176+
}
177+
178+
pub fn match_event(&self, event: &EventIndex) -> bool {
179+
self.ids_match(event)
180+
&& self.since.map_or(true, |t| event.created_at >= t)
181+
&& self.until.map_or(true, |t| event.created_at <= t)
182+
&& self.kind_match(&event.kind)
183+
&& self.authors_match(event)
184+
&& self.tag_match(event)
185+
}
170186
}
171187

172188
impl From<Filter> for FilterIndex {
173189
fn from(value: Filter) -> Self {
174190
Self {
175-
ids: value.ids,
191+
ids: value.ids.into_iter().collect(),
176192
authors: value
177193
.authors
178194
.into_iter()
179195
.map(PublicKeyPrefix::from)
180196
.collect(),
181-
kinds: value.kinds,
197+
kinds: value.kinds.into_iter().collect(),
182198
since: value.since,
183199
until: value.until,
184-
generic_tags: value.generic_tags,
200+
generic_tags: value.generic_tags.into_iter().collect(),
185201
}
186202
}
187203
}
@@ -468,61 +484,11 @@ impl DatabaseIndexes {
468484
T: Into<FilterIndex>,
469485
{
470486
let filter: FilterIndex = filter.into();
471-
index.par_iter().filter(move |m| {
472-
!deleted_ids.contains(&m.event_id)
473-
&& filter.until.map_or(true, |t| m.created_at <= t)
474-
&& filter.since.map_or(true, |t| m.created_at >= t)
475-
&& (filter.ids.is_empty() || filter.ids.contains(&m.event_id))
476-
&& (filter.authors.is_empty() || filter.authors.contains(&m.pubkey))
477-
&& (filter.kinds.is_empty() || filter.kinds.contains(&m.kind))
478-
&& m.filter_tags_match(&filter)
487+
index.par_iter().filter(move |event| {
488+
!deleted_ids.contains(&event.event_id) && filter.match_event(event)
479489
})
480490
}
481491

482-
/* fn internal_multi_parallel_query<'a, I, T>(
483-
&self,
484-
index: &'a BTreeSet<EventIndex>,
485-
deleted: &'a HashSet<EventId>,
486-
filters: I,
487-
) -> impl ParallelIterator<Item = &'a EventIndex>
488-
where
489-
I: IntoIterator<Item = T>,
490-
T: Into<FilterIndex>,
491-
{
492-
let filters: Vec<FilterIndex> = filters.into_iter().map(|f| f.into()).collect();
493-
let limits: Vec<Option<usize>> = filters.iter().map(|f| f.limit).collect();
494-
let counter: Vec<AtomicUsize> = filters.iter().map(|_| AtomicUsize::new(0)).collect();
495-
index
496-
.par_iter()
497-
.filter(move |i| !deleted.contains(&i.event_id))
498-
.filter(move |i| {
499-
filters.par_iter().enumerate().any(|(index, filter)| {
500-
if let Some(Some(limit)) = limits.get(index) {
501-
if let Some(counter) = counter.get(index) {
502-
if counter.load(AtomicOrdering::SeqCst) >= *limit {
503-
return false;
504-
}
505-
}
506-
}
507-
508-
let status: bool = filter.until.map_or(true, |t| i.created_at <= t)
509-
&& filter.since.map_or(true, |t| i.created_at >= t)
510-
&& (filter.ids.is_empty() || filter.ids.contains(&i.event_id))
511-
&& (filter.authors.is_empty() || filter.authors.contains(&i.pubkey))
512-
&& (filter.kinds.is_empty() || filter.kinds.contains(&i.kind))
513-
&& i.filter_tags_match(&filter);
514-
515-
if status {
516-
if let Some(counter) = counter.get(index) {
517-
counter.fetch_add(1, AtomicOrdering::SeqCst);
518-
}
519-
}
520-
521-
status
522-
})
523-
})
524-
} */
525-
526492
/// Query
527493
#[tracing::instrument(skip_all, level = "trace")]
528494
pub async fn query<I>(&self, filters: I) -> Vec<EventId>

crates/nostr-database/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub mod memory;
2525
mod options;
2626
pub mod profile;
2727
mod raw;
28+
mod tag_indexes;
2829

2930
pub use self::error::DatabaseError;
3031
#[cfg(feature = "flatbuf")]

crates/nostr-database/src/memory.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::sync::Arc;
99

1010
use async_trait::async_trait;
1111
use nostr::nips::nip01::Coordinate;
12-
use nostr::{Event, EventId, Filter, FiltersMatchEvent, Timestamp, Url};
12+
use nostr::{Event, EventId, Filter, Timestamp, Url};
1313
use tokio::sync::RwLock;
1414

1515
use crate::{
@@ -167,15 +167,13 @@ impl NostrDatabase for MemoryDatabase {
167167
#[tracing::instrument(skip_all, level = "trace")]
168168
async fn query(&self, filters: Vec<Filter>) -> Result<Vec<Event>, Self::Err> {
169169
if self.opts.events {
170-
let ids = self.indexes.query(filters.clone()).await;
170+
let ids = self.indexes.query(filters).await;
171171
let events = self.events.read().await;
172172

173173
let mut list: Vec<Event> = Vec::new();
174174
for event_id in ids.into_iter() {
175-
if let Some(event) = events.get(&event_id) {
176-
if filters.match_event(event) {
177-
list.push(event.clone());
178-
}
175+
if let Some(event) = events.get(&event_id).cloned() {
176+
list.push(event);
179177
}
180178
}
181179
Ok(list)

crates/nostr/src/event/tag/indexes.rs renamed to crates/nostr-database/src/tag_indexes.rs

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,24 @@
44

55
//! Tag Indexes
66
7-
use alloc::string::{String, ToString};
8-
use alloc::vec::Vec;
7+
use std::collections::{HashMap, HashSet};
8+
use std::ops::{Deref, DerefMut};
99

10-
use alloc::collections::{BTreeMap, BTreeSet};
11-
use core::ops::{Deref, DerefMut};
12-
13-
use bitcoin::hashes::siphash24::Hash as SipHash24;
14-
use bitcoin::hashes::Hash;
15-
16-
use crate::{Alphabet, GenericTagValue};
10+
use nostr::hashes::siphash24::Hash as SipHash24;
11+
use nostr::hashes::Hash;
12+
use nostr::{Alphabet, GenericTagValue};
1713

1814
/// Tag Index Value Size
1915
pub const TAG_INDEX_VALUE_SIZE: usize = 8;
2016

2117
/// Tag Indexes
2218
#[derive(Debug, Clone, Default, PartialEq, Eq)]
2319
pub struct TagIndexes {
24-
inner: BTreeMap<Alphabet, TagIndexValues>,
20+
inner: HashMap<Alphabet, TagIndexValues>,
2521
}
2622

2723
impl Deref for TagIndexes {
28-
type Target = BTreeMap<Alphabet, TagIndexValues>;
24+
type Target = HashMap<Alphabet, TagIndexValues>;
2925
fn deref(&self) -> &Self::Target {
3026
&self.inner
3127
}
@@ -76,11 +72,11 @@ where
7672
/// Tag Index Values
7773
#[derive(Debug, Clone, Default, PartialEq, Eq)]
7874
pub struct TagIndexValues {
79-
inner: BTreeSet<[u8; TAG_INDEX_VALUE_SIZE]>,
75+
inner: HashSet<[u8; TAG_INDEX_VALUE_SIZE]>,
8076
}
8177

8278
impl Deref for TagIndexValues {
83-
type Target = BTreeSet<[u8; TAG_INDEX_VALUE_SIZE]>;
79+
type Target = HashSet<[u8; TAG_INDEX_VALUE_SIZE]>;
8480
fn deref(&self) -> &Self::Target {
8581
&self.inner
8682
}
@@ -94,10 +90,11 @@ impl DerefMut for TagIndexValues {
9490

9591
impl TagIndexValues {
9692
#[allow(missing_docs)]
97-
pub fn iter(
98-
set: &BTreeSet<GenericTagValue>,
99-
) -> impl Iterator<Item = [u8; TAG_INDEX_VALUE_SIZE]> + '_ {
100-
set.iter().map(|value| {
93+
pub fn iter<'a, I>(iter: I) -> impl Iterator<Item = [u8; TAG_INDEX_VALUE_SIZE]> + 'a
94+
where
95+
I: Iterator<Item = &'a GenericTagValue> + 'a,
96+
{
97+
iter.map(|value| {
10198
let s: String = value.to_string();
10299
hash(s)
103100
})

0 commit comments

Comments
 (0)