persy/
transaction.rs

1use crate::{
2    address::segment_iter::TxSegmentIter,
3    error::{
4        CreateIndexError, CreateSegmentError, DeleteError, DropIndexError, DropSegmentError, GenericError,
5        IndexChangeError, IndexError, IndexOpsError, IndexPutError, InsertError, PrepareError, SegmentError,
6        UpdateError, PE,
7    },
8    id::{IndexId, PersyId, SegmentId, ToIndexId, ToSegmentId},
9    index::{
10        config::{is_index_name_data, is_index_name_meta, IndexType, ValueMode},
11        iter::TxIndexIter,
12        tree::nodes::Value,
13        value_iter::ValueIter,
14    },
15    persy::{IndexInfo, PersyImpl, TxFinalize},
16    transaction::tx_impl::TransactionImpl,
17    ReadError, Snapshot,
18};
19use std::{ops::RangeBounds, sync::Arc};
20
21pub(crate) mod index_locks;
22pub(crate) mod iter;
23pub(crate) mod locks;
24#[cfg(test)]
25mod tests;
26pub mod tx_impl;
27
28/// Transaction container, it include all the changes done in a transaction.
29pub struct Transaction {
30    pub(crate) persy_impl: Arc<PersyImpl>,
31    pub(crate) tx: Option<TransactionImpl>,
32}
33
34fn tx_mut(tx: &mut Option<TransactionImpl>) -> &mut TransactionImpl {
35    tx.as_mut().unwrap()
36}
37impl Transaction {
38    fn tx_mut(&mut self) -> &mut TransactionImpl {
39        tx_mut(&mut self.tx)
40    }
41    fn tx(&self) -> &TransactionImpl {
42        self.tx.as_ref().unwrap()
43    }
44    /// Create a new segment with the provided name
45    ///
46    /// # Example
47    ///
48    /// ```rust
49    /// # use persy::{OpenOptions};
50    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
51    /// # let persy = OpenOptions::new().memory()?;
52    /// let mut tx = persy.begin()?;
53    /// tx.create_segment("my_new_segment")?;
54    /// tx.prepare()?.commit()?;
55    /// # Ok(())
56    /// # }
57    /// ```
58    pub fn create_segment(&mut self, segment: &str) -> Result<SegmentId, PE<CreateSegmentError>> {
59        assert!(!is_index_name_meta(segment));
60        assert!(!is_index_name_data(segment));
61        Ok(self.persy_impl.create_segment(tx_mut(&mut self.tx), segment)?)
62    }
63
64    /// Drop a existing segment
65    ///
66    /// # Example
67    ///
68    /// ```rust
69    /// # use persy::{OpenOptions};
70    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
71    /// # let persy = OpenOptions::new().memory()?;
72    /// # let mut tx = persy.begin()?;
73    /// # tx.create_segment("existing_segment_name")?;
74    /// # tx.prepare()?.commit()?;
75    /// let mut tx = persy.begin()?;
76    /// tx.drop_segment("existing_segment_name")?;
77    /// tx.prepare()?.commit()?;
78    /// # Ok(())
79    /// # }
80    /// ```
81    pub fn drop_segment(&mut self, segment: &str) -> Result<(), PE<DropSegmentError>> {
82        Ok(self.persy_impl.drop_segment(tx_mut(&mut self.tx), segment)?)
83    }
84
85    /// Check if a segment already exist in the storage considering the transaction
86    ///
87    ///
88    /// # Example
89    /// ```rust
90    /// # use persy::{OpenOptions};
91    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
92    /// # let persy = OpenOptions::new().memory()?;
93    /// let mut tx = persy.begin()?;
94    /// tx.create_segment("my_new_segment")?;
95    /// assert!(tx.exists_segment("my_new_segment")?);
96    /// # tx.prepare()?.commit()?;
97    /// # Ok(())
98    /// # }
99    /// ```
100    pub fn exists_segment(&self, segment: &str) -> Result<bool, PE<GenericError>> {
101        Ok(self.persy_impl.exists_segment_tx(self.tx(), segment))
102    }
103
104    /// Resolves the segment to a SegmentId, considering the transaction
105    ///
106    /// # Example
107    ///
108    /// ```rust
109    /// # use persy::{OpenOptions};
110    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
111    /// # let persy = OpenOptions::new().memory()?;
112    /// let mut tx = persy.begin()?;
113    /// tx.create_segment("my_new_segment")?;
114    /// let segment_id = tx.solve_segment_id("my_new_segment")?;
115    /// # tx.prepare()?.commit()?;
116    /// # Ok(())
117    /// # }
118    /// ```
119    pub fn solve_segment_id(&self, segment: impl ToSegmentId) -> Result<SegmentId, PE<SegmentError>> {
120        Ok(self.persy_impl.solve_segment_id_tx(self.tx(), segment)?)
121    }
122
123    /// Resolves the index name to a IndexId, considering the transaction,
124    /// this has no public use as today, but may be used in future.
125    ///
126    /// # Example
127    ///
128    /// ```rust
129    /// # use persy::{OpenOptions, ValueMode};
130    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
131    /// # let persy = OpenOptions::new().memory()?;
132    /// # let mut tx = persy.begin()?;
133    /// let mut tx = persy.begin()?;
134    /// tx.create_index::<u8,u8>("my_new_index", ValueMode::Cluster)?;
135    /// let index_id = tx.solve_index_id("my_new_index")?;
136    /// # tx.prepare()?.commit()?;
137    /// # Ok(())
138    /// # }
139    /// ```
140    pub fn solve_index_id(&self, index: impl ToIndexId) -> Result<IndexId, PE<IndexError>> {
141        let (id, _) = self.persy_impl.solve_index_id_tx(self.tx(), index)?;
142        Ok(id)
143    }
144
145    /// Create a new record.
146    ///
147    /// This function return an id that can be used by [`read`],
148    /// the record content can be read only with the [`transaction read`] till the transaction is committed.
149    ///
150    /// [`read`]:struct.Persy.html#method.read
151    /// [`transaction read`]:struct.Transaction.html#method.read
152    ///
153    /// # Example
154    ///
155    /// ```rust
156    /// # use persy::{OpenOptions};
157    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
158    /// # let persy = OpenOptions::new().memory()?;
159    /// let mut tx = persy.begin()?;
160    /// # tx.create_segment("seg")?;
161    /// let data = vec![1;20];
162    /// tx.insert("seg", &data)?;
163    /// tx.prepare()?.commit()?;
164    /// # Ok(())
165    /// # }
166    /// ```
167    pub fn insert(&mut self, segment: impl ToSegmentId, rec: &[u8]) -> Result<PersyId, PE<InsertError>> {
168        Ok(PersyId(self.persy_impl.insert_record(
169            tx_mut(&mut self.tx),
170            segment,
171            rec,
172        )?))
173    }
174
175    /// Read the record content considering eventual in transaction changes.
176    ///
177    /// # Example
178    ///
179    /// ```rust
180    /// # use persy::{OpenOptions};
181    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
182    /// # let persy = OpenOptions::new().memory()?;
183    /// let mut tx = persy.begin()?;
184    /// # tx.create_segment("seg")?;
185    /// let data = vec![1;20];
186    /// let id = tx.insert("seg", &data)?;
187    /// let read = tx.read("seg", &id)?.expect("record exists");
188    /// assert_eq!(data,read);
189    /// # tx.prepare()?.commit()?;
190    /// # Ok(())
191    /// # }
192    /// ```
193    pub fn read(&mut self, segment: impl ToSegmentId, id: &PersyId) -> Result<Option<Vec<u8>>, PE<ReadError>> {
194        let segment_id = self.solve_segment_id(segment).map_err(|PE::PE(e)| ReadError::from(e))?;
195        Ok(self.persy_impl.read_tx(tx_mut(&mut self.tx), segment_id, &id.0)?)
196    }
197
198    /// Scan for persistent and in transaction records
199    ///
200    /// # Example
201    ///
202    /// ```rust
203    /// # use persy::{OpenOptions};
204    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
205    /// # let persy = OpenOptions::new().memory()?;
206    /// let mut tx = persy.begin()?;
207    /// # tx.create_segment("seg")?;
208    /// let data = vec![1;20];
209    /// let id = tx.insert("seg", &data)?;
210    /// let mut count = 0;
211    /// for (id,content) in tx.scan("seg")? {
212    ///     println!("record size:{}",content.len());
213    ///     count+=1;
214    /// }
215    /// assert_eq!(count,1);
216    /// # Ok(())
217    /// # }
218    /// ```
219    pub fn scan(&mut self, segment: impl ToSegmentId) -> Result<TxSegmentIter, PE<SegmentError>> {
220        let segment_id = self.solve_segment_id(segment)?;
221        Ok(TxSegmentIter::new(
222            self.persy_impl.scan_tx(self.tx.as_mut().unwrap(), segment_id)?,
223            self,
224        ))
225    }
226
227    /// Update the record content.
228    ///
229    /// This updated content can be read only with the [`transaction read`] till the transaction is committed.
230    ///
231    /// [`read`]:struct.Transaction.html#method.read
232    ///
233    /// # Example
234    ///
235    /// ```rust
236    /// # use persy::{OpenOptions};
237    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
238    /// # let persy = OpenOptions::new().memory()?;
239    /// let mut tx = persy.begin()?;
240    /// # tx.create_segment("seg")?;
241    /// let data = vec![1;20];
242    /// let id = tx.insert("seg", &data)?;
243    /// let new_data = vec![2;20];
244    /// tx.update("seg", &id, &new_data)?;
245    /// # tx.prepare()?.commit()?;
246    /// # Ok(())
247    /// # }
248    /// ```
249    pub fn update(&mut self, segment: impl ToSegmentId, id: &PersyId, rec: &[u8]) -> Result<(), PE<UpdateError>> {
250        let segment_id = self
251            .solve_segment_id(segment)
252            .map_err(|e| PE::PE(UpdateError::from(e.error())))?;
253        Ok(self.persy_impl.update(tx_mut(&mut self.tx), segment_id, &id.0, rec)?)
254    }
255
256    /// Delete a record.
257    ///
258    /// The record will result deleted only reading it with [`transaction read`] till the transaction is committed.
259    ///
260    /// [`transaction read`]:struct.Persy.html#method.read
261    ///
262    /// # Example
263    ///
264    /// ```rust
265    /// # use persy::{OpenOptions};
266    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
267    /// # let persy = OpenOptions::new().memory()?;
268    /// let mut tx = persy.begin()?;
269    /// # tx.create_segment("seg")?;
270    /// let data = vec![1;20];
271    /// let id = tx.insert("seg", &data)?;
272    /// tx.delete("seg", &id)?;
273    /// # tx.prepare()?.commit()?;
274    /// # Ok(())
275    /// # }
276    /// ```
277    pub fn delete(&mut self, segment: impl ToSegmentId, id: &PersyId) -> Result<(), PE<DeleteError>> {
278        let segment_id = self
279            .solve_segment_id(segment)
280            .map_err(|e| PE::PE(DeleteError::from(e.error())))?;
281        Ok(self.persy_impl.delete(tx_mut(&mut self.tx), segment_id, &id.0)?)
282    }
283
284    /// Create a new index with the name and the value management mode.
285    ///
286    /// The create operation require two template arguments that are the types as keys and
287    /// values of the index this have to match the following operation on the indexes.
288    ///
289    /// # Example
290    ///
291    /// ```rust
292    /// # use persy::{OpenOptions, ValueMode};
293    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
294    /// # let persy = OpenOptions::new().memory()?;
295    /// let mut tx = persy.begin()?;
296    /// tx.create_index::<u8,u8>("my_new_index", ValueMode::Cluster)?;
297    /// # tx.prepare()?.commit()?;
298    /// # Ok(())
299    /// # }
300    /// ```
301    pub fn create_index<K, V>(&mut self, index_name: &str, value_mode: ValueMode) -> Result<(), PE<CreateIndexError>>
302    where
303        K: IndexType,
304        V: IndexType,
305    {
306        Ok(self
307            .persy_impl
308            .create_index::<K, V>(tx_mut(&mut self.tx), index_name, value_mode)?)
309    }
310
311    /// Drop an existing index.
312    ///
313    /// # Example
314    ///
315    /// ```rust
316    /// # use persy::{OpenOptions, ValueMode};
317    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
318    /// # let persy = OpenOptions::new().memory()?;
319    /// # let mut tx = persy.begin()?;
320    /// # tx.create_index::<u8,u8>("my_new_index", ValueMode::Cluster)?;
321    /// # tx.prepare()?.commit()?;
322    /// let mut tx = persy.begin()?;
323    /// tx.drop_index("my_new_index")?;
324    /// # tx.prepare()?.commit()?;
325    /// # Ok(())
326    /// # }
327    /// ```
328    pub fn drop_index(&mut self, index_name: &str) -> Result<(), PE<DropIndexError>> {
329        Ok(self.persy_impl.drop_index(tx_mut(&mut self.tx), index_name)?)
330    }
331
332    /// Check if a segment already exist in the storage considering the transaction
333    ///
334    /// # Example
335    ///
336    /// ```rust
337    /// # use persy::{OpenOptions, ValueMode};
338    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
339    /// # let persy = OpenOptions::new().memory()?;
340    /// let mut tx = persy.begin()?;
341    /// tx.create_index::<u8,u8>("my_new_index", ValueMode::Replace)?;
342    /// assert!(tx.exists_index("my_new_index")?);
343    /// # tx.prepare()?.commit()?;
344    /// # Ok(())
345    /// # }
346    /// ```
347    pub fn exists_index(&self, index_name: &str) -> Result<bool, PE<GenericError>> {
348        Ok(self.persy_impl.exists_index_tx(self.tx(), index_name))
349    }
350
351    /// Put a key value in an index following the value mode strategy.
352    ///
353    /// # Example
354    ///
355    /// ```rust
356    /// # use persy::{OpenOptions, ValueMode};
357    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
358    /// # let persy = OpenOptions::new().memory()?;
359    /// let mut tx = persy.begin()?;
360    /// tx.create_index::<u8,u8>("my_new_index", ValueMode::Cluster)?;
361    /// tx.put::<u8,u8>("my_new_index",10,10)?;
362    /// tx.prepare()?.commit()?;
363    /// # Ok(())
364    /// # }
365    /// ```
366    pub fn put<K, V>(&mut self, index_name: &str, k: K, v: V) -> Result<(), PE<IndexPutError>>
367    where
368        K: IndexType,
369        V: IndexType,
370    {
371        let index_id = self
372            .solve_index_id(index_name)
373            .map_err(|e| PE::PE(IndexPutError::from(e.error())))?;
374        Ok(self
375            .persy_impl
376            .put::<K::Wrapper, V::Wrapper>(tx_mut(&mut self.tx), index_id, k.wrap(), v.wrap())?)
377    }
378
379    /// Remove a key and optionally a specific value from an index following the value mode strategy.
380    ///
381    /// # Example
382    ///
383    /// ```rust
384    /// # use persy::{OpenOptions, ValueMode};
385    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
386    /// # let persy = OpenOptions::new().memory()?;
387    /// let mut tx = persy.begin()?;
388    /// tx.create_index::<u8,u8>("my_new_index", ValueMode::Cluster)?;
389    /// tx.put::<u8,u8>("my_new_index",10,10)?;
390    /// tx.remove::<u8,u8>("my_new_index",10,Some(10))?;
391    /// # tx.prepare()?.commit()?;
392    /// # Ok(())
393    /// # }
394    /// ```
395    pub fn remove<K, V>(&mut self, index_name: &str, k: K, v: Option<V>) -> Result<(), PE<IndexOpsError>>
396    where
397        K: IndexType,
398        V: IndexType,
399    {
400        let index_id = self
401            .solve_index_id(index_name)
402            .map_err(|e| PE::PE(IndexOpsError::from(e.error())))?;
403        Ok(self.persy_impl.remove::<K::Wrapper, V::Wrapper>(
404            tx_mut(&mut self.tx),
405            index_id,
406            k.wrap(),
407            v.map(|rv| rv.wrap()),
408        )?)
409    }
410
411    /// Get a value or a group of values from a key considering changes in transaction.
412    ///
413    /// # Example
414    ///
415    /// ```rust
416    /// # use persy::{OpenOptions, ValueMode};
417    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
418    /// # let persy = OpenOptions::new().memory()?;
419    /// # let mut tx = persy.begin()?;
420    /// # tx.create_index::<u8,u8>("my_new_index", ValueMode::Cluster)?;
421    /// tx.put::<u8,u8>("my_new_index",10,10)?;
422    /// let values = tx.get::<u8,u8>("my_new_index",&10)?;
423    /// for value in values {
424    ///  //...
425    /// }
426    /// # tx.prepare()?.commit()?;
427    /// # Ok(())
428    /// # }
429    /// ```
430    pub fn get<K, V>(&mut self, index_name: &str, k: &K) -> Result<ValueIter<V>, PE<IndexChangeError>>
431    where
432        K: IndexType,
433        V: IndexType,
434    {
435        let index_id = self
436            .solve_index_id(index_name)
437            .map_err(|e| IndexChangeError::from(e.error()))?;
438        let entry: Option<Value<V::Wrapper>> =
439            self.persy_impl
440                .get_tx::<K::Wrapper, V::Wrapper>(tx_mut(&mut self.tx), index_id, &k.clone().wrap())?;
441        Ok(ValueIter::from(entry))
442    }
443
444    /// Get one value or none from a key considering changes in transaction.
445    ///
446    /// # Example
447    ///
448    /// ```rust
449    /// # use persy::{OpenOptions, ValueMode};
450    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
451    /// # let persy = OpenOptions::new().memory()?;
452    /// # let mut tx = persy.begin()?;
453    /// # tx.create_index::<u8,u8>("my_new_index", ValueMode::Cluster)?;
454    /// tx.put::<u8,u8>("my_new_index",10,10)?;
455    /// if let Some(value) =  tx.one::<u8,u8>("my_new_index",&10)?{
456    ///  //...
457    /// }
458    /// # tx.prepare()?.commit()?;
459    /// # Ok(())
460    /// # }
461    /// ```
462    pub fn one<K, V>(&mut self, index_name: &str, k: &K) -> Result<Option<V>, PE<IndexChangeError>>
463    where
464        K: IndexType,
465        V: IndexType,
466    {
467        Ok(self.get(index_name, k)?.next())
468    }
469
470    /// Browse a range of keys and values from an index including the transaction changes
471    ///
472    /// # Example
473    ///
474    /// ```rust
475    /// # use persy::{OpenOptions, ValueMode, TxIndexIter};
476    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
477    /// # let persy = OpenOptions::new().memory()?;
478    /// let mut tx = persy.begin()?;
479    /// # tx.create_index::<u8,u8>("my_new_index", ValueMode::Cluster)?;
480    /// tx.put::<u8,u8>("my_new_index",10,10)?;
481    /// {
482    ///     let iter:TxIndexIter<u8,u8> = tx.range("my_new_index",10..12)?;
483    ///     for (k,values) in iter  {
484    ///         for value in values {
485    ///             //...
486    ///         }
487    ///     }
488    /// }
489    /// tx.prepare()?.commit()?;
490    /// # Ok(())
491    /// # }
492    /// ```
493    pub fn range<'a, K, V, R>(
494        &'a mut self,
495        index_name: &str,
496        range: R,
497    ) -> Result<TxIndexIter<'a, K, V>, PE<IndexOpsError>>
498    where
499        K: IndexType,
500        V: IndexType,
501        R: RangeBounds<K>,
502    {
503        let index_id = self
504            .solve_index_id(index_name)
505            .map_err(|e| IndexOpsError::from(e.error()))?;
506        let imp = self.persy_impl.clone();
507
508        let range = PersyImpl::map_index_range_bounds(range);
509        let tx_raw = imp.range_tx(self.tx_mut(), index_id, range)?;
510        Ok(TxIndexIter::new(tx_raw, self))
511    }
512
513    /// Rollback a not yet prepared transaction.
514    ///
515    /// All the resources used for eventual insert or update are released.
516    ///
517    /// # Example
518    ///
519    /// ```rust
520    /// # use persy::{OpenOptions};
521    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
522    /// # let persy = OpenOptions::new().memory()?;
523    /// let mut tx = persy.begin()?;
524    /// # tx.create_segment("seg")?;
525    /// let data = vec![1;20];
526    /// tx.insert("seg", &data)?;
527    /// tx.rollback()?;
528    /// # Ok(())
529    /// # }
530    /// ```
531    pub fn rollback(mut self) -> Result<(), PE<GenericError>> {
532        if let Some(real_tx) = self.tx.take() {
533            self.persy_impl.rollback(real_tx)?;
534        }
535        Ok(())
536    }
537
538    /// Prepare to commit a transaction, when this method return all the validation checks
539    /// are done and is guaranteed that the transaction can be committed successfully
540    ///
541    /// it will lock all the records involved in the transaction
542    /// till a [`commit`] or [`rollback`] is called.
543    ///
544    /// [`commit`]:struct.TransactionFinalize.html#method.commit
545    /// [`rollback`]:struct.TransactionFinalize.html#method.rollback
546    ///
547    /// # Example
548    ///
549    /// ```rust
550    /// # use persy::{OpenOptions};
551    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
552    /// # let persy = OpenOptions::new().memory()?;
553    /// let mut tx = persy.begin()?;
554    /// # tx.create_segment("seg")?;
555    /// //Do what ever operations on the records
556    /// let data = vec![1;20];
557    /// tx.insert("seg", &data)?;
558    /// tx.prepare()?;
559    /// # Ok(())
560    /// # }
561    /// ```
562    pub fn prepare(mut self) -> Result<TransactionFinalize, PE<PrepareError>> {
563        let real_tx = self.tx.take().unwrap();
564        Ok(TransactionFinalize {
565            persy_impl: self.persy_impl.clone(),
566            finalize: Some(self.persy_impl.prepare(real_tx)?),
567        })
568    }
569
570    /// List all the existing segments, considering all the changes in transaction.
571    ///
572    /// # Example
573    ///
574    /// ```rust
575    /// # use persy::{OpenOptions};
576    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
577    /// # let persy = OpenOptions::new().memory()?;
578    /// let mut tx = persy.begin()?;
579    /// tx.create_segment("seg")?;
580    /// let segments = tx.list_segments()?;
581    /// let names = segments.into_iter().map(|(name,_id)|name).collect::<Vec<String>>();
582    /// assert!(names.contains(&"seg".to_string()));
583    /// tx.prepare()?.commit()?;
584    /// # Ok(())
585    /// # }
586    /// ```
587    pub fn list_segments(&self) -> Result<Vec<(String, SegmentId)>, GenericError> {
588        Ok(self.persy_impl.list_segments_tx(self.tx()))
589    }
590
591    /// List all the existing indexes, considering changes in the transaction.
592    ///
593    /// # Example
594    ///
595    /// ```rust
596    /// # use persy::{OpenOptions, ValueMode};
597    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
598    /// # let persy = OpenOptions::new().memory()?;
599    /// let mut tx = persy.begin()?;
600    /// tx.create_index::<u8, u8>("idx", ValueMode::Replace)?;
601    /// let indexes = tx.list_indexes()?;
602    /// let names = indexes.into_iter().map(|(name,_id)|name).collect::<Vec<String>>();
603    /// assert!(names.contains(&"idx".to_string()));
604    /// tx.prepare()?.commit()?;
605    /// # Ok(())
606    /// # }
607    /// ```
608    pub fn list_indexes(&self) -> Result<Vec<(String, IndexInfo)>, PE<GenericError>> {
609        Ok(self.persy_impl.list_indexes_tx(self.tx()))
610    }
611
612    /// Prepare and Commit a transaction
613    ///
614    /// # Example
615    ///
616    /// ```rust
617    /// # use persy::{OpenOptions};
618    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
619    /// # let persy = OpenOptions::new().memory()?;
620    /// let mut tx = persy.begin()?;
621    /// # tx.create_segment("seg")?;
622    /// //Do what ever operations on the records
623    /// let data = vec![1;20];
624    /// tx.insert("seg", &data)?;
625    /// tx.commit()?;
626    /// # Ok(())
627    /// # }
628    /// ```
629    pub fn commit(mut self) -> Result<(), PE<PrepareError>> {
630        let real_tx = self.tx.take().unwrap();
631        let mut finalize = self.persy_impl.prepare(real_tx)?;
632        self.persy_impl.commit(&mut finalize)?;
633        Ok(())
634    }
635}
636
637impl Drop for Transaction {
638    fn drop(&mut self) {
639        if let Some(tx) = self.tx.take() {
640            self.persy_impl
641                .rollback(tx)
642                .expect("no failure on rollback transaction on drop");
643        }
644    }
645}
646
647/// prepared transaction state
648#[must_use]
649pub struct TransactionFinalize {
650    persy_impl: Arc<PersyImpl>,
651    finalize: Option<TxFinalize>,
652}
653
654impl TransactionFinalize {
655    /// Rollback a prepared commit.
656    ///
657    /// All the modification are rolled back and all the used resources are put released
658    ///
659    /// # Example
660    ///
661    /// ```rust
662    /// # use persy::{OpenOptions};
663    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
664    /// # let persy = OpenOptions::new().memory()?;
665    /// # let mut tx = persy.begin()?;
666    /// # tx.create_segment("seg")?;
667    /// # tx.prepare()?.commit()?;
668    /// let mut tx = persy.begin()?;
669    /// //Do what ever operations on the records
670    /// let data = vec![1;20];
671    /// tx.insert("seg", &data)?;
672    /// let prepared = tx.prepare()?;
673    /// prepared.rollback()?;
674    /// # Ok(())
675    /// # }
676    /// ```
677    pub fn rollback(mut self) -> Result<(), PE<GenericError>> {
678        if let Some(mut finalize) = self.finalize.take() {
679            self.persy_impl.rollback_prepared(&mut finalize)?;
680        }
681        Ok(())
682    }
683
684    /// Finalize the commit result of a prepared commit.
685    ///
686    /// All the operation done on the transaction are finalized all the lock released, all the
687    /// old resources are released for reuse.
688    ///
689    /// # Example
690    ///
691    /// ```rust
692    /// # use persy::{OpenOptions};
693    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
694    /// # let persy = OpenOptions::new().memory()?;
695    /// # let mut tx = persy.begin()?;
696    /// # tx.create_segment("seg")?;
697    /// # tx.prepare()?.commit()?;
698    /// let mut tx = persy.begin()?;
699    /// let prepared = tx.prepare()?;
700    /// prepared.commit()?;
701    /// # Ok(())
702    /// # }
703    /// ```
704    pub fn commit(mut self) -> Result<(), PE<GenericError>> {
705        if let Some(mut finalize) = self.finalize.take() {
706            self.persy_impl.commit(&mut finalize)?;
707        }
708        Ok(())
709    }
710
711    /// Prepare and Commit a transaction
712    ///
713    /// # Example
714    ///
715    /// ```rust
716    /// # use persy::{OpenOptions};
717    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
718    /// # let persy = OpenOptions::new().memory()?;
719    /// let mut tx = persy.begin()?;
720    /// # tx.create_segment("seg")?;
721    /// //Do what ever operations on the records
722    /// let data = vec![1;20];
723    /// tx.insert("seg", &data)?;
724    /// let prepared = tx.prepare()?;
725    /// let snapshot = prepared.commit_to_snapshot()?;
726    /// # Ok(())
727    /// # }
728    /// ```
729    pub fn commit_to_snapshot(mut self) -> Result<Snapshot, PE<PrepareError>> {
730        let mut finalize = self.finalize.take().expect("at this state is there all the times");
731
732        let pre_segs = self.persy_impl.address().snapshot_list();
733        let snap = self.persy_impl.commit(&mut finalize)?;
734        let snap = self.persy_impl.fill_snapshot_tx(&snap, pre_segs, &finalize.transaction);
735        Ok(Snapshot::new(self.persy_impl.clone(), snap))
736    }
737
738    #[cfg(test)]
739    pub(crate) fn leak(mut self) {
740        if let Some(mut finalize) = self.finalize.take() {
741            finalize.leak();
742        }
743    }
744}
745
746impl Drop for TransactionFinalize {
747    fn drop(&mut self) {
748        if let Some(mut finalize) = self.finalize.take() {
749            self.persy_impl
750                .rollback_prepared(&mut finalize)
751                .expect("no failure on rollback transaction on drop");
752        }
753    }
754}