client-query-cache 0.9.1__tar.gz → 0.10.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/PKG-INFO +1 -1
  2. client_query_cache-0.10.0/native/shared-index/src/key_encoder.rs +224 -0
  3. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/lib.rs +4 -0
  4. client_query_cache-0.10.0/native/shared-index/src/local_cache.rs +2872 -0
  5. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/python.rs +4 -0
  6. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/pyproject.toml +4 -1
  7. client_query_cache-0.10.0/src/client_query_cache/_core/contracts.pyi +209 -0
  8. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/cursor_capture.py +3 -3
  9. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/entries.py +4 -0
  10. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/manager.py +28 -12
  11. client_query_cache-0.10.0/src/client_query_cache/_core/native.py +121 -0
  12. client_query_cache-0.9.1/src/client_query_cache/_core/residency.py → client_query_cache-0.10.0/src/client_query_cache/_core/residency.pyi +8 -20
  13. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/stream_events.py +1 -1
  14. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_shared/adapters.py +20 -24
  15. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_shared/shared_index.py +5 -1
  16. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_shared/wire.py +49 -2
  17. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_shared_index.pyi +21 -0
  18. {client_query_cache-0.9.1/src/client_query_cache/synchronous → client_query_cache-0.10.0/src/client_query_cache/asynchronous}/__init__.py +2 -1
  19. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/asynchronous/manager.py +1 -1
  20. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/asynchronous/streams.py +1 -1
  21. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/shared.py +5 -2
  22. {client_query_cache-0.9.1/src/client_query_cache/asynchronous → client_query_cache-0.10.0/src/client_query_cache/synchronous}/__init__.py +2 -1
  23. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/synchronous/manager.py +1 -1
  24. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/synchronous/streams.py +1 -1
  25. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/LICENSE +0 -0
  26. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/README.md +0 -0
  27. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/Cargo.lock +0 -0
  28. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/Cargo.toml +0 -0
  29. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/deny.toml +0 -0
  30. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/clock.rs +0 -0
  31. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/echo/tests.rs +0 -0
  32. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/echo.rs +0 -0
  33. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/frames/tests.rs +0 -0
  34. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/frames.rs +0 -0
  35. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/hash/tests.rs +0 -0
  36. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/hash.rs +0 -0
  37. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/index/support_tests.rs +0 -0
  38. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/index/tests.rs +0 -0
  39. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/index.rs +0 -0
  40. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/memory/support_tests.rs +0 -0
  41. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/memory/tests.rs +0 -0
  42. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/memory.rs +0 -0
  43. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/relay/tests.rs +0 -0
  44. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/relay.rs +0 -0
  45. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/ring/tests.rs +0 -0
  46. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/ring.rs +0 -0
  47. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/native/shared-index/src/sync.rs +0 -0
  48. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/__init__.py +0 -0
  49. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/__init__.py +0 -0
  50. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/canonical.py +0 -0
  51. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/codec.py +0 -0
  52. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/collation.py +0 -0
  53. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/collection_metadata.py +0 -0
  54. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/count_reads.py +0 -0
  55. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/errors.py +0 -0
  56. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/find_one_reads.py +0 -0
  57. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/find_reads.py +0 -0
  58. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/identity_reads.py +0 -0
  59. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/keys.py +0 -0
  60. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/lifecycle.py +0 -0
  61. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/locking.py +0 -0
  62. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/lru.py +0 -0
  63. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/namespace.py +0 -0
  64. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/namespace_metadata.py +0 -0
  65. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/order_sensitive_keys.py +0 -0
  66. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/projection.py +0 -0
  67. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/query_filters.py +0 -0
  68. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/read_classification.py +0 -0
  69. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/read_validation.py +0 -0
  70. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/snapshots.py +0 -0
  71. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/stream_activation.py +0 -0
  72. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/stream_cost.py +0 -0
  73. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/stream_health.py +0 -0
  74. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/stream_options.py +0 -0
  75. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/stream_startup.py +0 -0
  76. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/traversal.py +0 -0
  77. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_core/unique_keys.py +0 -0
  78. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_shared/__init__.py +0 -0
  79. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_shared/attachment.py +0 -0
  80. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_shared/coordinator.py +0 -0
  81. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/_types.py +0 -0
  82. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/asynchronous/collection.py +0 -0
  83. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/asynchronous/cursors.py +0 -0
  84. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/asynchronous/database.py +0 -0
  85. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/asynchronous/shared.py +0 -0
  86. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/otel.py +0 -0
  87. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/py.typed +0 -0
  88. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/synchronous/collection.py +0 -0
  89. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/synchronous/cursors.py +0 -0
  90. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/synchronous/database.py +0 -0
  91. {client_query_cache-0.9.1 → client_query_cache-0.10.0}/src/client_query_cache/synchronous/shared.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: client-query-cache
