1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT license.
*/
//! The working-set is a core scratch data structure used during pruning.
//!
//! # Overview
//!
//! This interface consists of two traits for all insert types and one additional trait for
//! batch operations like [`multi_insert`](crate::graph::DiskANNIndex::multi_insert).
//! These are summarized below.
//!
//! * [`View`] (all inserts): Read-only random access to cached data. Data access should
//! be reasonably efficient.
//!
//! * [`Fill`] (all inserts): Extension point for fetching data associated with internal IDs
//! and producing a [`View`] to access the retrieved data. This trait uses an opaque
//! `WorkingSet` that implementations are free to use in any way they see fit.
//!
//! * [`AsWorkingSet`] (bulk operations): Deferred creation of a `WorkingSet` to pass to
//! [`Fill`]. This allows [`MultiInsertStrategy`](crate::graph::glue::MultiInsertStrategy)
//! to seed [`View`]s with elements of the input.
//!
//! Traits that produce and otherwise interact with working sets are:
//!
//! * [`PruneStrategy`](crate::graph::glue::PruneStrategy): Creates a `WorkingSet` opaque type.
//! * [`MultiInsertStrategy`](crate::graph::glue::MultiInsertStrategy): Creates an implementation
//! of [`AsWorkingSet`] to defer creation of the final `WorkingSet` until needed by worker
//! tasks.
//!
//! # Implementation Strategies
//!
//! The `WorkingSet` type passed to [`Fill`] is opaque. Instead only the returned [`View`]
//! is accessed directly. This enables the following implementation strategies:
//!
//! * Allocate in `WorkingSet`, making `View` a shallow wrapper. This is the most
//! straightforward approach. Elements are stored directly in `WorkingSet` and the accessor
//! simply populates data.
//!
//! * Allocate in `Accessor`: Another approach is to allocate scratch space directly in `Self`
//! for the elements in `itr`. This works since [`Fill::View`] borrows from `Self`.
//!
//! * Passthrough: If random access into the [`Accessor`] is synchronous and fast, then an
//! implementation of [`View`] can simply reach through the [`Accessor`], use zero-sized
//! types for the `WorkingSet`, and avoid allocation entirely.
//!
//! Within these, there are multiple strategies as well. For example, if data is known to
//! be standard slices of standard types, then an implementation of `WorkingSet` can pack
//! this data contiguously in memory for better memory locality.
//!
//! # Reuse in a `WorkingSet`
//!
//! Any particular `WorkingSet` can be reused across multiple prunes. It's up to the
//! [`Accessor`] implementation to decide whether this reuse can serve as a cache for vectors
//! or not. The default implementation [`Map`] offers both cached and uncached modes.
//!
//! Trade offs include:
//!
//! * Without any cross-fill reuse, more vector retrievals are made, but the data in the
//! associated [`View`] is up-to-date.
//!
//! * With cross-fill reuse, the memory used by the working set increases.
//!
//! Working sets are used in the indexing algorithm within fairly tight temporal windows so
//! the risk of stale entries in the cache causing incorrect graphs is minimal.
use ;
use crate::;
/////////////
// Exports //
/////////////
pub use Map;
////////////
// Traits //
////////////
/// Populate a `WorkingSet` with data from an accessor and return a [`View`] over the set.
///
/// For each `i` in `itr` - the accessor should make the data behind `i` available, either
/// by storing it in `working_set` or through direct storage in the returned [`View`].
///
/// The `WorkingSet` type is constructed by either:
///
/// * [`PruneStrategy`](crate::graph::glue::PruneStrategy::create_working_set): Direct
/// construction of a working set for use in multiple prunes.
///
/// * [`MultiInsertStrategy::Seed`](crate::graph::glue::MultiInsertStrategy::Seed): Indirect
/// creation that uses [`AsWorkingSet`] for the final conversion. This allows the elements
/// in the input batch to [`multi_insert`](crate::graph::DiskANNIndex::multi_insert) to be
/// directly accessible by the `WorkingSet`/[`View`] types.
///
/// See Also: [`View`], [`AsWorkingSet`], [`Map`].