oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1use crate::block::{BlockCell, ClientID, GC};
2use crate::{TransactionMut, ID};
3use std::collections::HashMap;
4
5#[derive(Default)]
6pub(crate) struct GCCollector {
7 items: HashMap<ClientID, Vec<u32>>,
8}
9
10impl GCCollector {
11 /// Garbage collect all blocks deleted within current transaction scope.
12 pub fn collect(txn: &mut TransactionMut) {
13 let mut gc = Self::default();
14 gc.mark_in_scope(txn);
15 gc.collect_all_marked(txn);
16 }
17
18 /// Garbage collect all deleted blocks from current transaction's document store.
19 pub fn collect_all(txn: &mut TransactionMut) {
20 let mut gc = Self::default();
21 gc.mark_all(txn);
22 gc.collect_all_marked(txn);
23 }
24
25 /// Mark deleted items based on a current transaction delete set.
26 fn mark_in_scope(&mut self, txn: &mut TransactionMut) {
27 for (client, range) in txn.delete_set.iter() {
28 if let Some(blocks) = txn.store.blocks.get_client_mut(client) {
29 for delete_item in range.iter().rev() {
30 let mut start = delete_item.start;
31 if let Some(mut i) = blocks.find_pivot(start) {
32 while i < blocks.len() {
33 let block = &mut blocks[i];
34 let len = block.len();
35 start += len;
36 if start > delete_item.end {
37 break;
38 } else {
39 if let BlockCell::Block(item) = block {
40 item.gc(self, false);
41 }
42 i += 1;
43 }
44 }
45 }
46 }
47 }
48 }
49 }
50
51 fn mark_all(&mut self, txn: &mut TransactionMut) {
52 for (_, client_blocks) in txn.store.blocks.iter_mut() {
53 for block in client_blocks.iter_mut() {
54 if let BlockCell::Block(item) = block {
55 if item.is_deleted() {
56 item.gc(self, false);
57 txn.merge_blocks.push(item.id);
58 }
59 }
60 }
61 }
62 }
63
64 /// Marks item with a given [ID] as a candidate for being GCed.
65 pub(crate) fn mark(&mut self, id: &ID) {
66 let client = self.items.entry(id.client).or_default();
67 client.push(id.clock);
68 }
69
70 /// Garbage collects all items marked for GC.
71 fn collect_all_marked(self, txn: &mut TransactionMut) {
72 for (client_id, clocks) in self.items.into_iter() {
73 let client = txn.store.blocks.get_client_blocks_mut(client_id);
74 for clock in clocks {
75 if let Some(index) = client.find_pivot(clock) {
76 let block = &mut client[index];
77 if let BlockCell::Block(item) = block {
78 if item.is_deleted() && !item.info.is_keep() {
79 let (start, end) = item.clock_range();
80 let gc = BlockCell::GC(GC::new(start, end));
81 *block = gc;
82 }
83 }
84 }
85 }
86 }
87 }
88}
89