3
- Version: 0.9.1
3
+ Version: 0.10.0
4
4
  Classifier: Framework :: AsyncIO
5
5
  Classifier: Operating System :: POSIX :: Linux
6
6
  Classifier: Programming Language :: Python :: Implementation :: CPython
@@ -0,0 +1,224 @@
1
+ //! The shared key envelope follows https://bsonspec.org/spec.html. Specialized
2
+ //! scalar representations stay with the Python wire codec and PyMongo's encoder.
3
+ use pyo3::exceptions::{PyOverflowError, PyValueError};
4
+ use pyo3::prelude::*;
5
+ use pyo3::types::{PyBool, PyBytes, PyDict, PyFloat, PyInt, PyString, PyTuple};
6
+
7
+ type FindKeys<'py> = (Bound<'py, PyBytes>, Bound<'py, PyBytes>);
8
+
9
+ struct Recursion;
10
+
11
+ impl Recursion {
12
+ fn enter(py: Python<'_>) -> PyResult<Self> {
13
+ // CPython's recursion guard covers calls crossing the extension boundary.
14
+ if unsafe { pyo3::ffi::Py_EnterRecursiveCall(c" while encoding a cache key".as_ptr()) } != 0
15
+ {
16
+ return Err(PyErr::fetch(py));
17
+ }
18
+ Ok(Self)
19
+ }
20
+ }
21
+
22
+ impl Drop for Recursion {
23
+ fn drop(&mut self) {
24
+ unsafe { pyo3::ffi::Py_LeaveRecursiveCall() };
25
+ }
26
+ }
27
+
28
+ fn encoded_value(encoded: &[u8]) -> PyResult<(u8, &[u8])> {
29
+ match encoded {
30
+ [a, b, c, d, kind, b'k', 0, payload @ .., 0]
31
+ if usize::try_from(i32::from_le_bytes([*a, *b, *c, *d])).ok()
32
+ == Some(encoded.len()) =>
33
+ {
34
+ Ok((*kind, payload))
35
+ }
36
+ _ => Err(PyValueError::new_err("invalid encoded key envelope")),
37
+ }
38
+ }
39
+
40
+ fn length(value: usize) -> PyResult<[u8; 4]> {
41
+ i32::try_from(value)
42
+ .map(i32::to_le_bytes)
43
+ .map_err(|_| PyOverflowError::new_err("cache key exceeds BSON length"))
44
+ }
45
+
46
+ fn start(buffer: &mut Vec<u8>) -> usize {
47
+ let offset = buffer.len();
48
+ buffer.extend_from_slice(&[0; 4]);
49
+ offset
50
+ }
51
+
52
+ fn finish(buffer: &mut Vec<u8>, offset: usize) -> PyResult<()> {
53
+ buffer.push(0);
54
+ let size = length(buffer.len() - offset)?;
55
+ buffer[offset..offset + 4].copy_from_slice(&size);
56
+ Ok(())
57
+ }
58
+
59
+ fn header(buffer: &mut Vec<u8>, kind: u8, name: &str) {
60
+ buffer.push(kind);
61
+ buffer.extend_from_slice(name.as_bytes());
62
+ buffer.push(0);
63
+ }
64
+
65
+ fn string(buffer: &mut Vec<u8>, name: &str, value: &str) -> PyResult<()> {
66
+ header(buffer, 2, name);
67
+ buffer.extend_from_slice(&length(value.len() + 1)?);
68
+ buffer.extend_from_slice(value.as_bytes());
69
+ buffer.push(0);
70
+ Ok(())
71
+ }
72
+
73
+ fn tagged(buffer: &mut Vec<u8>, name: &str, tag: &str) -> PyResult<usize> {
74
+ header(buffer, 3, name);
75
+ let offset = start(buffer);
76
+ string(buffer, "t", tag)?;
77
+ Ok(offset)
78
+ }
79
+
80
+ fn tuple(buffer: &mut Vec<u8>, name: &str) -> PyResult<(usize, usize)> {
81
+ let document = tagged(buffer, name, "tuple")?;
82
+ header(buffer, 4, "p");
83
+ Ok((document, start(buffer)))
84
+ }
85
+
86
+ fn finish_tuple(buffer: &mut Vec<u8>, offsets: (usize, usize)) -> PyResult<()> {
87
+ finish(buffer, offsets.1)?;
88
+ finish(buffer, offsets.0)
89
+ }
90
+
91
+ #[pyclass(frozen)]
92
+ pub(crate) struct FindKeyEncoder {
93
+ tags: Vec<(usize, String)>,
94
+ }
95
+
96
+ impl FindKeyEncoder {
97
+ fn node(
98
+ &self,
99
+ buffer: &mut Vec<u8>,
100
+ name: &str,
101
+ value: &Bound<'_, PyAny>,
102
+ scalar_encoder: &Bound<'_, PyAny>,
103
+ ) -> PyResult<()> {
104
+ if let Ok(items) = value.cast::<PyTuple>() {
105
+ let _recursion = Recursion::enter(value.py())?;
106
+ let offsets = tuple(buffer, name)?;
107
+ for (index, item) in items.iter().enumerate() {
108
+ self.node(buffer, &index.to_string(), &item, scalar_encoder)?;
109
+ }
110
+ return finish_tuple(buffer, offsets);
111
+ }
112
+ if value.is_none() {
113
+ header(buffer, 10, name);
114
+ } else if value.is_exact_instance_of::<PyBool>() {
115
+ header(buffer, 8, name);
116
+ buffer.push(u8::from(value.extract::<bool>()?));
117
+ } else if value.is_exact_instance_of::<PyInt>() {
118
+ if let Ok(integer) = value.extract::<i64>() {
119
+ let offset = tagged(buffer, name, "int")?;
120
+ header(buffer, 18, "p");
121
+ buffer.extend_from_slice(&integer.to_le_bytes());
122
+ finish(buffer, offset)?;
123
+ } else {
124
+ scalar(buffer, name, value, scalar_encoder)?;
125
+ }
126
+ } else if value.is_exact_instance_of::<PyString>() {
127
+ string(buffer, name, value.cast::<PyString>()?.to_str()?)?;
128
+ } else if value.is_exact_instance_of::<PyBytes>() {
129
+ let bytes = value.cast::<PyBytes>()?.as_bytes();
130
+ header(buffer, 5, name);
131
+ buffer.extend_from_slice(&length(bytes.len())?);
132
+ buffer.push(0);
133
+ buffer.extend_from_slice(bytes);
134
+ } else if value.is_exact_instance_of::<PyFloat>() {
135
+ header(buffer, 1, name);
136
+ buffer.extend_from_slice(&value.extract::<f64>()?.to_le_bytes());
137
+ } else if let Some((_, tag)) = self
138
+ .tags
139
+ .iter()
140
+ .find(|(identity, _)| *identity == value.as_ptr() as usize)
141
+ {
142
+ let offset = tagged(buffer, name, "tag")?;
143
+ string(buffer, "p", tag)?;
144
+ finish(buffer, offset)?;
145
+ } else {
146
+ scalar(buffer, name, value, scalar_encoder)?;
147
+ }
148
+ Ok(())
149
+ }
150
+ }
151
+
152
+ fn scalar(
153
+ buffer: &mut Vec<u8>,
154
+ name: &str,
155
+ value: &Bound<'_, PyAny>,
156
+ scalar_encoder: &Bound<'_, PyAny>,
157
+ ) -> PyResult<()> {
158
+ let encoded = scalar_encoder.call1((value,))?;
159
+ let bytes = encoded.cast::<PyBytes>()?.as_bytes();
160
+ // The existing encoder returns one BSON element named "k". Reuse its
161
+ // complete value, including BSON subtype and specialized tagged nodes.
162
+ let (kind, payload) = encoded_value(bytes)?;
163
+ header(buffer, kind, name);
164
+ buffer.extend_from_slice(payload);
165
+ Ok(())
166
+ }
167
+
168
+ impl FindKeyEncoder {
169
+ fn new(tags: &Bound<'_, PyDict>) -> PyResult<Self> {
170
+ let tags = tags
171
+ .iter()
172
+ .map(|(identity, name)| Ok((identity.extract::<usize>()?, name.extract::<String>()?)))
173
+ .collect::<PyResult<_>>()?;
174
+ Ok(Self { tags })
175
+ }
176
+ }
177
+
178
+ #[pyfunction]
179
+ pub(crate) fn find_key_encoder(tags: &Bound<'_, PyDict>) -> PyResult<FindKeyEncoder> {
180
+ FindKeyEncoder::new(tags)
181
+ }
182
+
183
+ #[pymethods]
184
+ impl FindKeyEncoder {
185
+ fn encode<'py>(
186
+ &self,
187
+ py: Python<'py>,
188
+ family: &Bound<'py, PyAny>,
189
+ limit: &Bound<'py, PyAny>,
190
+ scalar_encoder: &Bound<'py, PyAny>,
191
+ ) -> PyResult<FindKeys<'py>> {
192
+ let mut family_bytes = Vec::with_capacity(256);
193
+ let root = start(&mut family_bytes);
194
+ self.node(&mut family_bytes, "k", family, scalar_encoder)?;
195
+ finish(&mut family_bytes, root)?;
196
+
197
+ let exact = self.wrap(py, &family_bytes, limit, scalar_encoder)?;
198
+ Ok((PyBytes::new(py, &family_bytes), exact))
199
+ }
200
+
201
+ fn wrap<'py>(
202
+ &self,
203
+ py: Python<'py>,
204
+ family_bytes: &[u8],
205
+ limit: &Bound<'py, PyAny>,
206
+ scalar_encoder: &Bound<'py, PyAny>,
207
+ ) -> PyResult<Bound<'py, PyBytes>> {
208
+ let mut exact = Vec::with_capacity(family_bytes.len() + 128);
209
+ let root = start(&mut exact);
210
+ let outer = tuple(&mut exact, "k")?;
211
+ let tag = tagged(&mut exact, "0", "tag")?;
212
+ string(&mut exact, "p", "canonical-seq")?;
213
+ finish(&mut exact, tag)?;
214
+ let pair = tuple(&mut exact, "1")?;
215
+ let (kind, payload) = encoded_value(family_bytes)?;
216
+ header(&mut exact, kind, "0");
217
+ exact.extend_from_slice(payload);
218
+ self.node(&mut exact, "1", limit, scalar_encoder)?;
219
+ finish_tuple(&mut exact, pair)?;
220
+ finish_tuple(&mut exact, outer)?;
221
+ finish(&mut exact, root)?;
222
+ Ok(PyBytes::new(py, &exact))
223
+ }
224
+ }
@@ -16,6 +16,10 @@ mod echo;
16
16
  mod frames;
17
17
  mod hash;
18
18
  mod index;
19
+ #[cfg(all(feature = "python", not(loom)))]
20
+ mod key_encoder;
21
+ #[cfg(all(feature = "python", not(loom)))]
22
+ mod local_cache;
19
23
  mod memory;
20
24
  #[cfg(all(feature = "python", not(loom)))]
21
25
  mod python;