1mod batch;
10mod notifications;
11mod read;
12mod serializable;
13pub use serializable::{
14 SerializableReadContext, SerializableSession, SerializableSnapshotCapture,
15 SerializableSnapshotOptions,
16};
17mod transaction;
18
19use std::sync::Arc;
20
21use parking_lot::Mutex;
22
23use crate::read_control::{KeyValueReadVisitor, StorageReadControl, ValueReadVisitor};
24use crate::{
25 KeyValueBatch, KeyValueStore, PersistentStorageIdentity, StorageBackendError,
26 StorageBackendResult, StorageSessionAffinity,
27};
28
29use super::{
30 CommitFailure, MergedRecordSnapshot, StorageTransactionId, VersionError, VersionResult,
31 VersionedPersistence,
32};
33use transaction::Transaction;
34
35#[derive(Debug, Clone, Copy)]
37pub struct VersionedSessionOptions {
38 pub retained_bytes: usize,
39}
40
41impl Default for VersionedSessionOptions {
42 fn default() -> Self {
43 Self {
44 retained_bytes: 64 * 1024 * 1024,
45 }
46 }
47}
48
49pub struct VersionedKeyValueStore {
51 affinity: StorageSessionAffinity,
52 persistence: Arc<dyn VersionedPersistence>,
53 identity: Option<PersistentStorageIdentity>,
54 options: VersionedSessionOptions,
55 control: StorageReadControl,
56 write_cancellation: uqa_core::CancellationToken,
57 retained: Option<MergedRecordSnapshot>,
58 active: Mutex<Option<Transaction>>,
59}
60
61impl VersionedKeyValueStore {
62 pub fn reclaim_versions(&self) -> StorageBackendResult<u64> {
64 self.persistence
65 .reclaim_versions(&self.write_control())
66 .map_err(VersionError::into_storage_error)
67 }
68
69 pub fn identifier_watermark(&self, namespace: &[u8]) -> StorageBackendResult<Option<u64>> {
71 self.persistence
72 .identifier_watermark(namespace, &self.control)
73 .map_err(VersionError::into_storage_error)
74 }
75
76 pub fn allocate_identifiers(
78 &self,
79 namespace: &[u8],
80 request: super::IdentifierRequest,
81 ) -> StorageBackendResult<super::IdentifierAllocation> {
82 self.require_mutable_session()?;
83 let active = self.active.lock();
84 if let Some(transaction) = active.as_ref() {
85 transaction
86 .writable()
87 .map_err(VersionError::into_storage_error)?;
88 }
89 self.persistence
90 .allocate_identifiers(namespace, request, &self.write_control())
91 .map_err(VersionError::into_storage_error)
92 }
93
94 pub fn new(
95 persistence: Arc<dyn VersionedPersistence>,
96 identity: Option<PersistentStorageIdentity>,
97 options: VersionedSessionOptions,
98 ) -> Self {
99 Self::new_with_cancellation(
100 persistence,
101 identity,
102 options,
103 uqa_core::CancellationToken::new(),
104 )
105 }
106
107 pub fn new_with_cancellation(
109 persistence: Arc<dyn VersionedPersistence>,
110 identity: Option<PersistentStorageIdentity>,
111 options: VersionedSessionOptions,
112 write_cancellation: uqa_core::CancellationToken,
113 ) -> Self {
114 Self {
115 affinity: StorageSessionAffinity::new(),
116 persistence,
117 identity,
118 options,
119 control: StorageReadControl::with_limit(options.retained_bytes),
120 write_cancellation,
121 retained: None,
122 active: Mutex::new(None),
123 }
124 }
125
126 pub fn new_session(&self) -> Self {
128 Self::new(
129 Arc::clone(&self.persistence),
130 self.identity.clone(),
131 self.options,
132 )
133 }
134
135 pub fn new_session_with_cancellation(
137 &self,
138 cancellation: &uqa_core::CancellationToken,
139 ) -> Self {
140 Self::new_with_cancellation(
141 Arc::clone(&self.persistence),
142 self.identity.clone(),
143 self.options,
144 cancellation.clone(),
145 )
146 }
147
148 pub fn new_retained_read_session(
150 &self,
151 cancellation: &uqa_core::CancellationToken,
152 ) -> StorageBackendResult<Self> {
153 cancellation.check()?;
154 let retained = self.view().map_err(VersionError::into_storage_error)?;
155 let mut session = self.new_session_with_cancellation(cancellation);
156 session.control =
157 StorageReadControl::new(self.control.memory(), session.control.cancellation());
158 session.retained = Some(retained);
159 Ok(session)
160 }
161
162 fn require_mutable_session(&self) -> StorageBackendResult<()> {
163 if self.retained.is_some() {
164 return Err(StorageBackendError::Other(
165 "cannot write through a retained read-only session".into(),
166 ));
167 }
168 Ok(())
169 }
170
171 fn write_control(&self) -> StorageReadControl {
172 StorageReadControl::new(self.control.memory(), &self.write_cancellation)
173 }
174
175 pub fn options(&self) -> VersionedSessionOptions {
176 self.options
177 }
178
179 pub fn record_snapshot(&self) -> VersionResult<MergedRecordSnapshot> {
181 self.view()
182 }
183
184 pub fn refresh_transaction_snapshot(
186 &self,
187 cancellation: &uqa_core::CancellationToken,
188 ) -> StorageBackendResult<()> {
189 cancellation.check()?;
190 let control = StorageReadControl::new(self.control.memory(), cancellation);
191 let mut active = self.active.lock();
192 if self.retained.is_some() {
193 active.as_ref().ok_or_else(no_transaction)?;
194 return Ok(());
195 }
196 active
197 .as_mut()
198 .ok_or_else(no_transaction)?
199 .refresh(&*self.persistence, &control)
200 .map_err(VersionError::into_storage_error)
201 }
202
203 pub fn retention_control(&self) -> StorageReadControl {
205 self.control.clone()
206 }
207
208 pub fn session_affinity(&self) -> StorageSessionAffinity {
209 self.affinity.clone()
210 }
211
212 pub fn pending_commit(&self) -> Option<StorageTransactionId> {
214 self.active
215 .lock()
216 .as_ref()
217 .and_then(|transaction| transaction.allocation)
218 }
219
220 pub fn pending_transaction_completion(&self) -> Option<super::TransactionOutcomeId> {
222 self.active
223 .lock()
224 .as_ref()
225 .and_then(Transaction::pending_completion)
226 }
227
228 pub fn establish_serializable_snapshot(&self) -> StorageBackendResult<SerializableReadContext> {
230 self.require_mutable_session()?;
231 self.active
232 .lock()
233 .as_mut()
234 .ok_or_else(no_transaction)?
235 .establish_serializable(&self.persistence, &self.write_control())
236 .map_err(VersionError::into_storage_error)
237 }
238
239 pub fn observe_serializable_write(
241 &self,
242 predicate: super::SerializablePredicate<'_>,
243 ) -> StorageBackendResult<()> {
244 let mut active = self.active.lock();
245 let transaction = active.as_mut().ok_or_else(no_transaction)?;
246 transaction
247 .writable()
248 .map_err(VersionError::into_storage_error)?;
249 let context = transaction.serializable_context().ok_or_else(|| {
250 StorageBackendError::Other("no serializable participant in this session".into())
251 })?;
252 let control = self.write_control();
253 context
254 .with_graph(&control, |graph| {
255 graph.observe_write(context.id(), predicate, &control)
256 })
257 .map_err(VersionError::into_storage_error)
258 }
259
260 fn begin(&self, read_only: bool) -> StorageBackendResult<()> {
261 if !read_only {
262 self.require_mutable_session()?;
263 }
264 let mut active = self.active.lock();
265 if active.is_some() {
266 return Err(StorageBackendError::Other(
267 "a KeyValue transaction is already active".into(),
268 ));
269 }
270 *active = Some(match self.retained.as_ref() {
271 Some(view) => Transaction::at_snapshot(view.retain_committed(), true, &self.control),
272 None => Transaction::new(&*self.persistence, read_only, &self.control)
273 .map_err(VersionError::into_storage_error)?,
274 });
275 Ok(())
276 }
277
278 fn view(&self) -> VersionResult<MergedRecordSnapshot> {
279 if let Some(view) = self.retained.as_ref() {
280 return view.try_clone();
281 }
282 let active = self.active.lock();
283 if let Some(transaction) = active.as_ref() {
284 transaction.view()
285 } else {
286 Transaction::new(&*self.persistence, true, &self.control)?.view()
287 }
288 }
289
290 fn write<T>(
291 &self,
292 operation: impl FnOnce(&mut Transaction) -> VersionResult<T>,
293 ) -> StorageBackendResult<T> {
294 self.require_mutable_session()?;
295 let mut active = self.active.lock();
296 if let Some(transaction) = active.as_mut() {
297 return transaction
298 .atomic(operation)
299 .map_err(VersionError::into_storage_error);
300 }
301 let mut transaction = Transaction::new(&*self.persistence, false, &self.control)
302 .map_err(VersionError::into_storage_error)?;
303 let result = operation(&mut transaction).map_err(VersionError::into_storage_error)?;
304 *active = Some(transaction);
306 active
307 .as_mut()
308 .expect("retained attempt")
309 .commit(&*self.persistence, &self.write_control())?;
310 active
311 .as_ref()
312 .expect("retained attempt")
313 .acknowledge_completion(&*self.persistence, &self.control)?;
314 *active = None;
315 Ok(result)
316 }
317
318 fn savepoint_action(
319 &self,
320 operation: impl FnOnce(&mut Transaction) -> VersionResult<()>,
321 ) -> StorageBackendResult<()> {
322 let mut active = self.active.lock();
323 let transaction = active.as_mut().ok_or_else(no_transaction)?;
324 transaction
325 .unsealed()
326 .map_err(VersionError::into_storage_error)?;
327 operation(transaction).map_err(VersionError::into_storage_error)
328 }
329}
330
331impl super::IdentifierAllocator for VersionedKeyValueStore {
332 fn identifier_watermark(&self, namespace: &[u8]) -> StorageBackendResult<Option<u64>> {
333 Self::identifier_watermark(self, namespace)
334 }
335
336 fn allocate_identifiers(
337 &self,
338 namespace: &[u8],
339 request: super::IdentifierRequest,
340 ) -> StorageBackendResult<super::IdentifierAllocation> {
341 Self::allocate_identifiers(self, namespace, request)
342 }
343}
344
345impl KeyValueStore for VersionedKeyValueStore {
346 fn retention_control(&self) -> Option<StorageReadControl> {
347 Some(Self::retention_control(self))
348 }
349
350 fn notification_publications(
351 &self,
352 ) -> Option<&dyn crate::notifications::NotificationPublicationStore> {
353 Some(self)
354 }
355
356 fn serializable_session(&self) -> Option<&dyn SerializableSession> {
357 self.persistence
358 .serializable_coordinator()
359 .map(|_| self as &dyn SerializableSession)
360 }
361
362 fn vacuum(&self) -> StorageBackendResult<()> {
363 let active = self.active.lock();
364 if active.is_some() {
365 return Err(StorageBackendError::Other(
366 "vacuum requires an inactive logical session".into(),
367 ));
368 }
369 self.reclaim_versions().map(|_| ())
370 }
371
372 fn write_cancellation(&self) -> Option<uqa_core::CancellationToken> {
373 Some(self.write_cancellation.clone())
374 }
375
376 fn open_session_with_cancellation(
377 &self,
378 cancellation: &uqa_core::CancellationToken,
379 ) -> StorageBackendResult<Arc<dyn KeyValueStore>> {
380 cancellation.check()?;
381 Ok(Arc::new(self.new_session_with_cancellation(cancellation)))
382 }
383
384 fn open_retained_read_session(
385 &self,
386 cancellation: &uqa_core::CancellationToken,
387 ) -> StorageBackendResult<Arc<dyn KeyValueStore>> {
388 Ok(Arc::new(self.new_retained_read_session(cancellation)?))
389 }
390
391 fn transaction_model(&self) -> crate::StorageTransactionModel {
392 crate::StorageTransactionModel::VersionedConcurrent {
393 database: self.persistence.database_id(),
394 }
395 }
396
397 fn refresh_transaction_snapshot(
398 &self,
399 cancellation: &uqa_core::CancellationToken,
400 ) -> StorageBackendResult<()> {
401 Self::refresh_transaction_snapshot(self, cancellation)
402 }
403
404 fn identifier_allocator(&self) -> Option<&dyn super::IdentifierAllocator> {
405 Some(self)
406 }
407
408 fn with_read_view(
409 &self,
410 operation: &mut crate::key_value::KeyValueReadScope<'_>,
411 ) -> StorageBackendResult<()> {
412 self.control.check()?;
413 let view = self.view().map_err(VersionError::into_storage_error)?;
414 operation(&read::RecordRead {
415 view: &view,
416 database: self.persistence.database_id(),
417 control: &self.control,
418 })?;
419 self.control.check()
420 }
421
422 fn with_mutation(
423 &self,
424 operation: &mut crate::key_value::KeyValueMutation<'_>,
425 ) -> StorageBackendResult<()> {
426 self.control.check()?;
427 self.write(|transaction| {
428 let view = transaction.view()?;
429 let read = read::RecordRead {
430 view: &view,
431 database: self.persistence.database_id(),
432 control: &self.control,
433 };
434 let mut batch = batch::Batch::new(
435 self,
436 transaction
437 .serializable_context()
438 .map(SerializableReadContext::id),
439 );
440 operation(&read, &mut batch)?;
441 self.control.check()?;
442 batch.apply(transaction)
443 })
444 }
445
446 fn transaction_affinity(&self) -> Option<StorageSessionAffinity> {
447 Some(self.session_affinity())
448 }
449
450 fn storage_identity(&self) -> StorageBackendResult<Option<PersistentStorageIdentity>> {
451 Ok(self.identity.clone())
452 }
453
454 fn open_session(&self) -> StorageBackendResult<Arc<dyn KeyValueStore>> {
455 Ok(Arc::new(self.new_session()))
456 }
457
458 fn get(&self, key: &[u8]) -> StorageBackendResult<Option<Vec<u8>>> {
459 let mut value = None;
460 self.visit_value(key, &self.control, &mut |bytes| {
461 value = bytes.map(<[u8]>::to_vec);
462 Ok(())
463 })?;
464 Ok(value)
465 }
466
467 fn contains_key(&self, key: &[u8]) -> StorageBackendResult<bool> {
468 Ok(self
469 .view()
470 .and_then(|view| view.metadata(key, &self.control))
471 .map_err(VersionError::into_storage_error)?
472 .is_some_and(|record| record.live))
473 }
474
475 fn contains_prefix_budgeted(
476 &self,
477 prefix: &[u8],
478 control: &StorageReadControl,
479 ) -> StorageBackendResult<bool> {
480 control.check()?;
481 let mut found = false;
482 self.view()
483 .map_err(VersionError::into_storage_error)?
484 .visit_keys(prefix, None, usize::MAX, control, &mut |_, record| {
485 found = record.live;
486 Ok(!found)
487 })
488 .map_err(VersionError::into_storage_error)?;
489 Ok(found)
490 }
491
492 fn visit_value(
493 &self,
494 key: &[u8],
495 control: &StorageReadControl,
496 visit: &mut ValueReadVisitor<'_>,
497 ) -> StorageBackendResult<()> {
498 control.check()?;
499 self.view()
500 .map_err(VersionError::into_storage_error)?
501 .visit_value(key, control, &mut |record| {
502 visit(record.and_then(|record| record.value)).map_err(VersionError::from)
503 })
504 .map_err(VersionError::into_storage_error)
505 }
506
507 fn visit_prefix_after(
508 &self,
509 prefix: &[u8],
510 after: Option<&[u8]>,
511 limit: usize,
512 control: &StorageReadControl,
513 visit: &mut KeyValueReadVisitor<'_>,
514 ) -> StorageBackendResult<()> {
515 control.check()?;
516 if limit == 0 {
517 return Ok(());
518 }
519 let view = self.view().map_err(VersionError::into_storage_error)?;
520 read::visit_live(&view, prefix, after, limit, control, visit)
521 .map_err(VersionError::into_storage_error)
522 }
523
524 fn put(&self, key: &[u8], value: &[u8]) -> StorageBackendResult<()> {
525 self.write(|transaction| transaction.replace(key, Some(value), &self.control))
526 }
527 fn delete(&self, key: &[u8]) -> StorageBackendResult<()> {
528 self.write(|transaction| transaction.replace(key, None, &self.control))
529 }
530
531 fn scan_prefix(&self, prefix: &[u8]) -> StorageBackendResult<Vec<(Vec<u8>, Vec<u8>)>> {
532 self.scan_prefix_after(prefix, None, usize::MAX)
533 }
534
535 fn scan_prefix_after(
536 &self,
537 prefix: &[u8],
538 after: Option<&[u8]>,
539 limit: usize,
540 ) -> StorageBackendResult<Vec<(Vec<u8>, Vec<u8>)>> {
541 let mut rows = Vec::new();
542 self.visit_prefix_after(prefix, after, limit, &self.control, &mut |key, value| {
543 rows.push((key.to_vec(), value.to_vec()));
544 Ok(())
545 })?;
546 Ok(rows)
547 }
548
549 fn scan_prefix_keys_after(
550 &self,
551 prefix: &[u8],
552 after: Option<&[u8]>,
553 limit: usize,
554 ) -> StorageBackendResult<Vec<Vec<u8>>> {
555 let mut keys = Vec::new();
556 if limit != 0 {
557 self.view()
558 .map_err(VersionError::into_storage_error)?
559 .visit_keys(
560 prefix,
561 after,
562 usize::MAX,
563 &self.control,
564 &mut |key, record| {
565 if record.live {
566 keys.push(key.to_vec());
567 }
568 Ok(keys.len() < limit)
569 },
570 )
571 .map_err(VersionError::into_storage_error)?;
572 }
573 Ok(keys)
574 }
575
576 fn first_prefix_after(
577 &self,
578 prefix: &[u8],
579 after: Option<&[u8]>,
580 ) -> StorageBackendResult<Option<(Vec<u8>, Vec<u8>)>> {
581 Ok(self.scan_prefix_after(prefix, after, 1)?.pop())
582 }
583 fn delete_prefix(&self, prefix: &[u8]) -> StorageBackendResult<usize> {
584 self.write(|transaction| transaction.delete_prefix(prefix, &self.control))
585 }
586 fn batch(&self) -> Box<dyn KeyValueBatch + '_> {
587 let participant = self
588 .active
589 .lock()
590 .as_ref()
591 .and_then(Transaction::serializable_context)
592 .map(SerializableReadContext::id);
593 Box::new(batch::Batch::new(self, participant))
594 }
595 fn begin_transaction(&self) -> StorageBackendResult<()> {
596 self.begin(false)
597 }
598 fn begin_read_transaction(&self) -> StorageBackendResult<()> {
599 self.begin(true)
600 }
601 fn begin_upgradeable_transaction(&self) -> StorageBackendResult<()> {
602 self.begin(self.retained.is_some())
603 }
604 fn in_transaction(&self) -> bool {
605 self.active.lock().is_some()
606 }
607 fn transaction_has_written(&self) -> StorageBackendResult<bool> {
608 Ok(self.active.lock().as_ref().is_some_and(|transaction| {
609 transaction.changes.has_written() || transaction.has_derived_changes()
610 }))
611 }
612 fn change_version(&self) -> StorageBackendResult<Option<u64>> {
613 Ok(Some(
614 self.view()
615 .map_err(VersionError::into_storage_error)?
616 .sequence()
617 .as_u64(),
618 ))
619 }
620
621 fn commit_transaction(&self) -> StorageBackendResult<()> {
622 let mut active = self.active.lock();
623 active
624 .as_mut()
625 .ok_or_else(no_transaction)?
626 .commit(&*self.persistence, &self.write_control())?;
627 active
628 .as_ref()
629 .expect("completed attempt")
630 .acknowledge_completion(&*self.persistence, &self.control)?;
631 *active = None;
632 Ok(())
633 }
634
635 fn rollback_transaction(&self) -> StorageBackendResult<()> {
636 let mut active = self.active.lock();
637 active
638 .as_mut()
639 .ok_or_else(no_transaction)?
640 .abort(&*self.persistence, &self.control)?;
641 active
642 .as_ref()
643 .expect("completed attempt")
644 .acknowledge_completion(&*self.persistence, &self.control)?;
645 *active = None;
646 Ok(())
647 }
648
649 fn savepoint(&self, name: &str) -> StorageBackendResult<()> {
650 self.savepoint_action(|transaction| transaction.savepoint(name, &self.control))
651 }
652 fn release_savepoint(&self, name: &str) -> StorageBackendResult<()> {
653 self.savepoint_action(|transaction| transaction.release(name))
654 }
655 fn rollback_to_savepoint(&self, name: &str) -> StorageBackendResult<()> {
656 self.savepoint_action(|transaction| transaction.rollback_to(name, &self.control))
657 }
658}
659
660fn no_transaction() -> StorageBackendError {
661 StorageBackendError::Other("no active KeyValue transaction".into())
662}
663
664fn commit_error(error: CommitFailure) -> StorageBackendError {
665 match error {
666 CommitFailure::Rejected(error) => error.into_storage_error(),
667 error @ CommitFailure::Indeterminate { .. } => StorageBackendError::backend("MVCC", error),
668 }
669}