grovedb_merk/test_utils/
temp_merk.rs

1// MIT LICENSE
2//
3// Copyright (c) 2021 Dash Core Group
4//
5// Permission is hereby granted, free of charge, to any
6// person obtaining a copy of this software and associated
7// documentation files (the "Software"), to deal in the
8// Software without restriction, including without
9// limitation the rights to use, copy, modify, merge,
10// publish, distribute, sublicense, and/or sell copies of
11// the Software, and to permit persons to whom the Software
12// is furnished to do so, subject to the following
13// conditions:
14//
15// The above copyright notice and this permission notice
16// shall be included in all copies or substantial portions
17// of the Software.
18//
19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
20// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
21// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
22// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
23// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
26// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27// DEALINGS IN THE SOFTWARE.
28
29//! Temp merk test utils
30
31#[cfg(feature = "minimal")]
32use std::ops::{Deref, DerefMut};
33
34use grovedb_path::SubtreePath;
35use grovedb_storage::StorageBatch;
36#[cfg(feature = "minimal")]
37use grovedb_storage::{
38    rocksdb_storage::{test_utils::TempStorage, PrefixedRocksDbStorageContext},
39    Storage,
40};
41use grovedb_version::version::GroveVersion;
42
43use crate::tree::kv::ValueDefinedCostType;
44#[cfg(feature = "minimal")]
45use crate::Merk;
46
47#[cfg(feature = "minimal")]
48/// Wraps a Merk instance and deletes it from disk it once it goes out of scope.
49pub struct TempMerk {
50    storage: &'static TempStorage,
51    batch: &'static StorageBatch,
52    merk: Merk<PrefixedRocksDbStorageContext<'static>>,
53}
54
55#[cfg(feature = "minimal")]
56impl TempMerk {
57    /// Opens a `TempMerk` at the given file path, creating a new one if it
58    /// does not exist.
59    pub fn new(grove_version: &GroveVersion) -> Self {
60        let storage = Box::leak(Box::new(TempStorage::new()));
61        let batch = Box::leak(Box::new(StorageBatch::new()));
62
63        let context = storage
64            .get_storage_context(SubtreePath::empty(), Some(batch))
65            .unwrap();
66
67        let merk = Merk::open_base(
68            context,
69            false,
70            None::<fn(&[u8], &GroveVersion) -> Option<ValueDefinedCostType>>,
71            grove_version,
72        )
73        .unwrap()
74        .unwrap();
75        TempMerk {
76            storage,
77            merk,
78            batch,
79        }
80    }
81
82    /// Commits pending batch operations.
83    pub fn commit(&mut self, grove_version: &GroveVersion) {
84        let batch = unsafe { Box::from_raw(self.batch as *const _ as *mut StorageBatch) };
85        self.storage
86            .commit_multi_context_batch(*batch, None)
87            .unwrap()
88            .expect("unable to commit batch");
89        self.batch = Box::leak(Box::new(StorageBatch::new()));
90        let context = self
91            .storage
92            .get_storage_context(SubtreePath::empty(), Some(self.batch))
93            .unwrap();
94        self.merk = Merk::open_base(
95            context,
96            false,
97            None::<fn(&[u8], &GroveVersion) -> Option<ValueDefinedCostType>>,
98            grove_version,
99        )
100        .unwrap()
101        .unwrap();
102    }
103}
104
105#[cfg(feature = "minimal")]
106impl Drop for TempMerk {
107    fn drop(&mut self) {
108        unsafe {
109            let batch = Box::from_raw(self.batch as *const _ as *mut StorageBatch);
110            let _ = self.storage.commit_multi_context_batch(*batch, None);
111            drop(Box::from_raw(self.storage as *const _ as *mut TempStorage));
112        }
113    }
114}
115
116#[cfg(feature = "minimal")]
117impl Default for TempMerk {
118    fn default() -> Self {
119        Self::new(GroveVersion::latest())
120    }
121}
122
123#[cfg(feature = "minimal")]
124impl Deref for TempMerk {
125    type Target = Merk<PrefixedRocksDbStorageContext<'static>>;
126
127    fn deref(&self) -> &Merk<PrefixedRocksDbStorageContext<'static>> {
128        &self.merk
129    }
130}
131
132#[cfg(feature = "minimal")]
133impl DerefMut for TempMerk {
134    fn deref_mut(&mut self) -> &mut Merk<PrefixedRocksDbStorageContext<'static>> {
135        &mut self.merk
136    }
137}