From 6e0e4b3cb7b43aa76f0f5bae731d00a98beee7bb Mon Sep 17 00:00:00 2001 From: MattHalpinParity Date: Thu, 18 Apr 2024 13:21:10 +0100 Subject: [PATCH 1/6] Fix for recording dereferences --- src/db.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/db.rs b/src/db.rs index 55f7b272..40cc8a22 100644 --- a/src/db.rs +++ b/src/db.rs @@ -551,12 +551,15 @@ impl DbInner { ); let mut trees = self.trees.write(); - if let Some(column_trees) = trees.get_mut(&col) { - let count = - column_trees.to_dereference.get(&hash).unwrap_or(&0) + - 1; - column_trees.to_dereference.insert(hash, count); - } + + let column_trees = trees.entry(col).or_insert_with(|| Trees { + readers: Default::default(), + to_dereference: Default::default(), + }); + let count = + column_trees.to_dereference.get(&hash).unwrap_or(&0) + 1; + column_trees.to_dereference.insert(hash, count); + drop(trees); commit.check_for_deferral = true; From c479217bd7f8ec7e4b8910188bb516b09b5c0c44 Mon Sep 17 00:00:00 2001 From: MattHalpinParity Date: Thu, 18 Apr 2024 13:26:28 +0100 Subject: [PATCH 2/6] Added get_node_children. Also increase min refcount bits. --- src/column.rs | 23 +++++++++++++++++++-- src/db.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/column.rs b/src/column.rs index f50f9e09..e6a5d66c 100644 --- a/src/column.rs +++ b/src/column.rs @@ -30,7 +30,7 @@ use std::{ }; pub const MIN_INDEX_BITS: u8 = 16; -pub const MIN_REF_COUNT_BITS: u8 = 11; +pub const MIN_REF_COUNT_BITS: u8 = 16; // Measured in index entries const MAX_REINDEX_BATCH: usize = 8192; @@ -416,7 +416,7 @@ pub fn unpack_node_data(data: Vec) -> Result<(Vec, Children)> { return Err(Error::InvalidValueData) } let data_len = data.len() - (child_buf_len + 1); - let mut children = Children::new(); + let mut children = Children::with_capacity(num_children); for i in 0..num_children { let node_address = u64::from_le_bytes(data[data_len + i * 8..data_len + (i + 1) * 8].try_into().unwrap()); @@ -426,6 +426,25 @@ pub fn unpack_node_data(data: Vec) -> Result<(Vec, Children)> { Ok((data, children)) } +pub fn unpack_node_children(data: &Vec) -> Result { + if data.len() == 0 { + return Err(Error::InvalidValueData) + } + let num_children = data[data.len() - 1] as usize; + let child_buf_len = num_children * 8; + if data.len() < (child_buf_len + 1) { + return Err(Error::InvalidValueData) + } + let data_len = data.len() - (child_buf_len + 1); + let mut children = Children::with_capacity(num_children); + for i in 0..num_children { + let node_address = + u64::from_le_bytes(data[data_len + i * 8..data_len + (i + 1) * 8].try_into().unwrap()); + children.push(node_address); + } + Ok(children) +} + impl HashColumn { fn open( col: ColId, diff --git a/src/db.rs b/src/db.rs index 40cc8a22..2069c092 100644 --- a/src/db.rs +++ b/src/db.rs @@ -21,8 +21,8 @@ use crate::{ btree::{commit_overlay::BTreeChangeSet, BTreeIterator, BTreeTable}, column::{ - hash_key, unpack_node_data, ColId, Column, HashColumn, IterState, ReindexBatch, - ValueIterState, + hash_key, unpack_node_children, unpack_node_data, ColId, Column, HashColumn, IterState, + ReindexBatch, ValueIterState, }, error::{try_io, Error, Result}, hash::IdentityBuildHasher, @@ -375,6 +375,42 @@ impl DbInner { } } + fn get_node_children( + &self, + col: ColId, + node_address: NodeAddress, + external_call: bool, + ) -> Result> { + if !self.options.columns[col as usize].multitree { + return Err(Error::InvalidConfiguration("Not a multitree column.".to_string())) + } + if !self.options.columns[col as usize].append_only && + !self.options.columns[col as usize].allow_direct_node_access && + external_call + { + return Err(Error::InvalidConfiguration( + "get_node_children can only be called on a column with append_only or allow_direct_node_access options.".to_string(), + )) + } + match &self.columns[col as usize] { + Column::Hash(column) => { + let overlay = self.commit_overlay.read(); + // Check commit overlay first + if let Some(v) = overlay.get(col as usize).and_then(|o| o.get_address(node_address)) + { + return Ok(Some(unpack_node_children(v.value())?)) + } + let log = self.log.overlays(); + let value = column.get_value(Address::from_u64(node_address), log)?; + if let Some(data) = value { + return Ok(Some(unpack_node_children(&data)?)) + } + Ok(None) + }, + Column::Tree(_) => Err(Error::InvalidConfiguration("Not a HashColumn.".to_string())), + } + } + fn get_tree( &self, db: &Arc, @@ -1499,6 +1535,14 @@ impl Db { self.inner.get_node(col, node_address, true) } + pub fn get_node_children( + &self, + col: ColId, + node_address: NodeAddress, + ) -> Result> { + self.inner.get_node_children(col, node_address, true) + } + /// Commit a set of changes to the database. pub fn commit(&self, tx: I) -> Result<()> where @@ -1781,6 +1825,7 @@ impl Db { pub trait TreeReader { fn get_root(&self) -> Result, Children)>>; fn get_node(&self, node_address: NodeAddress) -> Result, Children)>>; + fn get_node_children(&self, node_address: NodeAddress) -> Result>; } #[derive(Debug)] @@ -1826,6 +1871,10 @@ impl TreeReader for DbTreeReader { fn get_node(&self, node_address: NodeAddress) -> Result, Children)>> { self.db.get_node(self.col, node_address, false) } + + fn get_node_children(&self, node_address: NodeAddress) -> Result> { + self.db.get_node_children(self.col, node_address, false) + } } pub type IndexedCommitOverlay = HashMap), IdentityBuildHasher>; @@ -2197,12 +2246,12 @@ impl IndexedChangeSet { writer: &mut crate::log::LogWriter, ) -> Result<()> { for address in children { - let node = guard.get_node(*address)?; let (remains, _outcome) = column.write_address_dec_ref_plan(*address, writer)?; if !remains { // Was removed *num_removed += 1; - if let Some((_node_data, children)) = node { + let node = guard.get_node_children(*address)?; + if let Some(children) = node { self.write_dereference_children_plan( column, guard, From 8d1bd9eb2084647fb85aaf9aa20465ff1c174c8b Mon Sep 17 00:00:00 2001 From: MattHalpinParity Date: Sat, 20 Apr 2024 16:49:33 +0100 Subject: [PATCH 3/6] Faster multitree bench --- admin/src/multitree_bench/data.rs | 1851 +---------------------------- admin/src/multitree_bench/mod.rs | 1291 +++++++++++--------- src/db.rs | 11 +- 3 files changed, 754 insertions(+), 2399 deletions(-) diff --git a/admin/src/multitree_bench/data.rs b/admin/src/multitree_bench/data.rs index 6b5e2488..167f1b64 100644 --- a/admin/src/multitree_bench/data.rs +++ b/admin/src/multitree_bench/data.rs @@ -33,1842 +33,21 @@ pub const DEPTH_CHILD_COUNT_HISTOGRAMS: &[(u32, [u32; 17])] = &[ (13, [12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), ]; -pub const DEPTH_AGE_HISTOGRAMS: &[(u32, &[(u32, u32)])] = &[ - ( - 0, - &[ - (0, 520), - (1, 20), - (2, 22), - (3, 10), - (4, 14), - (5, 6), - (6, 9), - (7, 5), - (8, 5), - (9, 4), - (10, 4), - (11, 4), - (12, 4), - (13, 3), - (14, 4), - (15, 3), - (16, 2), - (17, 2), - (18, 2), - (19, 2), - (20, 2), - (21, 1), - (22, 1), - (23, 1), - (24, 1), - (25, 1), - (26, 1), - (27, 1), - (28, 1), - (29, 1), - (30, 1), - (31, 1), - (32, 1), - (33, 1), - (34, 1), - (35, 1), - (36, 1), - (37, 1), - (38, 1), - (39, 1), - (40, 1), - (41, 1), - (42, 1), - (43, 1), - (44, 1), - (45, 1), - (46, 1), - (47, 1), - (48, 1), - (49, 1), - (50, 1), - (51, 1), - (52, 1), - (53, 1), - (54, 1), - (55, 1), - (56, 1), - (57, 1), - (58, 1), - (59, 1), - (60, 1), - (61, 1), - (62, 1), - (63, 1), - (64, 2), - (65, 2), - (66, 2), - (67, 2), - (68, 2), - (69, 2), - (70, 2), - (71, 2), - (72, 2), - (73, 2), - (74, 2), - (75, 2), - (76, 2), - (77, 2), - (78, 1), - (79, 1), - (80, 1), - (81, 1), - (82, 1), - (83, 1), - (84, 1), - (85, 1), - (86, 1), - (87, 1), - (88, 1), - (89, 1), - (90, 1), - (91, 1), - (92, 1), - (93, 1), - (94, 1), - (95, 1), - (96, 2), - (97, 2), - (98, 2), - (99, 2), - (100, 2), - (101, 2), - (102, 2), - (103, 2), - (104, 2), - (105, 2), - (106, 2), - (107, 2), - (108, 2), - (109, 2), - (110, 2), - (111, 2), - (112, 2), - (113, 2), - (114, 2), - (115, 2), - (116, 3), - (117, 3), - (118, 3), - (119, 3), - (120, 3), - (121, 3), - (122, 3), - (123, 3), - (124, 3), - (125, 3), - (126, 3), - (127, 3), - (128, 2), - (129, 2), - (130, 2), - (131, 2), - (132, 2), - (133, 2), - (134, 2), - (135, 2), - (136, 2), - (137, 2), - (138, 2), - (139, 2), - (140, 2), - (141, 2), - (142, 2), - (143, 2), - (144, 2), - (145, 2), - (146, 2), - (147, 2), - (148, 2), - (149, 2), - (150, 2), - (151, 2), - (152, 2), - (153, 2), - (154, 2), - (155, 2), - (156, 2), - (157, 2), - (158, 2), - (159, 2), - (160, 1), - (161, 1), - (162, 1), - (163, 1), - (164, 1), - (165, 1), - (166, 1), - (167, 1), - (168, 1), - (169, 1), - (170, 1), - (171, 1), - (172, 1), - (173, 1), - (174, 1), - (175, 1), - (176, 1), - (177, 1), - (178, 1), - (179, 1), - (192, 2), - (193, 2), - (194, 2), - (195, 2), - (196, 2), - (197, 2), - (198, 2), - (199, 2), - (200, 2), - (201, 2), - (202, 2), - (203, 2), - (204, 2), - (205, 2), - (206, 2), - (207, 2), - (208, 2), - (209, 2), - (210, 2), - (211, 2), - (212, 2), - (213, 2), - (214, 2), - (215, 2), - (216, 2), - (217, 2), - (218, 2), - (219, 2), - (220, 2), - (221, 2), - (222, 2), - (223, 2), - (224, 2), - (225, 2), - (226, 2), - (227, 2), - (228, 2), - (229, 2), - (230, 2), - (231, 2), - (232, 2), - (233, 2), - (234, 2), - (235, 2), - (236, 2), - (237, 2), - (238, 2), - (239, 2), - (240, 2), - (241, 2), - (242, 2), - (243, 2), - (244, 2), - (245, 2), - (246, 2), - (247, 2), - (248, 2), - (249, 2), - (250, 2), - (251, 2), - (252, 2), - (253, 2), - (254, 2), - (255, 2), - ], - ), - ( - 1, - &[ - (0, 799), - (1, 14), - (2, 10), - (3, 4), - (4, 3), - (5, 2), - (6, 1), - (7, 1), - (8, 2), - (9, 1), - (10, 1), - (11, 1), - (12, 1), - (29, 1), - (78, 1), - (79, 1), - (80, 1), - (81, 1), - (82, 1), - (83, 1), - (84, 1), - (85, 1), - (86, 1), - (87, 1), - (88, 1), - (89, 1), - (90, 1), - (91, 1), - (92, 1), - (93, 1), - (94, 1), - (95, 1), - (96, 1), - (97, 1), - (98, 1), - (99, 1), - (100, 1), - (101, 1), - (102, 1), - (103, 1), - (104, 1), - (105, 1), - (106, 1), - (107, 1), - (108, 1), - (109, 1), - (110, 1), - (111, 1), - (112, 1), - (113, 1), - (114, 1), - (115, 1), - (116, 1), - (117, 1), - (118, 1), - (119, 1), - (120, 1), - (121, 1), - (122, 1), - (123, 1), - (124, 1), - (125, 1), - (126, 1), - (127, 1), - (128, 1), - (129, 1), - (130, 1), - (131, 1), - (132, 1), - (133, 1), - (134, 1), - (135, 1), - (136, 1), - (137, 1), - (138, 1), - (139, 1), - (140, 1), - (141, 1), - (192, 15), - (193, 16), - (194, 15), - (195, 16), - (196, 16), - (197, 14), - (198, 15), - (199, 15), - (200, 15), - (201, 17), - (202, 15), - (203, 14), - (204, 17), - (205, 15), - (206, 15), - (207, 14), - (208, 17), - (209, 16), - (210, 15), - (211, 15), - (212, 15), - (213, 15), - (214, 15), - (215, 15), - (216, 17), - (217, 15), - (218, 15), - (219, 17), - (220, 15), - (221, 17), - (222, 17), - (223, 14), - (224, 17), - (225, 15), - (226, 15), - (227, 16), - (228, 15), - (229, 14), - (230, 15), - (231, 17), - (232, 17), - (233, 15), - (234, 15), - (235, 17), - (236, 15), - (237, 16), - (238, 15), - (239, 16), - (240, 15), - (241, 15), - (242, 15), - (243, 14), - (244, 15), - (245, 14), - (246, 15), - (247, 14), - (248, 15), - (249, 14), - (250, 15), - (251, 15), - (252, 17), - (253, 17), - (254, 15), - (255, 14), - ], - ), - ( - 2, - &[ - (0, 2054), - (1, 36), - (2, 22), - (3, 17), - (4, 14), - (5, 9), - (6, 11), - (7, 6), - (8, 8), - (9, 5), - (10, 2), - (11, 2), - (12, 6), - (13, 1), - (14, 1), - (15, 2), - (16, 3), - (17, 3), - (18, 1), - (19, 2), - (20, 3), - (21, 2), - (22, 3), - (23, 2), - (24, 2), - (25, 3), - (26, 2), - (27, 2), - (28, 4), - (29, 2), - (30, 2), - (31, 3), - (32, 3), - (33, 3), - (34, 2), - (35, 2), - (36, 3), - (37, 2), - (38, 1), - (39, 2), - (40, 2), - (41, 1), - (42, 1), - (43, 2), - (44, 1), - (45, 2), - (46, 2), - (47, 1), - (48, 1), - (51, 1), - (60, 1), - (66, 1), - (86, 1), - (88, 1), - (105, 1), - (108, 1), - (109, 2), - (111, 1), - (112, 2), - (116, 1), - (124, 1), - (136, 1), - (154, 1), - (156, 1), - (160, 1), - (162, 1), - (166, 1), - (168, 1), - (170, 1), - (172, 2), - (176, 1), - (180, 1), - (182, 1), - (184, 1), - (192, 24), - (193, 18), - (194, 19), - (195, 18), - (196, 19), - (197, 18), - (198, 21), - (199, 19), - (200, 21), - (201, 19), - (202, 20), - (203, 18), - (204, 19), - (205, 19), - (206, 19), - (207, 23), - (208, 19), - (209, 18), - (210, 21), - (211, 19), - (212, 21), - (213, 19), - (214, 19), - (215, 20), - (216, 19), - (217, 19), - (218, 19), - (219, 19), - (220, 20), - (221, 19), - (222, 20), - (223, 18), - (224, 19), - (225, 19), - (226, 19), - (227, 18), - (228, 20), - (229, 18), - (230, 20), - (231, 19), - (232, 22), - (233, 19), - (234, 19), - (235, 19), - (236, 20), - (237, 18), - (238, 19), - (239, 18), - (240, 19), - (241, 19), - (242, 21), - (243, 18), - (244, 20), - (245, 18), - (246, 19), - (247, 18), - (248, 19), - (249, 18), - (250, 19), - (251, 19), - (252, 24), - (253, 19), - (254, 19), - (255, 18), - ], - ), - ( - 3, - &[ - (0, 3912), - (1, 395), - (2, 102), - (3, 97), - (4, 69), - (5, 72), - (6, 59), - (7, 60), - (8, 58), - (9, 41), - (10, 42), - (11, 45), - (12, 44), - (13, 49), - (14, 39), - (15, 37), - (16, 30), - (17, 25), - (18, 28), - (19, 23), - (20, 26), - (21, 23), - (22, 19), - (23, 24), - (24, 17), - (25, 15), - (26, 18), - (27, 16), - (28, 19), - (29, 17), - (30, 15), - (31, 17), - (32, 12), - (33, 15), - (34, 12), - (35, 9), - (36, 10), - (37, 9), - (38, 9), - (39, 9), - (40, 9), - (41, 11), - (42, 8), - (43, 8), - (44, 11), - (45, 10), - (46, 7), - (47, 6), - (48, 8), - (49, 6), - (50, 6), - (51, 7), - (52, 6), - (53, 7), - (54, 7), - (55, 6), - (56, 8), - (57, 4), - (58, 6), - (59, 6), - (60, 7), - (61, 4), - (62, 6), - (63, 6), - (64, 5), - (65, 5), - (66, 4), - (67, 5), - (68, 4), - (69, 5), - (70, 4), - (71, 7), - (72, 6), - (73, 6), - (74, 4), - (75, 4), - (76, 3), - (77, 3), - (78, 6), - (79, 3), - (80, 2), - (81, 2), - (82, 1), - (83, 1), - (84, 2), - (85, 2), - (86, 1), - (87, 2), - (88, 3), - (91, 2), - (92, 2), - (95, 1), - (96, 1), - (100, 1), - (103, 1), - (106, 1), - (108, 1), - (112, 1), - (114, 1), - (116, 2), - (117, 4), - (119, 1), - (132, 4), - (133, 2), - (134, 3), - (135, 1), - (140, 2), - (149, 1), - (150, 2), - (151, 1), - (161, 2), - (165, 3), - (168, 3), - (173, 3), - (177, 3), - (179, 2), - (183, 3), - (191, 3), - (192, 28), - (193, 21), - (194, 22), - (195, 20), - (196, 20), - (197, 20), - (198, 20), - (199, 19), - (200, 20), - (201, 19), - (202, 20), - (203, 20), - (204, 20), - (205, 20), - (206, 20), - (207, 38), - (208, 20), - (209, 20), - (210, 24), - (211, 20), - (212, 22), - (213, 20), - (214, 20), - (215, 21), - (216, 20), - (217, 19), - (218, 20), - (219, 19), - (220, 20), - (221, 20), - (222, 21), - (223, 20), - (224, 21), - (225, 21), - (226, 20), - (227, 21), - (228, 22), - (229, 20), - (230, 20), - (231, 20), - (232, 20), - (233, 20), - (234, 20), - (235, 21), - (236, 21), - (237, 20), - (238, 21), - (239, 20), - (240, 20), - (241, 20), - (242, 20), - (243, 20), - (244, 21), - (245, 20), - (246, 21), - (247, 20), - (248, 20), - (249, 20), - (250, 19), - (251, 19), - (252, 36), - (253, 20), - (254, 21), - (255, 20), - ], - ), - ( - 4, - &[ - (0, 14998), - (1, 1032), - (2, 194), - (3, 129), - (4, 91), - (5, 83), - (6, 55), - (7, 51), - (8, 51), - (9, 53), - (10, 47), - (11, 44), - (12, 35), - (13, 35), - (14, 27), - (15, 30), - (16, 25), - (17, 20), - (18, 25), - (19, 23), - (20, 15), - (21, 19), - (22, 16), - (23, 16), - (24, 13), - (25, 18), - (26, 13), - (27, 10), - (28, 13), - (29, 7), - (30, 5), - (31, 14), - (32, 7), - (33, 9), - (34, 17), - (35, 4), - (36, 6), - (37, 13), - (38, 10), - (39, 12), - (40, 6), - (41, 5), - (42, 15), - (43, 10), - (44, 9), - (45, 13), - (46, 12), - (47, 8), - (48, 7), - (49, 6), - (50, 5), - (51, 6), - (52, 2), - (53, 5), - (54, 6), - (55, 6), - (56, 7), - (57, 18), - (58, 2), - (59, 9), - (60, 16), - (61, 4), - (62, 17), - (63, 6), - (64, 7), - (65, 5), - (66, 7), - (67, 1), - (68, 5), - (69, 5), - (70, 5), - (71, 6), - (72, 8), - (73, 6), - (74, 7), - (75, 7), - (76, 4), - (77, 4), - (78, 7), - (79, 5), - (80, 6), - (81, 5), - (82, 2), - (83, 10), - (84, 6), - (85, 8), - (86, 6), - (87, 5), - (88, 5), - (89, 4), - (90, 6), - (91, 7), - (92, 3), - (93, 4), - (94, 5), - (95, 6), - (96, 9), - (97, 1), - (98, 4), - (99, 11), - (100, 6), - (101, 4), - (102, 7), - (103, 5), - (104, 4), - (105, 4), - (106, 8), - (107, 6), - (108, 1), - (109, 6), - (110, 2), - (111, 3), - (112, 2), - (113, 5), - (114, 1), - (115, 2), - (116, 4), - (117, 7), - (118, 5), - (119, 9), - (120, 5), - (121, 5), - (122, 4), - (123, 2), - (124, 4), - (125, 5), - (126, 4), - (127, 7), - (128, 7), - (129, 1), - (130, 3), - (131, 3), - (132, 2), - (133, 5), - (134, 7), - (135, 7), - (136, 7), - (137, 4), - (138, 4), - (139, 2), - (140, 11), - (141, 7), - (142, 4), - (143, 4), - (144, 2), - (145, 5), - (146, 3), - (147, 2), - (148, 3), - (149, 5), - (150, 5), - (151, 4), - (152, 5), - (153, 7), - (154, 3), - (155, 5), - (156, 5), - (157, 7), - (158, 4), - (159, 5), - (160, 4), - (161, 6), - (162, 2), - (163, 4), - (164, 8), - (165, 4), - (166, 4), - (167, 6), - (168, 15), - (169, 5), - (170, 7), - (171, 13), - (172, 1), - (173, 2), - (174, 3), - (175, 2), - (176, 12), - (177, 4), - (178, 3), - (179, 15), - (180, 5), - (181, 2), - (182, 6), - (183, 20), - (184, 10), - (185, 5), - (186, 1), - (187, 2), - (188, 6), - (189, 4), - (190, 3), - (191, 14), - (192, 74), - (193, 21), - (194, 45), - (195, 32), - (196, 36), - (197, 25), - (198, 23), - (199, 52), - (200, 44), - (201, 16), - (202, 44), - (203, 35), - (204, 18), - (205, 15), - (206, 30), - (207, 67), - (208, 39), - (209, 14), - (210, 29), - (211, 16), - (212, 31), - (213, 16), - (214, 27), - (215, 53), - (216, 21), - (217, 35), - (218, 49), - (219, 12), - (220, 62), - (221, 30), - (222, 19), - (223, 31), - (224, 20), - (225, 14), - (226, 30), - (227, 21), - (228, 31), - (229, 12), - (230, 32), - (231, 28), - (232, 18), - (233, 17), - (234, 38), - (235, 9), - (236, 43), - (237, 12), - (238, 31), - (239, 11), - (240, 22), - (241, 11), - (242, 20), - (243, 10), - (244, 22), - (245, 13), - (246, 22), - (247, 9), - (248, 18), - (249, 14), - (250, 40), - (251, 21), - (252, 94), - (253, 12), - (254, 19), - (255, 10), - ], - ), - ( - 5, - &[ - (0, 12542), - (1, 790), - (2, 646), - (3, 605), - (4, 561), - (5, 533), - (6, 524), - (7, 450), - (8, 417), - (9, 422), - (10, 346), - (11, 334), - (12, 303), - (13, 315), - (14, 278), - (15, 245), - (16, 246), - (17, 251), - (18, 223), - (19, 207), - (20, 188), - (21, 159), - (22, 182), - (23, 165), - (24, 159), - (25, 146), - (26, 137), - (27, 121), - (28, 119), - (29, 110), - (30, 113), - (31, 106), - (32, 98), - (33, 92), - (34, 82), - (35, 87), - (36, 68), - (37, 75), - (38, 70), - (39, 57), - (40, 68), - (41, 68), - (42, 52), - (43, 52), - (44, 45), - (45, 43), - (46, 42), - (47, 39), - (48, 39), - (49, 34), - (50, 37), - (51, 35), - (52, 25), - (53, 28), - (54, 26), - (55, 30), - (56, 31), - (57, 32), - (58, 32), - (59, 24), - (60, 27), - (61, 17), - (62, 27), - (63, 24), - (64, 20), - (65, 18), - (66, 20), - (67, 23), - (68, 18), - (69, 11), - (70, 11), - (71, 20), - (72, 20), - (73, 12), - (74, 13), - (75, 11), - (76, 19), - (77, 7), - (78, 12), - (79, 13), - (80, 12), - (81, 10), - (82, 6), - (83, 7), - (84, 10), - (85, 7), - (86, 8), - (87, 9), - (88, 13), - (89, 8), - (90, 8), - (91, 7), - (92, 11), - (93, 7), - (94, 6), - (95, 12), - (96, 9), - (97, 8), - (98, 8), - (99, 9), - (100, 10), - (101, 5), - (102, 4), - (103, 11), - (104, 10), - (105, 12), - (106, 5), - (107, 9), - (108, 5), - (109, 9), - (110, 8), - (111, 7), - (112, 7), - (113, 4), - (114, 3), - (115, 8), - (116, 9), - (117, 8), - (118, 3), - (119, 6), - (120, 6), - (121, 2), - (122, 8), - (123, 4), - (124, 7), - (125, 11), - (126, 4), - (127, 7), - (128, 7), - (129, 7), - (130, 6), - (131, 7), - (132, 5), - (133, 8), - (134, 7), - (135, 6), - (136, 7), - (137, 7), - (138, 9), - (139, 5), - (140, 4), - (141, 4), - (142, 5), - (143, 5), - (145, 4), - (146, 3), - (147, 6), - (148, 6), - (149, 4), - (150, 5), - (151, 2), - (152, 4), - (153, 3), - (154, 3), - (155, 4), - (156, 6), - (157, 6), - (159, 2), - (160, 8), - (161, 3), - (162, 2), - (163, 4), - (164, 3), - (165, 8), - (166, 7), - (167, 5), - (168, 10), - (169, 5), - (170, 5), - (171, 7), - (172, 3), - (173, 3), - (174, 4), - (175, 5), - (176, 6), - (177, 2), - (178, 2), - (179, 5), - (180, 5), - (181, 2), - (182, 1), - (183, 5), - (184, 4), - (185, 6), - (186, 7), - (187, 8), - (188, 4), - (189, 3), - (190, 4), - (191, 5), - (192, 128), - (193, 23), - (194, 67), - (195, 79), - (196, 34), - (197, 27), - (198, 27), - (199, 31), - (200, 78), - (201, 31), - (202, 31), - (203, 76), - (204, 27), - (205, 28), - (206, 24), - (207, 136), - (208, 83), - (209, 27), - (210, 23), - (211, 24), - (212, 27), - (213, 26), - (214, 33), - (215, 162), - (216, 25), - (217, 27), - (218, 106), - (219, 18), - (220, 112), - (221, 64), - (222, 22), - (223, 79), - (224, 22), - (225, 19), - (226, 82), - (227, 24), - (228, 25), - (229, 24), - (230, 61), - (231, 59), - (232, 22), - (233, 23), - (234, 76), - (235, 20), - (236, 95), - (237, 20), - (238, 69), - (239, 22), - (240, 21), - (241, 17), - (242, 21), - (243, 19), - (244, 18), - (245, 18), - (246, 22), - (247, 19), - (248, 22), - (249, 19), - (250, 26), - (251, 71), - (252, 192), - (253, 18), - (254, 22), - (255, 18), - ], - ), - ( - 6, - &[ - (0, 2615), - (1, 81), - (2, 62), - (3, 64), - (4, 75), - (5, 81), - (6, 77), - (7, 76), - (8, 64), - (9, 82), - (10, 73), - (11, 66), - (12, 67), - (13, 70), - (14, 78), - (15, 71), - (16, 70), - (17, 69), - (18, 67), - (19, 56), - (20, 65), - (21, 65), - (22, 84), - (23, 88), - (24, 66), - (25, 65), - (26, 58), - (27, 70), - (28, 55), - (29, 70), - (30, 64), - (31, 55), - (32, 53), - (33, 62), - (34, 75), - (35, 77), - (36, 62), - (37, 63), - (38, 68), - (39, 69), - (40, 55), - (41, 75), - (42, 68), - (43, 55), - (44, 74), - (45, 59), - (46, 50), - (47, 55), - (48, 64), - (49, 44), - (50, 67), - (51, 69), - (52, 57), - (53, 55), - (54, 61), - (55, 61), - (56, 57), - (57, 45), - (58, 63), - (59, 51), - (60, 65), - (61, 48), - (62, 64), - (63, 61), - (64, 49), - (65, 63), - (66, 50), - (67, 48), - (68, 57), - (69, 42), - (70, 59), - (71, 44), - (72, 51), - (73, 49), - (74, 59), - (75, 52), - (76, 46), - (77, 48), - (78, 59), - (79, 41), - (80, 53), - (81, 66), - (82, 57), - (83, 49), - (84, 37), - (85, 49), - (86, 54), - (87, 42), - (88, 54), - (89, 39), - (90, 42), - (91, 50), - (92, 57), - (93, 49), - (94, 53), - (95, 58), - (96, 50), - (97, 48), - (98, 40), - (99, 47), - (100, 46), - (101, 60), - (102, 40), - (103, 39), - (104, 41), - (105, 41), - (106, 46), - (107, 38), - (108, 40), - (109, 48), - (110, 45), - (111, 43), - (112, 47), - (113, 50), - (114, 49), - (115, 56), - (116, 54), - (117, 51), - (118, 64), - (119, 33), - (120, 38), - (121, 54), - (122, 49), - (123, 56), - (124, 46), - (125, 51), - (126, 55), - (127, 48), - (128, 42), - (129, 55), - (130, 55), - (131, 31), - (132, 48), - (133, 55), - (134, 31), - (135, 37), - (136, 44), - (137, 52), - (138, 38), - (139, 39), - (140, 40), - (141, 43), - (142, 46), - (143, 37), - (144, 56), - (145, 35), - (146, 38), - (147, 39), - (148, 39), - (149, 25), - (150, 41), - (151, 41), - (152, 47), - (153, 38), - (154, 40), - (155, 37), - (156, 33), - (157, 34), - (158, 36), - (159, 33), - (160, 40), - (161, 39), - (162, 31), - (163, 36), - (164, 48), - (165, 39), - (166, 35), - (167, 33), - (168, 42), - (169, 33), - (170, 28), - (171, 31), - (172, 31), - (173, 36), - (174, 41), - (175, 33), - (176, 31), - (177, 39), - (178, 29), - (179, 38), - (180, 34), - (181, 33), - (182, 34), - (183, 39), - (184, 36), - (185, 27), - (186, 27), - (187, 23), - (188, 39), - (189, 23), - (190, 30), - (191, 33), - (192, 207), - (193, 111), - (194, 134), - (195, 169), - (196, 128), - (197, 124), - (198, 108), - (199, 90), - (200, 182), - (201, 123), - (202, 109), - (203, 161), - (204, 108), - (205, 105), - (206, 127), - (207, 222), - (208, 176), - (209, 101), - (210, 111), - (211, 101), - (212, 120), - (213, 80), - (214, 136), - (215, 230), - (216, 101), - (217, 100), - (218, 173), - (219, 90), - (220, 202), - (221, 138), - (222, 93), - (223, 150), - (224, 89), - (225, 79), - (226, 170), - (227, 87), - (228, 95), - (229, 86), - (230, 138), - (231, 137), - (232, 99), - (233, 77), - (234, 158), - (235, 78), - (236, 177), - (237, 83), - (238, 155), - (239, 80), - (240, 93), - (241, 77), - (242, 108), - (243, 64), - (244, 90), - (245, 77), - (246, 81), - (247, 76), - (248, 77), - (249, 67), - (250, 88), - (251, 128), - (252, 264), - (253, 72), - (254, 76), - (255, 78), - ], - ), - ( - 7, - &[ - (0, 1579), - (1, 6), - (2, 9), - (3, 3), - (4, 7), - (5, 6), - (6, 6), - (7, 8), - (8, 4), - (9, 4), - (10, 4), - (11, 6), - (12, 4), - (13, 3), - (14, 8), - (15, 2), - (16, 5), - (17, 6), - (18, 7), - (19, 9), - (20, 3), - (21, 8), - (22, 5), - (23, 7), - (24, 1), - (25, 9), - (26, 12), - (27, 1), - (28, 5), - (29, 7), - (30, 8), - (31, 1), - (33, 5), - (34, 3), - (35, 6), - (36, 6), - (37, 4), - (38, 1), - (39, 7), - (40, 8), - (41, 4), - (42, 4), - (43, 5), - (44, 2), - (45, 6), - (46, 4), - (47, 8), - (48, 9), - (49, 4), - (50, 2), - (51, 4), - (52, 4), - (53, 11), - (54, 1), - (55, 2), - (56, 5), - (57, 10), - (58, 3), - (59, 2), - (60, 5), - (61, 4), - (62, 11), - (64, 2), - (65, 2), - (66, 12), - (67, 6), - (68, 10), - (69, 3), - (70, 2), - (71, 12), - (72, 4), - (73, 4), - (74, 4), - (75, 9), - (76, 7), - (77, 3), - (78, 8), - (79, 6), - (80, 2), - (81, 3), - (82, 5), - (83, 2), - (84, 8), - (85, 2), - (86, 3), - (87, 3), - (88, 2), - (89, 3), - (90, 6), - (91, 3), - (92, 4), - (93, 10), - (94, 7), - (95, 2), - (96, 1), - (97, 4), - (98, 12), - (99, 5), - (100, 4), - (101, 6), - (102, 3), - (103, 5), - (104, 9), - (105, 4), - (106, 4), - (107, 5), - (108, 8), - (109, 3), - (110, 2), - (111, 3), - (112, 8), - (113, 7), - (114, 5), - (115, 6), - (116, 5), - (117, 7), - (118, 3), - (119, 10), - (120, 5), - (121, 9), - (122, 3), - (123, 2), - (124, 2), - (125, 2), - (126, 8), - (127, 3), - (128, 7), - (129, 4), - (130, 2), - (131, 3), - (132, 7), - (133, 6), - (134, 6), - (135, 5), - (136, 3), - (137, 3), - (138, 10), - (139, 6), - (140, 1), - (141, 3), - (142, 6), - (143, 7), - (144, 11), - (145, 4), - (146, 5), - (147, 12), - (148, 4), - (149, 8), - (150, 4), - (151, 2), - (152, 4), - (153, 7), - (154, 6), - (155, 5), - (156, 6), - (157, 5), - (158, 8), - (159, 3), - (160, 1), - (161, 9), - (162, 8), - (163, 4), - (164, 6), - (165, 4), - (166, 7), - (167, 3), - (168, 7), - (169, 4), - (170, 5), - (171, 2), - (172, 5), - (173, 5), - (174, 6), - (175, 4), - (176, 2), - (177, 12), - (178, 4), - (179, 3), - (180, 4), - (181, 8), - (182, 6), - (183, 12), - (184, 6), - (185, 5), - (186, 1), - (187, 10), - (188, 6), - (189, 10), - (190, 7), - (191, 8), - (192, 76), - (193, 10), - (194, 45), - (195, 41), - (196, 13), - (197, 14), - (198, 12), - (199, 16), - (200, 62), - (201, 14), - (202, 12), - (203, 49), - (204, 14), - (205, 26), - (206, 12), - (207, 86), - (208, 49), - (209, 11), - (210, 22), - (211, 14), - (212, 18), - (213, 11), - (214, 20), - (215, 104), - (216, 19), - (217, 16), - (218, 61), - (219, 19), - (220, 72), - (221, 41), - (222, 7), - (223, 46), - (224, 19), - (225, 13), - (226, 59), - (227, 5), - (228, 15), - (229, 10), - (230, 35), - (231, 41), - (232, 11), - (233, 9), - (234, 58), - (235, 13), - (236, 66), - (237, 12), - (238, 50), - (239, 15), - (240, 10), - (241, 10), - (242, 11), - (243, 7), - (244, 15), - (245, 8), - (246, 15), - (247, 8), - (248, 13), - (249, 6), - (250, 7), - (251, 52), - (252, 120), - (253, 2), - (254, 19), - (255, 9), - ], - ), - ( - 8, - &[ - (0, 282), - (5, 1), - (11, 2), - (18, 2), - (20, 2), - (23, 2), - (24, 2), - (43, 2), - (54, 2), - (60, 2), - (68, 2), - (87, 2), - (95, 2), - (99, 2), - (127, 2), - (148, 2), - (158, 2), - (164, 2), - (169, 2), - (170, 2), - (185, 1), - (192, 19), - (194, 4), - (195, 4), - (200, 4), - (203, 7), - (207, 20), - (208, 5), - (212, 3), - (215, 18), - (218, 3), - (220, 7), - (221, 4), - (223, 4), - (225, 2), - (226, 5), - (229, 2), - (230, 3), - (231, 5), - (232, 2), - (234, 5), - (236, 17), - (238, 3), - (241, 2), - (245, 2), - (251, 12), - (252, 25), - (253, 2), - ], - ), - ( - 9, - &[ - (0, 14), - (28, 1), - (159, 2), - (192, 10), - (207, 12), - (215, 8), - (218, 2), - (236, 10), - (238, 1), - (252, 11), - ], - ), - (10, &[(0, 4), (192, 1), (207, 1), (215, 1), (252, 1)]), +pub const DEPTH_LEAF_COUNT_HISTOGRAM: &[(u32, u32)] = &[ + (0, 0), + (1, 0), + (2, 9), + (3, 79), + (4, 230), + (5, 1636), + (6, 5337), + (7, 38815), + (8, 605659), + (9, 950869), + (10, 190606), + (11, 50531), + (12, 2945), + (13, 12), ]; pub const VALUE_LENGTH_HISTOGRAM: &[(u32, u32)] = &[ diff --git a/admin/src/multitree_bench/mod.rs b/admin/src/multitree_bench/mod.rs index 7017c9e2..02919566 100644 --- a/admin/src/multitree_bench/mod.rs +++ b/admin/src/multitree_bench/mod.rs @@ -12,9 +12,8 @@ use parking_lot::{RwLock, RwLockReadGuard}; use rand::{RngCore, SeedableRng}; use std::{ - collections::{BTreeMap, HashMap, HashSet}, + collections::{BTreeMap, VecDeque}, io::Write, - ops::Deref, sync::{ atomic::{AtomicBool, AtomicUsize, Ordering}, Arc, @@ -30,15 +29,15 @@ static QUERIES: AtomicUsize = AtomicUsize::new(0); static ITERATIONS: AtomicUsize = AtomicUsize::new(0); static EXPECTED_NUM_ENTRIES: AtomicUsize = AtomicUsize::new(0); -static NUM_PATHS: AtomicUsize = AtomicUsize::new(0); -static NUM_PATHS_SUCCESS: AtomicUsize = AtomicUsize::new(0); - pub const TREE_COLUMN: u8 = 0; pub const INFO_COLUMN: u8 = 1; const KEY_LAST_COMMIT: Key = [1u8; 32]; const KEY_NUM_REMOVED: Key = [2u8; 32]; +const MAX_NUM_CHILDREN: usize = 16; +const NUM_TREES_TO_CACHE: usize = 3; + const THREAD_PRUNING: bool = true; const FORCE_NO_MULTIPART_VALUES: bool = true; const FIXED_TEXT_POSITION: bool = true; @@ -193,33 +192,48 @@ impl Histogram { } } -pub enum NodeSpec { - /// Direct specification of a node. (Tree index, depth, seed). - Direct(u64, u32, u64), - /// Node will be a path node but haven't done the work to generate the path yet. - UnresolvedPath(), - /// Path to another node. (Tree index, Path) where Path is a sequence of child indices starting - /// from the root of the tree. - Path(u64, Vec), +#[derive(Clone)] +enum ChildSpec { + /// New node. + New(Arc), + /// Node that existed in the previous tree at the specified previous index. + Existing(u8, Arc), + /// Replacement for a node that existed in the previous tree at the specified previous index. + Replacement(u8, Arc), +} + +impl ChildSpec { + fn get_child_as_ref(&self) -> &Arc { + match self { + ChildSpec::New(child) => child, + ChildSpec::Existing(_, child) => child, + ChildSpec::Replacement(_, child) => child, + } + } +} + +#[derive(Clone)] +struct NodeData { + data: Vec, + children: Vec, + leaf: bool, } struct ChainGenerator { depth_child_count_histograms: Vec, - depth_age_histograms: Vec, + depth_leaf_count_cumulative: Vec, value_length_histogram: Histogram, seed: u64, compressable: bool, - pruning: u64, } impl ChainGenerator { fn new( depth_child_count_histogram: &[(u32, [u32; 17])], - depth_age_histogram: &[(u32, &[(u32, u32)])], + depth_leaf_count_histogram: &[(u32, u32)], value_length_histogram: &[(u32, u32)], seed: u64, compressable: bool, - pruning: u64, ) -> ChainGenerator { let mut depth_child_count_histograms = Vec::default(); for (depth, histogram_data) in depth_child_count_histogram { @@ -232,24 +246,22 @@ impl ChainGenerator { depth_child_count_histograms.push(histogram); } - let mut depth_age_histograms = Vec::default(); - for (depth, histogram_data) in depth_age_histogram { - assert_eq!(*depth, depth_age_histograms.len() as u32); - - let histogram = Histogram::new(histogram_data); - - depth_age_histograms.push(histogram); + let mut depth_leaf_count_cumulative = Vec::new(); + let mut total = 0; + for entry in depth_leaf_count_histogram { + assert_eq!(entry.0, depth_leaf_count_cumulative.len() as u32); + total += entry.1; + depth_leaf_count_cumulative.push(total); } let value_length_histogram = Histogram::new(value_length_histogram); ChainGenerator { depth_child_count_histograms, - depth_age_histograms, + depth_leaf_count_cumulative, value_length_histogram, seed, compressable, - pruning, } } @@ -269,225 +281,374 @@ impl ChainGenerator { key } - fn num_node_children(&self, _tree_index: u64, depth: u32, seed: u64) -> u32 { + /// Returns tuple of node data and child specs. Child specs are depth and seed. + fn generate_node( + &self, + depth: u32, + seed: u64, + enumerated_depth_child_counts: &mut Vec>, + ) -> (Vec, Vec<(u32, u64)>) { let mut rng = rand::rngs::SmallRng::seed_from_u64(seed); - let num_children = if depth < self.depth_child_count_histograms.len() as u32 { - self.depth_child_count_histograms[depth as usize].sample(rng.next_u64()) - } else { - 0 - }; + let num_children = + enumerated_depth_child_counts.get_mut(depth as usize).map_or(None, |x| x.pop()); - num_children + let num_children = num_children.unwrap_or_else(|| { + self.depth_child_count_histograms + .get(depth as usize) + .map_or(0, |h| h.sample(rng.next_u64()) as usize) + }); + + let mut children = Vec::with_capacity(num_children as usize); + + for _ in 0..num_children { + children.push((depth + 1, rng.next_u64())); + } + + let v = self.generate_node_data(&mut rng, num_children == 0); + + (v, children) } - /// Returns tuple of node data and child specs. When only_direct_children is true node data will - /// be empty and non direct children will be NodeSpec::UnresolvedPath. - fn generate_node( + fn generate_node_data(&self, rng: &mut rand::rngs::SmallRng, leaf: bool) -> Vec { + // Polkadot doesn't store actual values in branch nodes, only in leaf nodes. Hence the value + // stored in the db will only be for the nibble path. + let mut size = 4; + if leaf { + // Leaf node, so simulate an actual value using the size histogram. + size = self.value_length_histogram.sample(rng.next_u64()) as usize; + if FORCE_NO_MULTIPART_VALUES { + size = std::cmp::min(size, 32760 - 64); + } + } + let mut v = Vec::new(); + + v.resize(size, 0); + let fill = if !self.compressable { size } else { size / 2 }; + rng.fill_bytes(&mut v[..fill]); + + v + } + + fn change_seed(&self, tree_index: u64) -> u64 { + use std::hash::Hasher; + let mut hasher = siphasher::sip::SipHasher24::new(); + hasher.write_u64(self.seed); + hasher.write_u64(tree_index); + hasher.write_u64(3); + let seed = hasher.finish(); + seed + } + + fn build_tree_with_changes( &self, tree_index: u64, - depth: u32, - seed: u64, - only_direct_children: bool, - ) -> (Vec, Vec) { - let mut rng = rand::rngs::SmallRng::seed_from_u64(seed); + previous_root_node: &NodeData, + ) -> Result { + let mut rng = rand::rngs::SmallRng::seed_from_u64(self.change_seed(tree_index)); + + // This results in about the right number of new nodes for each tree (AVERAGE_NUM_NEW_NODES) + let num_additions = 47; + let num_removals = (num_additions * 90) / 100; + + self.build_node_with_changes( + &mut rng, + Some(previous_root_node), + 0, + num_removals, + num_additions, + ) + } - let num_children = if depth < self.depth_child_count_histograms.len() as u32 { - self.depth_child_count_histograms[depth as usize].sample(rng.next_u64()) + fn build_node_with_changes( + &self, + rng: &mut rand::rngs::SmallRng, + previous_node: Option<&NodeData>, + depth: u32, + num_removals: u32, + num_additions: u32, + ) -> Result { + let mut num_children = 0; + let mut num_leaf_children: u32 = 0; + let mut num_branch_children: u32 = 0; + if let Some(previous_node) = previous_node { + num_children = previous_node.children.len(); + for child_node in previous_node.children.iter() { + if child_node.get_child_as_ref().leaf { + num_leaf_children += 1; + } else { + num_branch_children += 1; + } + } + } + assert!(num_children <= MAX_NUM_CHILDREN); + + // Tuple of (Existing index, Leaf, Num removals, Num additions) for each child + let mut child_changes = if let Some(previous_node) = previous_node { + let mut child_changes = Vec::with_capacity(previous_node.children.len()); + for (i, child_node) in previous_node.children.iter().enumerate() { + let leaf = child_node.get_child_as_ref().leaf; + child_changes.push((Some(i), leaf, 0, 0)); + } + child_changes } else { - 0 + Vec::new() }; - let mut children = Vec::with_capacity(num_children as usize); - for _i in 0..num_children { - let age = if depth < self.depth_age_histograms.len() as u32 { - self.depth_age_histograms[depth as usize].sample(rng.next_u64()) as u64 - } else { - // No age data for this depth. This implies the age is larger than was used when - // sampling. Hence use the oldest tree we can. - tree_index - }; + let mut num_removals = num_removals; - // Restrict to within the pruning window - let age = if self.pruning > 0 { std::cmp::min(age, self.pruning) } else { age }; + // Distribute removals and additions among children - let child_tree_index = if age > tree_index { 0 } else { tree_index - age }; + // Removals can be applied to any child, either passed down to branch children or leaf + // children can themselves be removed. - if child_tree_index == tree_index { - children.push(NodeSpec::Direct(tree_index, depth + 1, rng.next_u64())); - } else { - // Always generate path seed even if only_direct_children is true to ensure - // determinism. - let path_seed = rng.next_u64(); - if only_direct_children { - children.push(NodeSpec::UnresolvedPath()); + // Check if we should remove any leaf children + child_changes.retain(|x| { + if x.1 && num_removals > 0 { + let leaf_probability = 1.0 / (MAX_NUM_CHILDREN as f64); + let rand_float = (rng.next_u32() as f64) / (u32::MAX as f64); + if rand_float <= leaf_probability { + num_leaf_children -= 1; + num_children -= 1; + num_removals -= 1; + false } else { - // Generate path to node in child_tree_index - let mut path_rng = rand::rngs::SmallRng::seed_from_u64(path_seed); - let mut path_node: Option = None; - - let target_depth = depth + 1; - - for _ in 0..2 { - let mut other_tree_index = child_tree_index; - let mut other_depth = 0; - let mut other_seed = self.root_seed(child_tree_index); - let mut path = Vec::default(); - while other_depth < target_depth { - let (_other_node_data, other_children) = - self.generate_node(other_tree_index, other_depth, other_seed, true); - - let direct_children = - other_children.iter().enumerate().filter(|(_, x)| { - if let NodeSpec::Direct(..) = x { - true - } else { - false - } - }); - - let num_direct_children = direct_children.clone().count(); - - if num_direct_children == 0 { - break - } + true + } + } else { + true + } + }); - // Try to select a child that has more children itself so the path has a - // higher chance of success. - let mut num_grandchildren: Vec = - Vec::with_capacity(num_direct_children); - let mut min_grandchildren = u32::MAX; - let mut max_grandchildren = 0; - for (_index, node) in direct_children.clone() { - let num = if let NodeSpec::Direct(new_index, new_depth, new_seed) = - node - { - self.num_node_children(*new_index, *new_depth, *new_seed) - as usize - } else { - 0 - }; - min_grandchildren = std::cmp::min(min_grandchildren, num as u32); - max_grandchildren = std::cmp::max(max_grandchildren, num as u32); - num_grandchildren.push(num); - } - let direct_children: Vec<(usize, &NodeSpec)> = - if min_grandchildren < max_grandchildren { - // Can remove some - let diff = max_grandchildren - min_grandchildren; - let threshold = if diff > 1 { - min_grandchildren + diff / 2 - } else { - min_grandchildren - }; - direct_children - .enumerate() - .filter(|(index, _)| { - num_grandchildren[*index] as u32 > threshold - }) - .map(|(_, val)| val) - .collect::>() - } else { - direct_children.collect::>() - }; - - let num_direct_children = direct_children.len(); - - if num_direct_children == 0 { - break - } + let num_removal_slots = num_branch_children; + if num_removal_slots > 0 { + let mut removal_slots = Vec::with_capacity(num_removal_slots as usize); + for _ in 0..num_removal_slots { + removal_slots.push(0); + } - let child_index = path_rng.next_u64() % num_direct_children as u64; + // Allocate removals to removal_slots + let num_removals = if num_removals >= num_removal_slots { + let num_per_slot = num_removals / num_removal_slots; + for i in 0..num_removal_slots { + removal_slots[i as usize] += num_per_slot; + } + num_removals - (num_removal_slots * num_per_slot) + } else { + num_removals + }; + if num_removals > 0 { + assert!(num_removals < num_removal_slots); + let mut index = rng.next_u32() % num_removal_slots; + for _ in 0..num_removals { + removal_slots[index as usize] += 1; + index = (index + 1) % num_removal_slots; + } + } - let child = direct_children[child_index as usize]; - if let NodeSpec::Direct(new_index, new_depth, new_seed) = child.1 { - path.push(child.0 as u32); + let mut slot_index = 0; + for child in child_changes.iter_mut() { + if !child.1 { + child.2 += removal_slots[slot_index]; + slot_index += 1; + } + } + } - // Chose a direct node so should be same tree, one depth down. - assert_eq!(*new_index, other_tree_index); - assert_eq!(*new_depth, other_depth + 1); + // Based on depth leaf count histogram a certain number of additions should happen now as + // new leaf child nodes + let num_immediate_additions = + if depth as usize >= self.depth_leaf_count_cumulative.len() - 2 { + num_additions + } else { + let num = self.depth_leaf_count_cumulative[(depth + 1) as usize] - + self.depth_leaf_count_cumulative[depth as usize]; + let total = self.depth_leaf_count_cumulative + [self.depth_leaf_count_cumulative.len() - 1] - + self.depth_leaf_count_cumulative[depth as usize]; + if num_additions == 1 { + let probability = num as f64 / total as f64; + let rand_float = (rng.next_u32() as f64) / (u32::MAX as f64); + if rand_float <= probability { + 1 + } else { + 0 + } + } else { + (num * num_additions) / total + } + }; + // Each immediate addition needs a new leaf node so make sure we don't end up with more than + // 16 children. TODO: Would be better to split this node and allow all immediate additions. + let num_immediate_additions = + std::cmp::min(num_immediate_additions, (MAX_NUM_CHILDREN - num_children) as u32); + let num_additions = if depth as usize >= self.depth_leaf_count_cumulative.len() - 2 { + 0 + } else { + num_additions - num_immediate_additions + }; - other_tree_index = *new_index; - other_depth = *new_depth; - other_seed = *new_seed; + // Additions should not necessarilly go to an existing child. It goes to 1 of 16 slots. + // The children each take up a slot, so it might go to them. If not we create a new child + // node and give the addition to that. TODO: Would be nice to allow all 16 slots and split + // this node if num children is > 16. + let num_addition_slots = + MAX_NUM_CHILDREN as u32 - (num_leaf_children + num_immediate_additions); + if num_addition_slots > 0 { + let mut addition_slots = Vec::with_capacity(num_addition_slots as usize); + for _ in 0..num_addition_slots { + addition_slots.push(0); + } - if other_depth == target_depth { - path_node = - Some(NodeSpec::Path(child_tree_index, path.clone())); - } - } else { - assert!(false); - break - } - } - if path_node.is_some() { - break - } - } + // Allocate additions to addition_slots + let num_additions = if num_additions >= num_addition_slots { + let num_per_slot = num_additions / num_addition_slots; + for i in 0..num_addition_slots { + addition_slots[i as usize] += num_per_slot; + } + num_additions - (num_addition_slots * num_per_slot) + } else { + num_additions + }; + if num_additions > 0 { + assert!(num_additions < num_addition_slots); + let mut index = rng.next_u32() % num_addition_slots; + for _ in 0..num_additions { + addition_slots[index as usize] += 1; + index = (index + 1) % num_addition_slots; + } + } - NUM_PATHS.fetch_add(1, Ordering::SeqCst); - match path_node { - Some(node) => { - NUM_PATHS_SUCCESS.fetch_add(1, Ordering::SeqCst); - children.push(node); - }, - None => { - // Unable to generate a path so just create a direct node. Use path_rng - // to ensure deterministic generation when using only_direct_children. - // TODO: This is not returned when only_direct_children is true even - // though it is a direct node. Is this ok? only_direct_children is only - // used when generating a path so it is ok if it doesn't see these - // nodes. - children.push(NodeSpec::Direct( - tree_index, - depth + 1, - path_rng.next_u64(), - )); - }, - } + let mut slot_index = 0; + for child in child_changes.iter_mut() { + if !child.1 { + child.3 += addition_slots[slot_index]; + slot_index += 1; } } + + for _ in slot_index..num_addition_slots as usize { + if addition_slots[slot_index] > 0 { + // Insert at random index in child_changes + let index = rng.next_u32() as usize % (child_changes.len() + 1); + child_changes.insert(index, (None, false, 0, addition_slots[slot_index])); + } + slot_index += 1; + } } - if only_direct_children { - return (Vec::new(), children) + // Immediate additions + for _ in 0..num_immediate_additions { + child_changes.push((None, true, 0, 0)); } - // Polkadot doesn't store actual values in branch nodes, only in leaf nodes. Hence the value - // stored in the db will only be for the nibble path. - let mut size = 4; - if num_children == 0 { - // Leaf node, so simulate an actual value using the size histogram. - size = self.value_length_histogram.sample(rng.next_u64()) as usize; - if FORCE_NO_MULTIPART_VALUES { - size = std::cmp::min(size, 32760 - 64); + // Apply child_changes + let mut children = Vec::with_capacity(child_changes.len()); + for (existing_index, leaf, removals, additions) in child_changes.iter() { + if let Some(existing_index) = existing_index { + let previous_child_node = &previous_node.unwrap().children[*existing_index]; + let previous_child = previous_child_node.get_child_as_ref(); + if *removals > 0 || *additions > 0 { + assert!(!*leaf); + let child = self.build_node_with_changes( + rng, + Some(previous_child), + depth + 1, + *removals, + *additions, + )?; + children.push(ChildSpec::Replacement(*existing_index as u8, Arc::new(child))); + } else { + children + .push(ChildSpec::Existing(*existing_index as u8, previous_child.clone())); + } + } else { + assert!(*leaf || *removals > 0 || *additions > 0); + let child = + self.build_node_with_changes(rng, None, depth + 1, *removals, *additions)?; + children.push(ChildSpec::New(Arc::new(child))); } } - let mut v = Vec::new(); - v.resize(size, 0); - let fill = if !self.compressable { size } else { size / 2 }; - rng.fill_bytes(&mut v[..fill]); + // Remove non-leaf nodes that have no children + children.retain(|x| match x { + ChildSpec::Replacement(_, child) => child.leaf || child.children.len() > 0, + _ => true, + }); - (v, children) + let (data, leaf) = if let Some(previous_node) = previous_node { + (previous_node.data.clone(), previous_node.leaf) + } else { + let leaf = (num_removals == 0) && (num_additions == 0); + let data = self.generate_node_data(rng, leaf); + (data, leaf) + }; + + Ok(NodeData { data, children, leaf }) } +} - fn execute_path(&self, tree_index: u64, path: Vec) -> Result<(u64, u32, u64), String> { - let mut depth = 0; - let mut seed = self.root_seed(tree_index); - for child_index in path { - let (_node_data, children) = self.generate_node(tree_index, depth, seed, true); - let child = &children[child_index as usize]; - if let NodeSpec::Direct(child_tree_index, child_depth, child_seed) = child { - assert_eq!(*child_tree_index, tree_index); - assert_eq!(*child_depth, depth + 1); - depth = *child_depth; - seed = *child_seed; - } else { - return Err("Non-direct node in path".to_string()) - } +fn build_full_tree( + node_spec: (u32, u64), + chain_generator: &ChainGenerator, + enumerated_depth_child_counts: &mut Vec>, +) -> (NodeData, u32) { + let node_data = + chain_generator.generate_node(node_spec.0, node_spec.1, enumerated_depth_child_counts); + let mut total_num_nodes = 1; + let mut children = Vec::with_capacity(node_data.1.len()); + for child_spec in node_data.1 { + let (child_node, num_child_nodes) = + build_full_tree(child_spec, chain_generator, enumerated_depth_child_counts); + total_num_nodes += num_child_nodes; + children.push(ChildSpec::New(Arc::new(child_node))); + } + let num_children = children.len(); + (NodeData { data: node_data.0, children, leaf: num_children == 0 }, total_num_nodes) +} + +fn build_node_from_db<'a>( + database_node_data: Vec, + database_children: &Vec, + reader: &RwLockReadGuard<'a, Box>, + chain_generator: &ChainGenerator, +) -> NodeData { + let mut children = Vec::with_capacity(database_children.len()); + for i in 0..database_children.len() { + let child_address = database_children[i]; + match reader.get_node(child_address).unwrap() { + Some((db_node_data, db_children)) => { + children.push(ChildSpec::New(Arc::new(build_node_from_db( + db_node_data, + &db_children, + reader, + chain_generator, + )))); + }, + None => panic!("Child address not in database"), } - Ok((tree_index, depth, seed)) + } + let num_children = children.len(); + NodeData { data: database_node_data, children, leaf: num_children == 0 } +} + +fn build_tree_from_db(tree_index: u64, db: &Db, chain_generator: &ChainGenerator) -> NodeData { + let root_seed = chain_generator.root_seed(tree_index); + let key = chain_generator.key(root_seed); + match db.get_tree(TREE_COLUMN, &key).unwrap() { + Some(reader) => { + let reader = reader.read(); + match reader.get_root().unwrap() { + Some((db_node_data, db_children)) => + build_node_from_db(db_node_data, &db_children, &reader, &chain_generator), + None => { + panic!("Latest tree root not in database at restart"); + }, + } + }, + None => { + panic!("Latest tree not in database at restart"); + }, } } @@ -495,31 +656,68 @@ fn informant( db: Arc, shutdown: Arc, shutdown_final: Arc, + total_commits: usize, + start_commit: usize, + start_num_nodes: usize, output_helper: Arc>, ) -> Result<(), String> { + let mut last_commits = start_commit; + let mut last_time = std::time::Instant::now(); + let mut last_num_expected_entries = start_num_nodes; let mut num_expected_entries = 0; let mut num_entries = 0; + let mut finished = false; + let mut iteration_count = 0; while !shutdown_final.load(Ordering::Relaxed) { - if FIXED_TEXT_POSITION { + let write_info = if FIXED_TEXT_POSITION { thread::sleep(std::time::Duration::from_millis(100)); + iteration_count = (iteration_count + 1) % 10; + iteration_count == 0 } else { thread::sleep(std::time::Duration::from_secs(1)); - } + true + }; let new_num_expected_entries = EXPECTED_NUM_ENTRIES.load(Ordering::Relaxed); let new_num_entries = db.get_num_column_value_entries(TREE_COLUMN).unwrap(); + if write_info { + let commits = COMMITS.load(Ordering::Acquire); + let num_removed = NUM_REMOVED.load(Ordering::Relaxed); + let now = std::time::Instant::now(); + + if !finished { + if commits > 0 && commits > last_commits { + output_helper.write().println(format!( + "{}/{} tree commits, {:.2} cps, {} removed, {:.2} average new nodes", + commits - start_commit, + total_commits, + ((commits - last_commits) as f64) / (now - last_time).as_secs_f64(), + num_removed, + (new_num_expected_entries - last_num_expected_entries) as f64 / + (commits - last_commits) as f64 + )); + } + + if (commits - start_commit) >= total_commits && + num_removed >= (start_commit + total_commits) + { + finished = true; + } + } + + last_commits = commits; + last_time = now; + last_num_expected_entries = new_num_expected_entries; + } + if new_num_expected_entries != num_expected_entries || new_num_entries != num_entries { num_expected_entries = new_num_expected_entries; num_entries = new_num_entries; - let num_paths = NUM_PATHS.load(Ordering::Relaxed); - let num_paths_success = NUM_PATHS_SUCCESS.load(Ordering::Relaxed); - let existing_ratio = num_paths_success as f32 / num_paths as f32; - output_helper.write().print_fixed(format!( - "Entries, Created: {}, ValueTables: {}, Path success ratio: {}", - num_expected_entries, num_entries, existing_ratio + "Entries, Created: {}, in ValueTables: {}", + num_expected_entries, num_entries )); if num_entries == 0 { @@ -532,143 +730,67 @@ fn informant( Ok(()) } -fn find_dependent_trees( - node_data: &(Vec, Vec), +fn build_initial_commit_tree( + node: &NodeData, + db: &Db, chain_generator: &ChainGenerator, - trees: &mut HashSet, -) -> Result<(), String> { - for spec in &node_data.1 { - match spec { - NodeSpec::Direct(child_tree_index, child_depth, child_seed) => { - let child_data = chain_generator.generate_node( - *child_tree_index, - *child_depth, - *child_seed, - false, - ); - find_dependent_trees(&child_data, chain_generator, trees)?; - }, - NodeSpec::UnresolvedPath() => return Err("UnresolvedPath found".to_string()), - NodeSpec::Path(tree_index, _path) => { - trees.insert(*tree_index); +) -> Result { + let mut children = Vec::with_capacity(node.children.len()); + for child in node.children.iter() { + match child { + ChildSpec::New(child) => { + children.push(build_initial_commit_tree(child, db, chain_generator)?); }, + ChildSpec::Existing(..) => + return Err("Existing node found in initial commit".to_string()), + ChildSpec::Replacement(..) => + return Err("Replacement node found in initial commit".to_string()), } } - Ok(()) + let new_node = NewNode { data: node.data.clone(), children }; + Ok(NodeRef::New(new_node)) } -fn build_commit_tree<'s, 'd: 's>( - node_data: (Vec, Vec), +fn build_commit_tree( + node: &NodeData, db: &Db, chain_generator: &ChainGenerator, - tree_refs: &'s HashMap>, - tree_guards: &mut HashMap>, + prev_child_addresses: Option>, + prev_reader: &RwLockReadGuard>, ) -> Result { - let mut children = Vec::default(); - for spec in node_data.1 { - match spec { - NodeSpec::Direct(child_tree_index, child_depth, child_seed) => { - let child_data = - chain_generator.generate_node(child_tree_index, child_depth, child_seed, false); - let child_node = - build_commit_tree(child_data, db, chain_generator, tree_refs, tree_guards)?; - children.push(child_node); + let mut children = Vec::with_capacity(node.children.len()); + for child in node.children.iter() { + match child { + ChildSpec::New(child) => { + children.push(build_commit_tree(child, db, chain_generator, None, prev_reader)?); }, - NodeSpec::UnresolvedPath() => return Err("UnresolvedPath found".to_string()), - NodeSpec::Path(tree_index, path) => { - let root_seed = chain_generator.root_seed(tree_index); - let key = chain_generator.key(root_seed); - - if let None = tree_guards.get(&key) { - if let Some(tree_ref) = tree_refs.get(&key) { - tree_guards.insert(key.clone(), tree_ref.read()); - } - } - - let mut final_child_address: Option = None; - if let Some(tree_guard) = tree_guards.get(&key) { - if let Some((_db_node_data, db_children)) = tree_guard.get_root().unwrap() { - // Note: We don't actually have to generate any nodes here; we could just - // traverse down the database nodes. Only generating them to verify data. - /* let (gen_node_data, gen_children) = - chain_generator.generate_node(tree_index, 0, root_seed, false); - - assert_eq!(gen_node_data, db_node_data); - assert_eq!(gen_children.len(), db_children.len()); - - let mut generated_children = gen_children; */ - let mut database_children = db_children; - - for index in 0..path.len() { - let child_index = path[index]; - - let child_address = database_children[child_index as usize]; - - if index == path.len() - 1 { - final_child_address = Some(child_address); - break - } - - /* let (child_tree_index, child_depth, child_seed) = - match &generated_children[child_index as usize] { - NodeSpec::Direct(child_tree_index, child_depth, child_seed) => - (*child_tree_index, *child_depth, *child_seed), - NodeSpec::UnresolvedPath() => - return Err("UnresolvedPath found".to_string()), - NodeSpec::Path(_tree_index, _path) => - return Err("NodeSpec::Path found within path".to_string()), - }; - - let (gen_node_data, gen_children) = chain_generator.generate_node( - child_tree_index, - child_depth, - child_seed, - false, - ); */ - - match tree_guard.get_node(child_address).unwrap() { - Some((_db_node_data, db_children)) => { - /* assert_eq!(gen_node_data, db_node_data); - assert_eq!(gen_children.len(), db_children.len()); - - generated_children = gen_children; */ - database_children = db_children; - }, - None => return Err("Child address not in database".to_string()), - } - } + ChildSpec::Existing(prev_child_index, _child) => match &prev_child_addresses { + Some(addresses) => { + children.push(NodeRef::Existing(addresses[*prev_child_index as usize])); + }, + None => return Err("Existing node without child addresses".to_string()), + }, + ChildSpec::Replacement(prev_child_index, child) => match &prev_child_addresses { + Some(addresses) => { + let address = addresses[*prev_child_index as usize]; + match prev_reader.get_node_children(address).unwrap() { + Some(db_children) => { + children.push(build_commit_tree( + child, + db, + chain_generator, + Some(db_children), + prev_reader, + )?); + }, + None => return Err("Child address not in database".to_string()), } - } - - match final_child_address { - Some(address) => { - let child_node = NodeRef::Existing(address); - children.push(child_node); - }, - None => { - // Not able to get the existing child address so duplicate sub-tree - let (child_tree_index, child_depth, child_seed) = - chain_generator.execute_path(tree_index, path)?; - let child_data = chain_generator.generate_node( - child_tree_index, - child_depth, - child_seed, - false, - ); - let child_node = build_commit_tree( - child_data, - db, - chain_generator, - tree_refs, - tree_guards, - )?; - children.push(child_node); - }, - } + }, + None => return Err("Replacement node without child addresses".to_string()), }, } } - let new_node = NewNode { data: node_data.0, children }; + let new_node = NewNode { data: node.data.clone(), children }; Ok(NodeRef::New(new_node)) } @@ -690,58 +812,36 @@ fn num_new_nodes(node: &NodeRef, num_existing: &mut u32) -> u32 { fn read_value( tree_index: u64, + gen_root_node: &NodeData, rng: &mut rand::rngs::SmallRng, db: &Db, - args: &Args, chain_generator: &ChainGenerator, ) -> Result<(), String> { - let mut depth = 0; let root_seed = chain_generator.root_seed(tree_index); - - let (gen_node_data, gen_children) = - chain_generator.generate_node(tree_index, depth, root_seed, false); - let key = chain_generator.key(root_seed); match db.get_tree(TREE_COLUMN, &key).unwrap() { Some(reader) => { let reader = reader.read(); match reader.get_root().unwrap() { Some((db_node_data, db_children)) => { - assert_eq!(gen_node_data, db_node_data); - assert_eq!(gen_children.len(), db_children.len()); + assert_eq!(gen_root_node.data, db_node_data); + assert_eq!(gen_root_node.children.len(), db_children.len()); - let mut generated_children = gen_children; + let mut generated_children = &gen_root_node.children; let mut database_children = db_children; while generated_children.len() > 0 { let child_index = rng.next_u64() % generated_children.len() as u64; - let (child_tree_index, child_seed) = - match &generated_children[child_index as usize] { - NodeSpec::Direct(child_tree_index, _child_depth, child_seed) => - (*child_tree_index, *child_seed), - NodeSpec::UnresolvedPath() => - return Err("UnresolvedPath found".to_string()), - NodeSpec::Path(tree_index, path) => { - let (child_tree_index, child_depth, child_seed) = - chain_generator.execute_path(*tree_index, path.clone())?; - assert_eq!(child_depth, depth + 1); - (child_tree_index, child_seed) - }, - }; - let child_address = database_children[child_index as usize]; - depth += 1; - let (gen_node_data, gen_children) = chain_generator.generate_node( - child_tree_index, - depth, - child_seed, - false, - ); + let gen_child = generated_children[child_index as usize].get_child_as_ref(); + let gen_node_data = &gen_child.data; + let gen_children = &gen_child.children; + match reader.get_node(child_address).unwrap() { Some((db_node_data, db_children)) => { - assert_eq!(gen_node_data, db_node_data); + assert_eq!(*gen_node_data, db_node_data); assert_eq!(gen_children.len(), db_children.len()); generated_children = gen_children; @@ -754,28 +854,22 @@ fn read_value( QUERIES.fetch_add(1, Ordering::SeqCst); }, None => { - // Is this expected? If there are multiple writers then commits might happen out - // of order so this path can happen even when the tree hasn't been pruned. - if args.writers == 1 { - let num_removed = NUM_REMOVED.load(Ordering::Relaxed); - if tree_index >= num_removed as u64 { - panic!("Tree root not in database"); - } + // Is this expected? + let num_removed = NUM_REMOVED.load(Ordering::Relaxed); + if tree_index >= num_removed as u64 { + panic!("Tree root not in database during read"); } }, } }, None => { - // Is this expected? If there are multiple writers then commits might happen out of - // order so this path can happen even when the tree hasn't been pruned. - if args.writers == 1 { - let num_removed = NUM_REMOVED.load(Ordering::Relaxed); - if tree_index >= num_removed as u64 { - panic!( - "Tree not in database during read (index: {}, removed: {})", - tree_index, num_removed - ); - } + // Is this expected? + let num_removed = NUM_REMOVED.load(Ordering::Relaxed); + if tree_index >= num_removed as u64 { + panic!( + "Tree not in database during read (index: {}, removed: {})", + tree_index, num_removed + ); } }, } @@ -783,37 +877,14 @@ fn read_value( Ok(()) } -struct TreeReaderRef<'d> { - reader_ref: Arc>>, -} - -impl<'d> TreeReaderRef<'d> { - pub fn read<'s>(&'s self) -> TreeReaderGuard<'s, 'd> { - TreeReaderGuard { lock_guard: self.reader_ref.read() } - } -} - -struct TreeReaderGuard<'s, 'd: 's> { - lock_guard: RwLockReadGuard<'s, Box>, -} - -impl<'s, 'd: 's> Deref for TreeReaderGuard<'s, 'd> { - type Target = Box; - - fn deref(&self) -> &Self::Target { - self.lock_guard.deref() - } -} - fn writer( db: Arc, args: Arc, chain_generator: Arc, + trees: Arc)>>>, shutdown: Arc, start_commit: usize, - output_helper: Arc>, ) -> Result<(), String> { - //let seed = args.seed.unwrap_or(0); let mut commit = Vec::new(); loop { @@ -825,68 +896,134 @@ fn writer( let tree_index = n as u64; let root_seed = chain_generator.root_seed(tree_index); - let node_data = chain_generator.generate_node(tree_index, 0, root_seed, false); + let (previous_tree_index, previous_tree) = if args.writers > 1 { + // Not much advantage to multiple writers. They have to work from the previous commit so + // just wait their turn. + let required_tree_index = if n == 0 { 0 } else { tree_index - 1 }; + let mut previous_tree_index = 0; + let mut previous_tree = None; + while previous_tree.is_none() { + let check = if n == 1 { + let commits = COMMITS.load(Ordering::Relaxed); + commits > start_commit + } else { + true + }; + if check { + let tree_lock = trees.read(); + if let Some(back_tree) = tree_lock.back() { + if back_tree.0 == required_tree_index { + previous_tree_index = back_tree.0; + previous_tree = Some(back_tree.1.clone()); + } + } + } + } + (previous_tree_index, previous_tree) + } else { + let tree_lock = trees.read(); + let (previous_tree_index, previous_tree) = if let Some(previous_tree) = tree_lock.back() + { + let previous_root_node = previous_tree.1.clone(); + (previous_tree.0, Some(previous_root_node)) + } else { + // There should always be a cached tree + assert!(false); + (0, None) + }; + (previous_tree_index, previous_tree) + }; - // First phase. Find all trees that this commit is dependent on. - let mut trees: HashSet = Default::default(); - find_dependent_trees(&node_data, &chain_generator, &mut trees)?; + if let Some(previous_tree) = previous_tree { + let prev_root_seed = chain_generator.root_seed(previous_tree_index); + let prev_key = chain_generator.key(prev_root_seed); - let mut tree_refs: HashMap = Default::default(); - let mut tree_guards: HashMap = Default::default(); - for index in trees { - let seed = chain_generator.root_seed(index); - let key = chain_generator.key(seed); - match db.get_tree(TREE_COLUMN, &key).unwrap() { - Some(reader) => { - let reader_ref = TreeReaderRef { reader_ref: reader }; - tree_refs.insert(key, reader_ref); - }, - None => { - // It's fine for the tree to not be in the database. The commit will regenerate - // the required nodes. - }, - } - } + let reader = if n > 0 { + Some(match db.get_tree(TREE_COLUMN, &prev_key).unwrap() { + Some(r) => r, + None => return Err("Previous tree not found in database".to_string()), + }) + } else { + None + }; - /* for (key, tree_ref) in tree_refs.iter() { - tree_guards.insert(key.clone(), tree_ref.read()); - } */ + let reader_lock = reader.as_ref().map(|f| f.read()); - let root_node_ref = - build_commit_tree(node_data, &db, &chain_generator, &tree_refs, &mut tree_guards)?; - let mut num_existing_nodes = 0; - let num_new_nodes = num_new_nodes(&root_node_ref, &mut num_existing_nodes); - if let NodeRef::New(node) = root_node_ref { - let key: [u8; 32] = chain_generator.key(root_seed); + let (root_node_ref, tree) = if n == 0 { + assert_eq!(previous_tree_index, 0); + let root = build_initial_commit_tree(&previous_tree, &db, &chain_generator)?; + (root, None) + } else { + assert_eq!(previous_tree_index, tree_index - 1); - commit.push((TREE_COLUMN, Operation::InsertTree(key.to_vec(), node))); + // Create new tree with removals and additions + let new_tree = + chain_generator.build_tree_with_changes(tree_index, &previous_tree)?; - commit.push(( - INFO_COLUMN, - Operation::Set(KEY_LAST_COMMIT.to_vec(), (n as u64).to_be_bytes().to_vec()), - )); + let reader = reader_lock.as_ref().unwrap(); - db.commit_changes(commit.drain(..)).unwrap(); + let prev_child_address = match reader.get_root().unwrap() { + Some(prev_root) => prev_root.1, + None => return Err("Previous root not found in database".to_string()), + }; - output_helper.write().println(format!( - "Commit tree {}, new: {}, existing: {}", - tree_index, num_new_nodes, num_existing_nodes - )); + let root = build_commit_tree( + &new_tree, + &db, + &chain_generator, + Some(prev_child_address), + &reader, + )?; + (root, Some(new_tree)) + }; - COMMITS.fetch_add(1, Ordering::SeqCst); - EXPECTED_NUM_ENTRIES.fetch_add(num_new_nodes as usize, Ordering::SeqCst); - commit.clear(); + let mut num_existing_nodes = 0; + let num_new_nodes = num_new_nodes(&root_node_ref, &mut num_existing_nodes); + if let NodeRef::New(node) = root_node_ref { + let key: [u8; 32] = chain_generator.key(root_seed); - // Immediately read and check a random value from the tree - /* let mut rng = rand::rngs::SmallRng::seed_from_u64(seed + n as u64); - read_value(tree_index, &mut rng, &db, &args, &chain_generator)?; */ + commit.push((TREE_COLUMN, Operation::InsertTree(key.to_vec(), node))); - if args.pruning > 0 && !THREAD_PRUNING { - try_prune(&db, &args, &chain_generator, &mut commit, &output_helper)?; - } + commit.push(( + INFO_COLUMN, + Operation::Set(KEY_LAST_COMMIT.to_vec(), (n as u64).to_be_bytes().to_vec()), + )); + + db.commit_changes(commit.drain(..)).unwrap(); + + drop(reader_lock); + + if let Some(tree) = tree { + let mut tree_lock = trees.write(); + tree_lock.push_back((tree_index, Arc::new(tree))); + while tree_lock.len() > NUM_TREES_TO_CACHE { + tree_lock.pop_front(); + } + } - if args.commit_time > 0 { - thread::sleep(std::time::Duration::from_millis(args.commit_time)); + COMMITS.fetch_add(1, Ordering::SeqCst); + EXPECTED_NUM_ENTRIES.fetch_add(num_new_nodes as usize, Ordering::SeqCst); + commit.clear(); + + // Immediately read and check a random value from the tree + /* let tree_lock = trees.read(); + if let Some(back_tree) = tree_lock.back() { + if back_tree.0 == tree_index { + let root_node = back_tree.1.clone(); + let mut rng = + rand::rngs::SmallRng::seed_from_u64(args.seed.unwrap_or(0) + n as u64); + read_value(tree_index, &root_node, &mut rng, &db, &chain_generator)?; + } + } + drop(tree_lock); */ + + if args.pruning > 0 && !THREAD_PRUNING { + try_prune(&db, &args, &chain_generator, &mut commit)?; + } + + if args.commit_time > 0 { + thread::sleep(std::time::Duration::from_millis(args.commit_time)); + } } } } @@ -899,7 +1036,6 @@ fn try_prune( args: &Args, chain_generator: &ChainGenerator, commit: &mut Vec<(u8, Operation, Vec>)>, - output_helper: &RwLock, ) -> Result<(), String> { let num_removed = NUM_REMOVED.load(Ordering::Relaxed); let target_override = TARGET_NUM_REMOVED.load(Ordering::Relaxed); @@ -921,8 +1057,6 @@ fn try_prune( let root_seed = chain_generator.root_seed(tree_index); let key = chain_generator.key(root_seed); - output_helper.write().println(format!("Remove tree {}", tree_index)); - commit.push((TREE_COLUMN, Operation::DereferenceTree(key.to_vec()))); commit.push(( INFO_COLUMN, @@ -945,12 +1079,11 @@ fn pruner( args: Arc, chain_generator: Arc, shutdown: Arc, - output_helper: Arc>, ) -> Result<(), String> { let mut commit = Vec::new(); while !shutdown.load(Ordering::Relaxed) { - try_prune(&db, &args, &chain_generator, &mut commit, &output_helper)?; + try_prune(&db, &args, &chain_generator, &mut commit)?; } Ok(()) @@ -960,6 +1093,7 @@ fn reader( db: Arc, args: Arc, chain_generator: Arc, + trees: Arc)>>>, index: u64, shutdown: Arc, ) -> Result<(), String> { @@ -968,59 +1102,48 @@ fn reader( let mut rng = rand::rngs::SmallRng::seed_from_u64(offset + index); while !shutdown.load(Ordering::Relaxed) { - let num_removed = NUM_REMOVED.load(Ordering::Relaxed) as u64; let commits = COMMITS.load(Ordering::Relaxed) as u64; if commits == 0 { continue } - //let tree_index = rng.next_u64() % commits; - let tree_index = (rng.next_u64() % (commits - num_removed)) + num_removed; - - read_value(tree_index, &mut rng, &db, &args, &chain_generator)?; + let trees = trees.read(); + let generated_tree = if trees.len() > 0 { + let cached_index = rng.next_u32() as usize % trees.len(); + let gen_tree = &trees[cached_index]; + let gen_tree_root = gen_tree.1.clone(); + Some((gen_tree.0, gen_tree_root)) + } else { + None + }; + drop(trees); + if let Some((tree_index, gen_root_node)) = generated_tree { + read_value(tree_index, &gen_root_node, &mut rng, &db, &chain_generator)?; + } } Ok(()) } fn iter_children<'a>( - depth: u32, - generated_children: &mut Vec, - database_children: &mut Vec, + generated_children: &Vec, + database_children: &Vec, reader: &RwLockReadGuard<'a, Box>, chain_generator: &ChainGenerator, ) -> Result<(), String> { - for i in 0..generated_children.len() { - let child_index = i; - - let (child_tree_index, child_seed) = match &generated_children[child_index as usize] { - NodeSpec::Direct(child_tree_index, _child_depth, child_seed) => - (*child_tree_index, *child_seed), - NodeSpec::UnresolvedPath() => return Err("UnresolvedPath found".to_string()), - NodeSpec::Path(tree_index, path) => { - let (child_tree_index, child_depth, child_seed) = - chain_generator.execute_path(*tree_index, path.clone())?; - assert_eq!(child_depth, depth + 1); - (child_tree_index, child_seed) - }, - }; + for i in 0..database_children.len() { + let child_address = database_children[i]; - let child_address = database_children[child_index as usize]; + let gen_child = generated_children[i].get_child_as_ref(); + let gen_node_data = &gen_child.data; + let gen_children = &gen_child.children; - let (gen_node_data, mut gen_children) = - chain_generator.generate_node(child_tree_index, depth + 1, child_seed, false); match reader.get_node(child_address).unwrap() { - Some((db_node_data, mut db_children)) => { - assert_eq!(gen_node_data, db_node_data); + Some((db_node_data, db_children)) => { + assert_eq!(*gen_node_data, db_node_data); assert_eq!(gen_children.len(), db_children.len()); - iter_children( - depth + 1, - &mut gen_children, - &mut db_children, - reader, - chain_generator, - )?; + iter_children(gen_children, &db_children, reader, chain_generator)?; }, None => panic!("Child address not in database"), } @@ -1033,6 +1156,7 @@ fn iter( db: Arc, args: Arc, chain_generator: Arc, + trees: Arc)>>>, index: u64, shutdown: Arc, ) -> Result<(), String> { @@ -1041,61 +1165,55 @@ fn iter( let mut rng = rand::rngs::SmallRng::seed_from_u64(offset + index); while !shutdown.load(Ordering::Relaxed) { - let num_removed = NUM_REMOVED.load(Ordering::Relaxed) as u64; let commits = COMMITS.load(Ordering::Relaxed) as u64; if commits == 0 { continue } - //let tree_index = rng.next_u64() % commits; - let tree_index = (rng.next_u64() % (commits - num_removed)) + num_removed; - - let root_seed = chain_generator.root_seed(tree_index); - let depth = 0; - - let (gen_node_data, gen_children) = - chain_generator.generate_node(tree_index, depth, root_seed, false); - - let key = chain_generator.key(root_seed); - match db.get_tree(TREE_COLUMN, &key).unwrap() { - Some(reader) => { - let reader = reader.read(); - match reader.get_root().unwrap() { - Some((db_node_data, db_children)) => { - assert_eq!(gen_node_data, db_node_data); - assert_eq!(gen_children.len(), db_children.len()); - - // Iterate over all children recursively in depth first order. - let mut generated_children = gen_children; - let mut database_children = db_children; - - iter_children( - depth, - &mut generated_children, - &mut database_children, - &reader, - &chain_generator, - )?; - - ITERATIONS.fetch_add(1, Ordering::SeqCst); - }, - None => { - // Is this expected? If there are multiple writers then commits might happen - // out of order so this path can happen even when the tree hasn't been - // pruned. - if args.writers == 1 { + let trees = trees.read(); + let generated_tree = if trees.len() > 0 { + let cached_index = rng.next_u32() as usize % trees.len(); + let gen_tree = &trees[cached_index]; + let gen_tree_root = gen_tree.1.clone(); + Some((gen_tree.0, gen_tree_root)) + } else { + None + }; + drop(trees); + if let Some((tree_index, gen_root_node)) = generated_tree { + let root_seed = chain_generator.root_seed(tree_index); + let key = chain_generator.key(root_seed); + match db.get_tree(TREE_COLUMN, &key).unwrap() { + Some(reader) => { + let reader = reader.read(); + match reader.get_root().unwrap() { + Some((db_node_data, db_children)) => { + assert_eq!(gen_root_node.data, db_node_data); + assert_eq!(gen_root_node.children.len(), db_children.len()); + + // Iterate over all children recursively in depth first order. + let generated_children = &gen_root_node.children; + let database_children = db_children; + + iter_children( + generated_children, + &database_children, + &reader, + &chain_generator, + )?; + + ITERATIONS.fetch_add(1, Ordering::SeqCst); + }, + None => { + // Is this expected? let num_removed = NUM_REMOVED.load(Ordering::Relaxed); if tree_index >= num_removed as u64 { panic!("Tree root not in database"); } - } - }, - } - }, - None => { - // Is this expected? If there are multiple writers then commits might happen out of - // order so this path can happen even when the tree hasn't been pruned. - if args.writers == 1 { + }, + } + }, + None => { let num_removed = NUM_REMOVED.load(Ordering::Relaxed); if tree_index >= num_removed as u64 { panic!( @@ -1103,14 +1221,31 @@ fn iter( tree_index, num_removed ); } - } - }, + }, + } + } else { + panic!("Trying to iterate over tree that isn't cached"); } } Ok(()) } +fn enumerate_depth_child_counts(num_depths: u32) -> Vec> { + let mut depth_child_counts = Vec::new(); + for i in 0..num_depths { + let mut child_counts = Vec::new(); + let counts = data::DEPTH_CHILD_COUNT_HISTOGRAMS[i as usize]; + for c in 0..counts.1.len() { + for _ in 0..counts.1[c] { + child_counts.push(c); + } + } + depth_child_counts.push(child_counts); + } + depth_child_counts +} + pub fn run_internal(args: Args, db: Db) -> Result<(), String> { let args = Arc::new(args); let shutdown = Arc::new(AtomicBool::new(false)); @@ -1145,14 +1280,38 @@ pub fn run_internal(args: Args, db: Db) -> Result<(), String> { let chain_generator = ChainGenerator::new( data::DEPTH_CHILD_COUNT_HISTOGRAMS, - data::DEPTH_AGE_HISTOGRAMS, + data::DEPTH_LEAF_COUNT_HISTOGRAM, data::VALUE_LENGTH_HISTOGRAM, args.seed.unwrap_or(0), args.compress, - args.pruning, ); let chain_generator = Arc::new(chain_generator); + if start_commit != 0 { + output_helper.write().println(format!("Start commit: {}", start_commit)); + } + if num_removed != 0 { + output_helper.write().println(format!("Num removed: {}", num_removed)); + } + + let (tree_index, node, start_num_nodes) = if start_commit == 0 { + let tree_index = start_commit as u64; + let root_seed = chain_generator.root_seed(tree_index); + let node_spec = (0, root_seed); + let mut enumerated_depth_child_counts = enumerate_depth_child_counts(2); + let (node, start_num_nodes) = + build_full_tree(node_spec, &chain_generator, &mut enumerated_depth_child_counts); + output_helper.write().println(format!("Initial num nodes: {}", start_num_nodes)); + (tree_index, node, start_num_nodes) + } else { + let tree_index = start_commit as u64 - 1; + (tree_index, build_tree_from_db(tree_index, &db, &chain_generator), 0) + }; + + let mut trees: VecDeque<_> = VecDeque::new(); + trees.push_back((tree_index, Arc::new(node))); + let trees = Arc::new(RwLock::new(trees)); + let start_time = std::time::Instant::now(); COMMITS.store(start_commit, Ordering::SeqCst); @@ -1163,9 +1322,20 @@ pub fn run_internal(args: Args, db: Db) -> Result<(), String> { let db = db.clone(); let shutdown = shutdown.clone(); let shutdown_final = shutdown_final.clone(); + let total_commits = args.commits; let output_helper = output_helper.clone(); - threads.push(thread::spawn(move || informant(db, shutdown, shutdown_final, output_helper))); + threads.push(thread::spawn(move || { + informant( + db, + shutdown, + shutdown_final, + total_commits, + start_commit, + start_num_nodes as usize, + output_helper, + ) + })); } for i in 0..args.readers { @@ -1173,11 +1343,12 @@ pub fn run_internal(args: Args, db: Db) -> Result<(), String> { let shutdown = shutdown.clone(); let args = args.clone(); let chain_generator = chain_generator.clone(); + let trees = trees.clone(); threads.push( thread::Builder::new() .name(format!("reader {i}")) - .spawn(move || reader(db, args, chain_generator, i as u64, shutdown)) + .spawn(move || reader(db, args, chain_generator, trees, i as u64, shutdown)) .unwrap(), ); } @@ -1188,12 +1359,13 @@ pub fn run_internal(args: Args, db: Db) -> Result<(), String> { let shutdown = shutdown.clone(); let args = args.clone(); let chain_generator = chain_generator.clone(); + let trees = trees.clone(); threads.push( thread::Builder::new() .name(format!("iter {i}")) .spawn(move || { - iter(db, args, chain_generator, (iter_start_index + i) as u64, shutdown) + iter(db, args, chain_generator, trees, (iter_start_index + i) as u64, shutdown) }) .unwrap(), ); @@ -1204,14 +1376,12 @@ pub fn run_internal(args: Args, db: Db) -> Result<(), String> { let shutdown = shutdown.clone(); let args = args.clone(); let chain_generator = chain_generator.clone(); - let output_helper = output_helper.clone(); + let trees = trees.clone(); threads.push( thread::Builder::new() .name(format!("writer {i}")) - .spawn(move || { - writer(db, args, chain_generator, shutdown, start_commit, output_helper) - }) + .spawn(move || writer(db, args, chain_generator, trees, shutdown, start_commit)) .unwrap(), ); } @@ -1221,12 +1391,11 @@ pub fn run_internal(args: Args, db: Db) -> Result<(), String> { let shutdown = shutdown_final.clone(); let args = args.clone(); let chain_generator = chain_generator.clone(); - let output_helper = output_helper.clone(); threads.push( thread::Builder::new() .name(format!("pruner")) - .spawn(move || pruner(db, args, chain_generator, shutdown, output_helper)) + .spawn(move || pruner(db, args, chain_generator, shutdown)) .unwrap(), ); } diff --git a/src/db.rs b/src/db.rs index 2069c092..71ba1e12 100644 --- a/src/db.rs +++ b/src/db.rs @@ -2246,11 +2246,14 @@ impl IndexedChangeSet { writer: &mut crate::log::LogWriter, ) -> Result<()> { for address in children { + // Can't move this after write_address_dec_ref_plan as write_address_dec_ref_plan might + // free the node meaning it could get reclaimed. Then get_node_children will return + // incorrect data. + let node = guard.get_node_children(*address)?; let (remains, _outcome) = column.write_address_dec_ref_plan(*address, writer)?; if !remains { // Was removed *num_removed += 1; - let node = guard.get_node_children(*address)?; if let Some(children) = node { self.write_dereference_children_plan( column, @@ -2286,7 +2289,11 @@ impl IndexedChangeSet { } for change in self.node_changes.iter() { if let NodeChange::NewValue(address, _val) = change { - overlay.address.remove(address); + if let Entry::Occupied(e) = overlay.address.entry(*address) { + if e.get().0 == record_id { + e.remove_entry(); + } + } } } } From e0f7878d5d7d6930357c47de3bfe0455fab7ffc7 Mon Sep 17 00:00:00 2001 From: MattHalpinParity Date: Sat, 20 Apr 2024 19:21:20 +0100 Subject: [PATCH 4/6] Add tree commits to commit queue size --- src/db.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/db.rs b/src/db.rs index 71ba1e12..cb9cabce 100644 --- a/src/db.rs +++ b/src/db.rs @@ -2163,6 +2163,7 @@ impl IndexedChangeSet { } for change in self.node_changes.iter() { if let NodeChange::NewValue(address, val) = change { + *bytes += val.value().len(); overlay.address.insert(*address, (record_id, val.clone())); } } From a84d077145ca933ec7805feb803e76cbfd1c58e2 Mon Sep 17 00:00:00 2001 From: MattHalpinParity Date: Fri, 26 Apr 2024 16:27:51 +0100 Subject: [PATCH 5/6] Better default parameters for multitree stress --- admin/src/multitree_bench/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/admin/src/multitree_bench/mod.rs b/admin/src/multitree_bench/mod.rs index 02919566..8b362e03 100644 --- a/admin/src/multitree_bench/mod.rs +++ b/admin/src/multitree_bench/mod.rs @@ -106,14 +106,14 @@ pub struct Args { impl MultiTreeStress { pub(super) fn get_args(&self) -> Args { Args { - readers: self.readers.unwrap_or(0), + readers: self.readers.unwrap_or(1), iter: self.iter.unwrap_or(0), writers: self.writers.unwrap_or(1), - commits: self.commits.unwrap_or(100_000), + commits: self.commits.unwrap_or(10_000), seed: self.seed, append: self.append, empty_on_shutdown: self.empty_on_shutdown, - pruning: self.pruning.unwrap_or(8), + pruning: self.pruning.unwrap_or(256), compress: self.compress, commit_time: self.commit_time.unwrap_or(0), } From af5443f31b245b59f46340bd6df24901b6636887 Mon Sep 17 00:00:00 2001 From: MattHalpinParity Date: Wed, 1 May 2024 11:03:28 +0100 Subject: [PATCH 6/6] Clarified comment --- admin/src/multitree_bench/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/src/multitree_bench/mod.rs b/admin/src/multitree_bench/mod.rs index 8b362e03..c06d42ca 100644 --- a/admin/src/multitree_bench/mod.rs +++ b/admin/src/multitree_bench/mod.rs @@ -311,8 +311,8 @@ impl ChainGenerator { } fn generate_node_data(&self, rng: &mut rand::rngs::SmallRng, leaf: bool) -> Vec { - // Polkadot doesn't store actual values in branch nodes, only in leaf nodes. Hence the value - // stored in the db will only be for the nibble path. + // Polkadot avoids storing actual values in branch nodes, they mainly go in leaf nodes. + // Hence the value stored in the db will only be for the nibble path. let mut size = 4; if leaf { // Leaf node, so simulate an actual value using the size histogram.