Skip to main content

MetadataStore

Struct MetadataStore 

Source
pub struct MetadataStore { /* private fields */ }
Expand description

High-performance metadata store with indexes

Implementations§

Source§

impl MetadataStore

Source

pub fn new() -> Self

Create new metadata store

Source

pub fn with_capacity(max_capacity: usize) -> Self

Create store with capacity limit

Source

pub fn upsert(&self, metadata: NodeMetadata) -> Result<(), MetadataError>

Insert or update node metadata

The entire (read-old, remove-from-indexes, add-to-indexes, insert) sequence runs inside DashMap::entry’s shard write lock, serializing all concurrent upserts on the same node_id. Splitting this into a 5-step sequence without an overarching lock — (1) capacity check, (2) nodes.get(&id), (3) remove_from_indexes(&old), (4) add_to_indexes(&new), (5) nodes.insert — would let two concurrent upserts on the same node both observe the same old at step 2, both remove its index entries at step 3 (second a no-op), and both add to indexes at step 4 into DIFFERENT buckets if the metadata differed. Whichever nodes.insert landed second would win, but the loser’s index entries would never be removed, producing permanent index drift (queries return the node under the wrong filter; stats over-count).

Source

pub fn update_versioned( &self, metadata: NodeMetadata, expected_version: u64, ) -> Result<(), MetadataError>

Update with version check (optimistic locking)

Source

pub fn get(&self, node_id: &NodeId) -> Option<Arc<NodeMetadata>>

Get node metadata

Source

pub fn remove(&self, node_id: &NodeId) -> Option<Arc<NodeMetadata>>

Remove node

Source

pub fn query(&self, query: &MetadataQuery) -> Vec<Arc<NodeMetadata>>

Query nodes

Source

pub fn find_nearby( &self, location: &LocationInfo, max_distance_km: f64, limit: usize, ) -> Vec<(Arc<NodeMetadata>, f64)>

Find nodes near a location

Source

pub fn find_best_for_routing(&self, limit: usize) -> Vec<Arc<NodeMetadata>>

Find best nodes for routing

Source

pub fn find_relays(&self) -> Vec<Arc<NodeMetadata>>

Find relay nodes

Source

pub fn stats(&self) -> MetadataStoreStats

Get statistics

Source

pub fn len(&self) -> usize

Number of nodes

Source

pub fn is_empty(&self) -> bool

Check if empty

Source

pub fn clear(&self)

Clear all nodes

Drains nodes FIRST and routes every drained metadata through remove_from_indexes — making the intermediate state consistent (nodes exist alongside their indexes throughout the drain). A naive nodes.clear() followed by six index clear()s in sequence would let a concurrent upsert landing between any two of those clears observe nodes.get(&id) → None (skipping remove_from_indexes), then add_to_indexes (writing into the SAME index maps clear is about to wipe), then nodes.insert(...) — the final state would be a node in nodes with NO index entries, invisible to every indexed query and only retrievable via the full-scan branch.

With the drain-first ordering, any concurrent upsert landing during the drain either races BEFORE this function reads its key (the upsert wins; we drain its entry afterward) or AFTER (the upsert observes a cleared nodes and proceeds normally — no index drift, since remove_from_indexes only touches keys that exist in nodes). The final clears on the index maps catch any residual entries the per-key path missed (defense-in-depth; should be no-ops on the happy path).

Trait Implementations§

Source§

impl Default for MetadataStore

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more