ckb_store/
write_batch.rs

1use ckb_db::RocksDBWriteBatch;
2use ckb_db_schema::{
3    COLUMN_BLOCK_BODY, COLUMN_BLOCK_EXTENSION, COLUMN_BLOCK_HEADER, COLUMN_BLOCK_PROPOSAL_IDS,
4    COLUMN_BLOCK_UNCLE, COLUMN_CELL, COLUMN_CELL_DATA, COLUMN_CELL_DATA_HASH, COLUMN_NUMBER_HASH,
5    Col,
6};
7use ckb_error::Error;
8use ckb_types::{core::BlockNumber, packed, prelude::*};
9
10/// Wrapper of `RocksDBWriteBatch`, provides atomic batch of write operations.
11pub struct StoreWriteBatch {
12    pub(crate) inner: RocksDBWriteBatch,
13}
14
15impl StoreWriteBatch {
16    /// Write the bytes into the given column with associated key.
17    pub fn put(&mut self, col: Col, key: &[u8], value: &[u8]) -> Result<(), Error> {
18        self.inner.put(col, key, value)
19    }
20
21    /// Delete the data associated with the given key and given column.
22    pub fn delete(&mut self, col: Col, key: &[u8]) -> Result<(), Error> {
23        self.inner.delete(col, key)
24    }
25
26    /// Return WriteBatch serialized size (in bytes).
27    pub fn size_in_bytes(&self) -> usize {
28        self.inner.size_in_bytes()
29    }
30
31    /// Return the count of write batch.
32    pub fn len(&self) -> usize {
33        self.inner.len()
34    }
35
36    /// Returns true if the write batch contains no operations.
37    pub fn is_empty(&self) -> bool {
38        self.inner.is_empty()
39    }
40
41    /// Clear all updates buffered in this batch.
42    pub fn clear(&mut self) -> Result<(), Error> {
43        self.inner.clear()
44    }
45
46    /// Put cells into this write batch
47    pub fn insert_cells(
48        &mut self,
49        cells: impl Iterator<
50            Item = (
51                packed::OutPoint,
52                packed::CellEntry,
53                Option<packed::CellDataEntry>,
54            ),
55        >,
56    ) -> Result<(), Error> {
57        for (out_point, cell, cell_data) in cells {
58            let key = out_point.to_cell_key();
59            self.put(COLUMN_CELL, &key, cell.as_slice())?;
60            if let Some(data) = cell_data {
61                self.put(COLUMN_CELL_DATA, &key, data.as_slice())?;
62                self.put(
63                    COLUMN_CELL_DATA_HASH,
64                    &key,
65                    data.output_data_hash().as_slice(),
66                )?;
67            } else {
68                self.put(COLUMN_CELL_DATA, &key, &[])?;
69                self.put(COLUMN_CELL_DATA_HASH, &key, &[])?;
70            }
71        }
72        Ok(())
73    }
74
75    /// Remove cells from this write batch
76    pub fn delete_cells(
77        &mut self,
78        out_points: impl Iterator<Item = packed::OutPoint>,
79    ) -> Result<(), Error> {
80        for out_point in out_points {
81            let key = out_point.to_cell_key();
82            self.delete(COLUMN_CELL, &key)?;
83            self.delete(COLUMN_CELL_DATA, &key)?;
84            self.delete(COLUMN_CELL_DATA_HASH, &key)?;
85        }
86
87        Ok(())
88    }
89
90    /// Removes the block body from database with corresponding hash, number and txs number
91    pub fn delete_block_body(
92        &mut self,
93        number: BlockNumber,
94        hash: &packed::Byte32,
95        txs_len: u32,
96    ) -> Result<(), Error> {
97        self.inner.delete(COLUMN_BLOCK_UNCLE, hash.as_slice())?;
98        self.inner.delete(COLUMN_BLOCK_EXTENSION, hash.as_slice())?;
99        self.inner
100            .delete(COLUMN_BLOCK_PROPOSAL_IDS, hash.as_slice())?;
101        self.inner.delete(
102            COLUMN_NUMBER_HASH,
103            packed::NumberHash::new_builder()
104                .number(number)
105                .block_hash(hash.clone())
106                .build()
107                .as_slice(),
108        )?;
109
110        let key_range = (0u32..txs_len).map(|i| {
111            packed::TransactionKey::new_builder()
112                .block_hash(hash.clone())
113                .index(i)
114                .build()
115        });
116
117        self.inner.delete_range(COLUMN_BLOCK_BODY, key_range)?;
118        Ok(())
119    }
120
121    /// Removes the entire block from database with corresponding hash, number and txs number
122    pub fn delete_block(
123        &mut self,
124        number: BlockNumber,
125        hash: &packed::Byte32,
126        txs_len: u32,
127    ) -> Result<(), Error> {
128        self.inner.delete(COLUMN_BLOCK_HEADER, hash.as_slice())?;
129        self.delete_block_body(number, hash, txs_len)
130    }
131}