Skip to main content

qdrant_edge/edge/read_view/
shard_read.rs

1use std::path::Path;
2use std::sync::Arc;
3
4use rayon::ThreadPool;
5use crate::segment::common::operation_error::OperationResult;
6use crate::segment::data_types::facets::FacetResponse;
7use crate::segment::types::{PointIdType, ScoredPoint};
8use crate::shard::retrieve::record_internal::RecordInternal;
9
10use super::{EdgeReadView, Group, ReadSegmentHandle, SearchMatrixResponse, ShardInfo};
11use crate::edge::EdgeConfig;
12use crate::edge::requests::{
13    CountRequest, FacetRequest, GroupRequest, QueryRequest, RetrieveRequest, ScrollRequest,
14    SearchMatrixRequest, SearchRequest,
15};
16
17mod sealed {
18    /// Empty marker supertrait of [`EdgeShardRead`](super::EdgeShardRead). Unnameable outside the
19    /// crate, so downstream crates cannot implement `EdgeShardRead`; it carries no methods, so
20    /// nothing internal becomes callable through it.
21    pub trait Sealed {}
22}
23
24impl<T: ReadViewProvider + ?Sized> sealed::Sealed for T {}
25
26/// The snapshot half of the read path: how a shard exposes its segments, search pool, and config
27/// for the shared read logic. Crate-private plumbing — [`EdgeShardRead`] is implemented for every
28/// provider through a blanket impl, so these methods never appear on the public trait.
29pub(crate) trait ReadViewProvider {
30    /// Concrete segment handle backing this shard. A follower uses the monomorphic
31    /// `Arc<RwLock<ReadOnlySegment<S>>>`; the read-write shard uses `LockedSegment`.
32    type Handle: ReadSegmentHandle;
33
34    /// Snapshot the current segments in retrieval order (non-appendable first, then appendable).
35    fn read_segments(&self) -> Vec<Self::Handle>;
36
37    /// Snapshot the current config.
38    fn config_snapshot(&self) -> Arc<EdgeConfig>;
39
40    /// The shard's search thread pool, used to run per-segment reads in parallel.
41    fn search_pool(&self) -> Arc<ThreadPool>;
42
43    fn path(&self) -> &Path;
44}
45
46/// Read API shared by the read-write [`EdgeShard`](crate::EdgeShard) and the read-only follower
47/// shard.
48///
49/// Every method takes its edge request type from [`crate::requests`]; the blanket impl converts
50/// it into the internal request the read logic executes.
51///
52/// A shard only implements the crate-private snapshot provider; this trait comes for free through
53/// a blanket impl whose methods build an [`EdgeReadView`] from that snapshot and run the shared
54/// logic, so the read code is never duplicated and the snapshot plumbing stays invisible to crate
55/// users. Sealed: cannot be implemented outside the crate.
56pub trait EdgeShardRead: sealed::Sealed {
57    /// Snapshot the current config.
58    fn config_snapshot(&self) -> Arc<EdgeConfig>;
59
60    fn path(&self) -> &Path;
61
62    /// This method is DEPRECATED and should be replaced with query.
63    fn search(&self, request: SearchRequest) -> OperationResult<Vec<ScoredPoint>>;
64
65    fn query(&self, request: QueryRequest) -> OperationResult<Vec<ScoredPoint>>;
66
67    fn scroll(
68        &self,
69        request: ScrollRequest,
70    ) -> OperationResult<(Vec<RecordInternal>, Option<PointIdType>)>;
71
72    fn retrieve(&self, request: RetrieveRequest) -> OperationResult<Vec<RecordInternal>>;
73
74    fn count(&self, request: CountRequest) -> OperationResult<usize>;
75
76    fn facet(&self, request: FacetRequest) -> OperationResult<FacetResponse>;
77
78    fn search_matrix(&self, request: SearchMatrixRequest) -> OperationResult<SearchMatrixResponse>;
79
80    fn query_groups(&self, request: GroupRequest) -> OperationResult<Vec<Group>>;
81
82    fn info(&self) -> OperationResult<ShardInfo>;
83}
84
85impl<T: ReadViewProvider + ?Sized> EdgeShardRead for T {
86    fn config_snapshot(&self) -> Arc<EdgeConfig> {
87        ReadViewProvider::config_snapshot(self)
88    }
89
90    fn path(&self) -> &Path {
91        ReadViewProvider::path(self)
92    }
93
94    fn search(&self, request: SearchRequest) -> OperationResult<Vec<ScoredPoint>> {
95        view(self).search(request.into())
96    }
97
98    fn query(&self, request: QueryRequest) -> OperationResult<Vec<ScoredPoint>> {
99        view(self).query(request.into())
100    }
101
102    fn scroll(
103        &self,
104        request: ScrollRequest,
105    ) -> OperationResult<(Vec<RecordInternal>, Option<PointIdType>)> {
106        view(self).scroll(request.into())
107    }
108
109    fn retrieve(&self, request: RetrieveRequest) -> OperationResult<Vec<RecordInternal>> {
110        let RetrieveRequest {
111            point_ids,
112            with_payload,
113            with_vector,
114        } = request;
115        view(self).retrieve(&point_ids, with_payload, with_vector)
116    }
117
118    fn count(&self, request: CountRequest) -> OperationResult<usize> {
119        view(self).count(request.into())
120    }
121
122    fn facet(&self, request: FacetRequest) -> OperationResult<FacetResponse> {
123        view(self).facet(request.into())
124    }
125
126    fn search_matrix(&self, request: SearchMatrixRequest) -> OperationResult<SearchMatrixResponse> {
127        view(self).search_matrix(request)
128    }
129
130    fn query_groups(&self, request: GroupRequest) -> OperationResult<Vec<Group>> {
131        view(self).query_groups(request)
132    }
133
134    fn info(&self) -> OperationResult<ShardInfo> {
135        view(self).info()
136    }
137}
138
139/// Build a one-shot read snapshot for a shard. Private so it is not part of the trait's surface —
140/// the snapshot is an implementation detail of the blanket [`EdgeShardRead`] impl.
141fn view<T: ReadViewProvider + ?Sized>(shard: &T) -> EdgeReadView<T::Handle> {
142    EdgeReadView::new(
143        shard.read_segments(),
144        shard.config_snapshot(),
145        shard.search_pool(),
146    )
147}