diff --git a/.gitignore b/.gitignore index ab57bcf4..658079fd 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ Cargo.lock *.log test_db/ test_db_stress/ +test_db_multitree_stress/ # vim *.swp diff --git a/admin/Cargo.toml b/admin/Cargo.toml index 8978e098..4d28ad9b 100644 --- a/admin/Cargo.toml +++ b/admin/Cargo.toml @@ -11,8 +11,10 @@ env_logger = { version = "0.10.0", default-features = false, features = ["auto-c fdlimit = "0.2.1" log = "0.4.8" parity-db = { path = ".." } +parking_lot = "0.12.0" rand = { version = "0.8.5", features = ["small_rng"] } blake2 = "0.10.4" +siphasher = "0.3.10" [target.'cfg(not(target_env = "msvc"))'.dependencies] jemallocator = "0.5.0" diff --git a/admin/src/lib.rs b/admin/src/lib.rs index c15f0160..9f3673ff 100644 --- a/admin/src/lib.rs +++ b/admin/src/lib.rs @@ -6,6 +6,7 @@ use std::path::PathBuf; mod bench; +mod multitree_bench; /// Command line admin client entry point. /// Uses default column definition. @@ -127,6 +128,44 @@ pub fn run() -> Result<(), String> { let db = parity_db::Db::open_or_create(&db_options).unwrap(); bench::run_internal(args, db); }, + SubCommand::MultiTreeStress(bench) => { + let args = bench.get_args(); + // avoid deleting folders by mistake. + options.path.push("test_db_multitree_stress"); + if options.path.exists() && !args.append { + std::fs::remove_dir_all(options.path.as_path()) + .map_err(|e| format!("Error clearing multitree stress db: {e:?}"))?; + } + + let mut db_options = options.clone(); + + for c in &mut db_options.columns { + c.multitree = true; + if args.pruning == 0 { + c.append_only = true; + } + } + + if args.compress { + for c in &mut db_options.columns { + c.compression = parity_db::CompressionType::Lz4; + } + } + + if db_options.columns.len() < 2 { + let info_column: parity_db::ColumnOptions = Default::default(); + db_options.columns.push(info_column); + } + + let info_column = &mut db_options.columns[multitree_bench::INFO_COLUMN as usize]; + info_column.uniform = false; + info_column.multitree = false; + info_column.ref_counted = false; + info_column.preimage = false; + + let db = parity_db::Db::open_or_create(&db_options).unwrap(); + multitree_bench::run_internal(args, db)?; + }, } Ok(()) } @@ -187,6 +226,8 @@ pub enum SubCommand { Check(Check), /// Stress tests. Stress(bench::Stress), + /// Multitree stress test. + MultiTreeStress(multitree_bench::MultiTreeStress), } impl SubCommand { @@ -207,6 +248,7 @@ impl Cli { SubCommand::Flush(flush) => &flush.shared, SubCommand::Check(check) => &check.shared, SubCommand::Stress(bench) => &bench.shared, + SubCommand::MultiTreeStress(bench) => &bench.shared, } } } diff --git a/admin/src/multitree_bench/data.rs b/admin/src/multitree_bench/data.rs new file mode 100644 index 00000000..6b5e2488 --- /dev/null +++ b/admin/src/multitree_bench/data.rs @@ -0,0 +1,7442 @@ +// Copyright 2021-2022 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or MIT. + +pub const NUM_NODES: u32 = 2493773; +pub const AVERAGE_NUM_NEW_NODES: f64 = 614.359375; + +pub const DEPTH_CHILD_COUNT_HISTOGRAMS: &[(u32, [u32; 17])] = &[ + (0, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]), + (1, [0, 0, 7, 3, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + (2, [9, 0, 10, 16, 4, 4, 2, 1, 1, 0, 1, 2, 1, 0, 0, 0, 1]), + (3, [79, 0, 42, 14, 11, 4, 2, 1, 3, 4, 0, 1, 0, 0, 2, 7, 21]), + (4, [230, 0, 79, 52, 41, 54, 35, 22, 26, 20, 22, 12, 8, 12, 9, 18, 109]), + (5, [1636, 0, 688, 380, 279, 190, 112, 50, 33, 20, 24, 14, 11, 9, 16, 8, 761]), + (6, [5337, 0, 1075, 317, 229, 215, 202, 314, 538, 827, 1114, 948, 845, 550, 329, 323, 6020]), + ( + 7, + [ + 38815, 0, 21492, 8449, 3864, 3017, 4081, 6491, 9796, 13328, 15775, 15326, 12054, 7061, + 2971, 757, 1253, + ], + ), + ( + 8, + [ + 605659, 0, 277669, 80106, 17947, 3814, 2167, 2561, 2968, 2808, 2433, 1824, 1146, 679, + 239, 55, 355, + ], + ), + (9, [950869, 0, 66216, 9742, 1686, 346, 117, 213, 441, 735, 914, 934, 711, 447, 188, 36, 24]), + (10, [190606, 0, 17715, 4316, 895, 191, 24, 2, 1, 12, 5, 0, 1, 0, 2, 0, 0]), + (11, [50531, 0, 1471, 29, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + (12, [2945, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + (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 VALUE_LENGTH_HISTOGRAM: &[(u32, u32)] = &[ + (1, 66330), + (2, 100), + (3, 1), + (4, 267500), + (5, 1304), + (6, 182), + (7, 45), + (8, 108), + (9, 11), + (10, 2), + (11, 6), + (12, 255), + (13, 6), + (14, 5), + (15, 25), + (16, 595), + (17, 441), + (18, 2), + (19, 373), + (20, 591), + (21, 60), + (23, 2), + (24, 6), + (25, 7), + (26, 69031), + (27, 1), + (28, 6), + (29, 22), + (30, 10), + (31, 10), + (32, 84843), + (33, 3429), + (34, 119), + (35, 224), + (36, 288), + (37, 13121), + (38, 9153), + (39, 31), + (40, 26), + (41, 29), + (42, 18), + (43, 44), + (44, 46), + (45, 21), + (46, 70), + (47, 6), + (48, 47), + (49, 3852), + (50, 3006), + (51, 1059), + (52, 28), + (53, 147), + (54, 3619), + (55, 84), + (56, 90), + (57, 801), + (58, 32), + (59, 21), + (60, 29), + (61, 16), + (62, 19), + (63, 10), + (64, 23), + (65, 186), + (66, 177), + (67, 15), + (68, 14), + (69, 33), + (70, 2229), + (71, 19), + (72, 17), + (73, 128), + (74, 22), + (75, 14), + (76, 2786), + (77, 76), + (78, 22), + (79, 19), + (80, 1136051), + (81, 43), + (82, 297), + (83, 136), + (84, 23), + (85, 122), + (86, 29), + (87, 14), + (88, 148), + (89, 295), + (90, 961), + (91, 124), + (92, 22), + (93, 8), + (94, 21), + (95, 56), + (96, 103), + (97, 107), + (98, 645), + (99, 14), + (100, 44), + (101, 199), + (102, 5085), + (103, 11), + (104, 21), + (105, 30), + (106, 16), + (107, 22), + (108, 16), + (109, 85), + (110, 17), + (111, 11), + (112, 20), + (113, 22), + (114, 44262), + (115, 503), + (116, 25), + (117, 11), + (118, 13), + (119, 9), + (120, 372), + (121, 32), + (122, 47), + (123, 67), + (124, 26), + (125, 10), + (126, 21), + (127, 29), + (128, 187), + (129, 211), + (130, 138), + (131, 6), + (132, 25), + (133, 13), + (134, 1865), + (135, 11), + (136, 13), + (137, 13), + (138, 4), + (139, 5), + (140, 9), + (141, 11), + (142, 157), + (143, 6), + (144, 11), + (145, 94), + (146, 11), + (147, 1), + (148, 17), + (149, 4), + (150, 1), + (151, 9), + (152, 3), + (153, 20), + (154, 1), + (155, 1), + (156, 137), + (157, 2), + (158, 4), + (159, 3), + (160, 5), + (161, 40), + (162, 10), + (163, 13), + (164, 113), + (165, 26), + (166, 1681), + (167, 72), + (168, 60), + (169, 99), + (170, 64), + (171, 2), + (172, 2), + (173, 33), + (174, 14), + (175, 5), + (176, 3), + (177, 9), + (178, 7), + (179, 1), + (180, 2), + (181, 59), + (182, 3), + (183, 1), + (185, 1), + (186, 115), + (188, 24), + (189, 2), + (190, 3), + (192, 1965), + (193, 27), + (194, 1), + (195, 2), + (196, 3), + (197, 9), + (198, 1440), + (199, 98), + (200, 4), + (201, 4), + (202, 22), + (204, 1), + (205, 8), + (206, 28), + (207, 22), + (208, 186), + (209, 35), + (210, 160), + (211, 3), + (212, 12), + (213, 16), + (214, 8), + (216, 23), + (217, 51), + (218, 2), + (220, 3), + (221, 2), + (222, 2), + (223, 2), + (225, 13), + (226, 4), + (228, 6), + (229, 2), + (230, 1224), + (232, 1), + (233, 3), + (234, 4), + (235, 1), + (237, 1), + (238, 3), + (239, 25), + (241, 5), + (242, 6), + (243, 1), + (244, 9), + (245, 41), + (246, 35), + (247, 20), + (248, 18), + (249, 20), + (250, 59), + (251, 13), + (252, 49), + (253, 33), + (255, 1), + (257, 11), + (258, 3), + (259, 2), + (260, 1), + (261, 6), + (262, 1247), + (264, 15), + (265, 3), + (266, 9), + (268, 8), + (269, 8), + (270, 23), + (271, 162), + (272, 11), + (273, 10), + (274, 91), + (276, 5), + (277, 4), + (278, 8), + (279, 8), + (280, 8), + (281, 7), + (282, 5), + (283, 10), + (284, 59), + (285, 39), + (286, 34), + (287, 25), + (288, 30), + (289, 64), + (290, 36), + (291, 5), + (292, 10), + (293, 5), + (294, 990), + (295, 8), + (296, 59), + (297, 1), + (298, 5), + (300, 1), + (301, 3), + (303, 8), + (305, 7), + (306, 2), + (307, 5), + (309, 2), + (311, 6), + (313, 3), + (315, 3), + (317, 2), + (318, 55), + (319, 2), + (321, 18), + (322, 1), + (323, 67), + (324, 28), + (325, 36), + (326, 1303), + (327, 21), + (328, 33), + (329, 36), + (330, 9), + (331, 11), + (332, 4), + (333, 4), + (334, 3), + (335, 10), + (336, 4), + (337, 3), + (338, 1), + (339, 7), + (340, 39), + (341, 1), + (342, 1), + (343, 4), + (344, 8), + (345, 2), + (346, 1), + (347, 4), + (349, 8), + (350, 3), + (351, 7), + (353, 11), + (354, 2), + (355, 11), + (357, 1), + (358, 1030), + (359, 7), + (360, 6), + (361, 9), + (362, 46), + (363, 68), + (364, 39), + (365, 18), + (366, 19), + (367, 31), + (368, 44), + (369, 24), + (370, 8), + (371, 39), + (372, 2), + (373, 17), + (374, 5), + (375, 74), + (376, 1), + (377, 26), + (378, 7), + (379, 156), + (380, 3), + (381, 34), + (382, 49), + (383, 18546), + (384, 55), + (385, 33545), + (386, 7395), + (387, 982), + (388, 3862), + (389, 73), + (390, 1055), + (391, 281), + (392, 151), + (393, 579), + (394, 317), + (395, 31), + (396, 84), + (397, 32), + (398, 4), + (399, 10), + (400, 11), + (401, 45), + (402, 73), + (403, 90), + (404, 25), + (405, 24), + (406, 18), + (407, 28), + (408, 39), + (409, 19), + (410, 4), + (411, 4), + (412, 1), + (413, 1), + (414, 2), + (415, 2), + (417, 12), + (418, 5), + (419, 4), + (420, 1), + (421, 1), + (422, 1033), + (424, 2), + (425, 2), + (426, 4), + (428, 7), + (429, 3), + (431, 2), + (432, 4), + (433, 3), + (436, 7), + (437, 1), + (438, 2), + (440, 25), + (441, 82), + (442, 117), + (443, 40), + (444, 19), + (445, 13), + (446, 23), + (447, 19), + (448, 11), + (449, 7), + (450, 14), + (451, 2), + (454, 1097), + (455, 2), + (456, 2), + (460, 1), + (463, 1), + (465, 4), + (466, 1), + (469, 3), + (470, 1), + (472, 3), + (474, 1), + (477, 1), + (479, 8), + (480, 73), + (481, 132), + (482, 65), + (483, 18), + (484, 11), + (485, 31), + (486, 1711), + (487, 9), + (488, 7), + (489, 8), + (490, 2), + (491, 1), + (493, 2), + (494, 4), + (495, 1), + (500, 1), + (501, 1), + (502, 1), + (513, 8), + (516, 3), + (518, 14410), + (519, 55), + (520, 99), + (521, 76), + (522, 21), + (523, 19), + (524, 24), + (525, 15), + (526, 4), + (527, 4), + (528, 1), + (529, 3), + (530, 10), + (535, 1), + (537, 1), + (538, 14), + (543, 1), + (545, 7), + (557, 4), + (558, 28), + (559, 45), + (560, 64), + (561, 22), + (562, 10), + (563, 13), + (564, 15), + (565, 14), + (566, 1), + (567, 4), + (569, 6), + (570, 7), + (572, 4), + (573, 3), + (577, 1), + (578, 1), + (582, 11), + (591, 2), + (596, 12), + (597, 16), + (598, 23), + (599, 28), + (600, 18), + (601, 20), + (602, 20), + (603, 20), + (604, 36), + (605, 6), + (606, 3), + (607, 1), + (612, 1), + (613, 2), + (614, 1), + (617, 1), + (626, 7), + (628, 1), + (635, 16), + (636, 11), + (637, 12), + (638, 16), + (639, 19), + (640, 10), + (641, 16), + (642, 18), + (643, 33), + (644, 7), + (645, 4), + (648, 7), + (649, 2), + (650, 1), + (655, 3), + (656, 3), + (657, 1), + (670, 12), + (673, 6), + (674, 7), + (675, 15), + (676, 18), + (677, 17), + (678, 3), + (679, 12), + (680, 10), + (681, 11), + (682, 23), + (683, 8), + (684, 9), + (685, 2), + (687, 2), + (688, 1), + (689, 1), + (692, 23), + (695, 3), + (696, 2), + (703, 1), + (706, 1), + (708, 1), + (713, 8), + (714, 34), + (715, 16), + (716, 12), + (717, 5), + (718, 6), + (719, 8), + (720, 8), + (721, 11), + (722, 5), + (723, 7), + (724, 7), + (726, 2), + (727, 2), + (730, 1), + (734, 3), + (735, 5), + (736, 3), + (737, 1), + (745, 3), + (750, 1), + (752, 18), + (753, 13), + (754, 13), + (755, 5), + (756, 12), + (757, 5), + (758, 7), + (759, 10), + (760, 12), + (761, 16), + (762, 7), + (763, 3), + (764, 2), + (765, 3), + (770, 1), + (774, 2), + (776, 1), + (780, 1), + (785, 1), + (789, 6), + (791, 16), + (792, 10), + (793, 29), + (794, 10), + (795, 12), + (796, 7), + (797, 10), + (798, 12), + (799, 9), + (800, 4), + (801, 3), + (802, 7), + (803, 5), + (804, 6), + (805, 1), + (808, 2), + (811, 1), + (813, 3), + (816, 1), + (824, 1), + (830, 15), + (831, 4), + (832, 15), + (833, 12), + (834, 14), + (835, 11), + (836, 12), + (837, 8), + (838, 7), + (839, 6), + (840, 5), + (841, 7), + (842, 3), + (843, 3), + (844, 2), + (845, 1), + (846, 1), + (847, 5), + (849, 1), + (852, 2), + (860, 1), + (869, 19), + (870, 4), + (871, 12), + (872, 10), + (873, 7), + (874, 13), + (875, 9), + (876, 7), + (877, 12), + (878, 6), + (879, 5), + (880, 1), + (881, 7), + (882, 10), + (883, 3), + (887, 1), + (888, 2), + (890, 3), + (891, 4), + (908, 1), + (909, 3), + (910, 9), + (911, 7), + (912, 14), + (913, 14), + (914, 7), + (915, 5), + (916, 9), + (917, 9), + (918, 2), + (919, 5), + (920, 6), + (921, 1), + (922, 1), + (924, 1), + (926, 1), + (927, 3), + (928, 4), + (930, 12), + (931, 2), + (932, 3), + (934, 2), + (948, 5), + (949, 9), + (950, 7), + (951, 5), + (952, 11), + (953, 14), + (954, 12), + (955, 6), + (956, 6), + (957, 1), + (958, 4), + (959, 6), + (960, 4), + (961, 1), + (962, 1), + (968, 2), + (969, 7), + (970, 12), + (971, 4), + (972, 2), + (977, 1), + (978, 2), + (986, 2), + (987, 3), + (988, 13), + (989, 3), + (990, 4), + (991, 11), + (992, 10), + (993, 5), + (994, 10), + (995, 7), + (996, 6), + (997, 2), + (998, 5), + (999, 1), + (1000, 1), + (1002, 3), + (1005, 1), + (1008, 5), + (1009, 8), + (1010, 5), + (1011, 3), + (1012, 2), + (1022, 4), + (1025, 1), + (1026, 6), + (1027, 8), + (1028, 5), + (1029, 5), + (1030, 10), + (1031, 7), + (1032, 8), + (1033, 12), + (1034, 6), + (1035, 4), + (1039, 2), + (1040, 4), + (1041, 4), + (1044, 6), + (1047, 10), + (1048, 3), + (1049, 5), + (1050, 4), + (1051, 1), + (1055, 2), + (1064, 2), + (1065, 2), + (1066, 5), + (1068, 1), + (1069, 3), + (1070, 5), + (1071, 8), + (1072, 12), + (1073, 8), + (1074, 5), + (1075, 1), + (1076, 1), + (1080, 5), + (1085, 2), + (1086, 5), + (1087, 8), + (1088, 7), + (1089, 1), + (1090, 1), + (1105, 2), + (1106, 4), + (1107, 6), + (1108, 12), + (1109, 7), + (1110, 9), + (1111, 12), + (1112, 12), + (1113, 4), + (1114, 2), + (1115, 2), + (1117, 1), + (1119, 2), + (1125, 4), + (1126, 4), + (1127, 6), + (1128, 2), + (1131, 1), + (1132, 2), + (1141, 6), + (1143, 7), + (1144, 9), + (1145, 13), + (1146, 3), + (1147, 6), + (1148, 5), + (1149, 7), + (1150, 6), + (1151, 7), + (1152, 3), + (1153, 2), + (1154, 1), + (1155, 2), + (1164, 1), + (1165, 6), + (1166, 4), + (1167, 3), + (1176, 1), + (1181, 1), + (1183, 8), + (1184, 1), + (1185, 3), + (1186, 3), + (1187, 4), + (1188, 7), + (1189, 7), + (1190, 13), + (1191, 8), + (1192, 2), + (1193, 3), + (1194, 2), + (1198, 2), + (1204, 1), + (1205, 3), + (1206, 1), + (1207, 3), + (1221, 4), + (1223, 3), + (1224, 5), + (1225, 1), + (1226, 4), + (1227, 5), + (1228, 8), + (1229, 6), + (1230, 5), + (1231, 5), + (1232, 4), + (1233, 1), + (1234, 1), + (1243, 1), + (1244, 1), + (1245, 2), + (1248, 1), + (1258, 1), + (1259, 2), + (1261, 1), + (1262, 1), + (1263, 4), + (1264, 8), + (1265, 4), + (1266, 7), + (1267, 18), + (1268, 8), + (1269, 6), + (1270, 3), + (1271, 2), + (1272, 1), + (1285, 2), + (1286, 1), + (1296, 6), + (1298, 1), + (1300, 9), + (1302, 6), + (1303, 4), + (1304, 7), + (1305, 4), + (1306, 12), + (1307, 14), + (1308, 7), + (1309, 1), + (1311, 1), + (1312, 1), + (1322, 1), + (1323, 2), + (1324, 1), + (1330, 3), + (1338, 1), + (1339, 2), + (1340, 1), + (1341, 3), + (1342, 1), + (1343, 2), + (1344, 8), + (1345, 7), + (1346, 14), + (1347, 6), + (1348, 1), + (1349, 1), + (1352, 1), + (1374, 1), + (1377, 1), + (1378, 4), + (1379, 2), + (1380, 1), + (1381, 4), + (1382, 5), + (1383, 11), + (1384, 5), + (1385, 12), + (1386, 6), + (1387, 3), + (1388, 2), + (1396, 1), + (1404, 1), + (1416, 3), + (1417, 2), + (1418, 4), + (1420, 5), + (1421, 7), + (1422, 10), + (1423, 8), + (1424, 9), + (1425, 5), + (1426, 4), + (1427, 1), + (1428, 1), + (1430, 1), + (1442, 1), + (1455, 1), + (1456, 1), + (1457, 1), + (1458, 4), + (1459, 6), + (1460, 10), + (1461, 12), + (1462, 10), + (1463, 10), + (1464, 7), + (1465, 2), + (1466, 2), + (1473, 1), + (1485, 1), + (1494, 2), + (1495, 7), + (1496, 9), + (1497, 8), + (1498, 7), + (1499, 6), + (1500, 11), + (1501, 10), + (1502, 12), + (1503, 9), + (1504, 3), + (1505, 4), + (1506, 1), + (1529, 3), + (1532, 1), + (1533, 25), + (1534, 3), + (1535, 8), + (1536, 5), + (1537, 3), + (1538, 5), + (1539, 17), + (1540, 11), + (1541, 14), + (1542, 11), + (1543, 4), + (1544, 3), + (1545, 1), + (1548, 1), + (1572, 3), + (1573, 4), + (1574, 2), + (1575, 3), + (1576, 5), + (1577, 3), + (1578, 10), + (1579, 18), + (1580, 10), + (1581, 11), + (1582, 4), + (1583, 4), + (1595, 1), + (1609, 2), + (1610, 1), + (1611, 3), + (1613, 3), + (1614, 3), + (1615, 5), + (1616, 12), + (1617, 13), + (1618, 15), + (1619, 25), + (1620, 2), + (1622, 1), + (1639, 2), + (1649, 2), + (1650, 3), + (1651, 9), + (1652, 3), + (1653, 4), + (1654, 3), + (1655, 4), + (1656, 12), + (1657, 18), + (1658, 11), + (1659, 10), + (1660, 1), + (1664, 1), + (1688, 2), + (1689, 2), + (1690, 4), + (1691, 1), + (1692, 2), + (1693, 7), + (1694, 7), + (1695, 11), + (1696, 17), + (1697, 13), + (1698, 8), + (1699, 2), + (1700, 2), + (1701, 1), + (1703, 1), + (1705, 5), + (1727, 6), + (1728, 1), + (1729, 4), + (1730, 3), + (1732, 7), + (1733, 7), + (1734, 4), + (1735, 19), + (1736, 9), + (1737, 5), + (1738, 1), + (1739, 2), + (1740, 1), + (1741, 1), + (1742, 1), + (1744, 1), + (1763, 6), + (1766, 10), + (1767, 3), + (1768, 4), + (1769, 2), + (1770, 2), + (1772, 5), + (1773, 19), + (1774, 18), + (1775, 16), + (1776, 7), + (1777, 4), + (1778, 3), + (1780, 1), + (1805, 1), + (1806, 4), + (1807, 2), + (1808, 5), + (1809, 5), + (1810, 7), + (1811, 4), + (1812, 13), + (1813, 17), + (1814, 10), + (1815, 8), + (1816, 4), + (1817, 3), + (1825, 2), + (1845, 1), + (1846, 3), + (1847, 1), + (1848, 5), + (1849, 3), + (1850, 4), + (1851, 7), + (1852, 10), + (1853, 20), + (1854, 10), + (1855, 7), + (1856, 1), + (1861, 1), + (1883, 4), + (1884, 8), + (1886, 1), + (1887, 4), + (1888, 3), + (1889, 9), + (1890, 8), + (1891, 12), + (1892, 11), + (1893, 6), + (1894, 2), + (1895, 1), + (1899, 1), + (1922, 7), + (1924, 3), + (1925, 3), + (1926, 7), + (1927, 8), + (1928, 7), + (1929, 11), + (1930, 13), + (1931, 13), + (1932, 9), + (1933, 4), + (1934, 5), + (1936, 1), + (1937, 1), + (1939, 2), + (1961, 8), + (1962, 2), + (1964, 2), + (1965, 9), + (1966, 7), + (1967, 7), + (1968, 11), + (1969, 5), + (1970, 13), + (1971, 9), + (1972, 5), + (1973, 1), + (1977, 1), + (1978, 1), + (1997, 2), + (2000, 8), + (2001, 6), + (2003, 4), + (2004, 7), + (2005, 6), + (2006, 6), + (2007, 10), + (2008, 15), + (2009, 10), + (2010, 14), + (2011, 3), + (2012, 2), + (2013, 1), + (2014, 3), + (2016, 1), + (2017, 1), + (2018, 2), + (2021, 1), + (2039, 2), + (2040, 2), + (2041, 1), + (2042, 4), + (2044, 7), + (2045, 10), + (2046, 13), + (2047, 10), + (2048, 18), + (2049, 12), + (2050, 7), + (2051, 1), + (2054, 3), + (2057, 1), + (2058, 1), + (2059, 1), + (2062, 1), + (2070, 5), + (2077, 1), + (2078, 4), + (2079, 6), + (2081, 1), + (2082, 6), + (2083, 7), + (2084, 4), + (2085, 15), + (2086, 16), + (2087, 10), + (2088, 9), + (2089, 11), + (2090, 2), + (2091, 2), + (2092, 2), + (2093, 1), + (2094, 1), + (2096, 2), + (2099, 1), + (2113, 6), + (2117, 3), + (2118, 2), + (2119, 1), + (2120, 3), + (2121, 5), + (2122, 9), + (2123, 5), + (2124, 10), + (2125, 16), + (2126, 10), + (2127, 4), + (2128, 2), + (2129, 1), + (2130, 3), + (2131, 1), + (2133, 1), + (2134, 1), + (2135, 4), + (2136, 1), + (2137, 1), + (2156, 5), + (2158, 1), + (2160, 2), + (2161, 2), + (2162, 5), + (2163, 10), + (2164, 12), + (2165, 3), + (2166, 9), + (2167, 5), + (2168, 4), + (2169, 1), + (2170, 2), + (2171, 1), + (2175, 1), + (2176, 1), + (2194, 1), + (2195, 2), + (2196, 2), + (2198, 1), + (2199, 4), + (2200, 7), + (2201, 4), + (2202, 4), + (2203, 14), + (2204, 3), + (2205, 5), + (2206, 6), + (2207, 3), + (2208, 1), + (2209, 2), + (2210, 1), + (2214, 1), + (2234, 7), + (2235, 1), + (2236, 3), + (2237, 2), + (2238, 1), + (2239, 3), + (2240, 10), + (2241, 13), + (2242, 12), + (2243, 14), + (2244, 16), + (2245, 5), + (2246, 2), + (2247, 1), + (2248, 2), + (2251, 3), + (2271, 1), + (2273, 8), + (2274, 2), + (2275, 1), + (2276, 3), + (2277, 5), + (2278, 5), + (2279, 3), + (2280, 11), + (2281, 8), + (2282, 11), + (2283, 5), + (2284, 2), + (2285, 2), + (2286, 2), + (2287, 2), + (2288, 1), + (2289, 1), + (2290, 1), + (2312, 17), + (2315, 1), + (2316, 5), + (2317, 3), + (2318, 9), + (2319, 7), + (2320, 10), + (2321, 18), + (2322, 13), + (2323, 7), + (2324, 1), + (2325, 1), + (2326, 7), + (2329, 1), + (2341, 1), + (2351, 15), + (2353, 3), + (2354, 10), + (2355, 8), + (2356, 5), + (2357, 7), + (2358, 9), + (2359, 12), + (2360, 8), + (2361, 9), + (2362, 5), + (2364, 4), + (2365, 4), + (2390, 7), + (2391, 1), + (2392, 4), + (2393, 4), + (2394, 3), + (2395, 6), + (2396, 13), + (2397, 3), + (2398, 6), + (2399, 12), + (2400, 8), + (2401, 7), + (2402, 5), + (2403, 2), + (2404, 1), + (2405, 1), + (2406, 1), + (2408, 7), + (2412, 1), + (2428, 1), + (2429, 11), + (2430, 2), + (2431, 4), + (2432, 2), + (2433, 5), + (2434, 10), + (2435, 15), + (2436, 7), + (2437, 17), + (2438, 10), + (2439, 8), + (2440, 8), + (2441, 1), + (2442, 4), + (2443, 2), + (2444, 1), + (2445, 2), + (2464, 2), + (2468, 4), + (2470, 13), + (2471, 2), + (2472, 5), + (2473, 7), + (2474, 6), + (2475, 8), + (2476, 8), + (2477, 7), + (2478, 5), + (2479, 9), + (2481, 4), + (2482, 1), + (2483, 1), + (2484, 1), + (2486, 2), + (2488, 1), + (2508, 8), + (2509, 7), + (2510, 2), + (2511, 7), + (2512, 9), + (2513, 9), + (2514, 10), + (2515, 15), + (2516, 8), + (2517, 10), + (2518, 8), + (2519, 3), + (2520, 3), + (2521, 4), + (2522, 3), + (2523, 2), + (2524, 1), + (2525, 1), + (2546, 1), + (2547, 3), + (2548, 1), + (2550, 6), + (2551, 4), + (2552, 2), + (2553, 6), + (2554, 14), + (2555, 10), + (2556, 10), + (2557, 8), + (2558, 3), + (2559, 2), + (2560, 1), + (2561, 2), + (2562, 2), + (2564, 1), + (2565, 1), + (2586, 1), + (2587, 2), + (2588, 1), + (2589, 4), + (2590, 4), + (2591, 3), + (2592, 4), + (2593, 10), + (2594, 13), + (2595, 9), + (2596, 9), + (2597, 5), + (2598, 2), + (2599, 3), + (2600, 4), + (2601, 1), + (2602, 2), + (2603, 1), + (2627, 1), + (2628, 5), + (2629, 3), + (2630, 9), + (2631, 5), + (2632, 14), + (2633, 7), + (2634, 5), + (2635, 6), + (2636, 4), + (2637, 1), + (2638, 1), + (2639, 5), + (2640, 6), + (2641, 1), + (2642, 1), + (2662, 1), + (2665, 9), + (2666, 9), + (2667, 2), + (2668, 6), + (2669, 6), + (2670, 8), + (2671, 5), + (2672, 14), + (2673, 11), + (2674, 8), + (2675, 5), + (2676, 1), + (2677, 1), + (2678, 2), + (2679, 4), + (2680, 1), + (2681, 1), + (2703, 2), + (2704, 1), + (2705, 4), + (2706, 4), + (2707, 7), + (2708, 5), + (2709, 5), + (2710, 3), + (2711, 10), + (2712, 6), + (2713, 8), + (2714, 6), + (2716, 3), + (2717, 2), + (2718, 3), + (2719, 3), + (2720, 1), + (2722, 1), + (2731, 2), + (2743, 1), + (2744, 2), + (2745, 5), + (2746, 3), + (2747, 3), + (2748, 2), + (2749, 8), + (2750, 8), + (2751, 7), + (2752, 10), + (2753, 2), + (2754, 1), + (2756, 5), + (2757, 2), + (2758, 1), + (2760, 6), + (2775, 1), + (2778, 1), + (2782, 1), + (2783, 1), + (2784, 4), + (2785, 2), + (2786, 3), + (2787, 4), + (2788, 3), + (2789, 9), + (2790, 11), + (2791, 5), + (2792, 2), + (2793, 3), + (2794, 1), + (2795, 4), + (2797, 2), + (2798, 1), + (2799, 1), + (2822, 1), + (2823, 2), + (2824, 1), + (2825, 2), + (2826, 4), + (2827, 3), + (2828, 5), + (2829, 8), + (2830, 6), + (2831, 3), + (2832, 2), + (2833, 1), + (2834, 2), + (2835, 1), + (2836, 1), + (2837, 2), + (2860, 2), + (2861, 1), + (2862, 9), + (2863, 4), + (2864, 5), + (2865, 5), + (2866, 7), + (2867, 7), + (2868, 18), + (2869, 5), + (2870, 4), + (2872, 1), + (2873, 2), + (2874, 1), + (2877, 1), + (2878, 2), + (2899, 1), + (2900, 7), + (2901, 10), + (2902, 5), + (2903, 8), + (2904, 1), + (2905, 6), + (2906, 7), + (2907, 4), + (2908, 4), + (2909, 5), + (2910, 1), + (2911, 2), + (2912, 1), + (2916, 1), + (2939, 2), + (2940, 2), + (2942, 2), + (2943, 4), + (2944, 7), + (2945, 5), + (2946, 4), + (2947, 7), + (2948, 4), + (2951, 1), + (2954, 2), + (2955, 1), + (2962, 6), + (2977, 2), + (2979, 1), + (2980, 4), + (2981, 4), + (2982, 2), + (2983, 5), + (2984, 8), + (2985, 3), + (2986, 5), + (2987, 2), + (2989, 1), + (2995, 2), + (2996, 2), + (3016, 3), + (3017, 5), + (3018, 3), + (3019, 3), + (3020, 3), + (3021, 2), + (3022, 8), + (3023, 4), + (3024, 5), + (3025, 5), + (3026, 4), + (3027, 1), + (3029, 6), + (3030, 1), + (3031, 1), + (3033, 1), + (3035, 1), + (3054, 1), + (3055, 1), + (3056, 4), + (3057, 3), + (3058, 1), + (3059, 4), + (3061, 3), + (3062, 7), + (3063, 2), + (3064, 4), + (3065, 1), + (3066, 2), + (3068, 2), + (3069, 3), + (3072, 1), + (3073, 1), + (3086, 1), + (3092, 2), + (3093, 1), + (3094, 1), + (3095, 3), + (3096, 5), + (3097, 5), + (3098, 2), + (3099, 9), + (3100, 4), + (3101, 7), + (3102, 6), + (3103, 4), + (3105, 3), + (3106, 1), + (3110, 1), + (3111, 1), + (3124, 6), + (3134, 2), + (3135, 5), + (3136, 4), + (3137, 2), + (3138, 4), + (3139, 7), + (3140, 9), + (3141, 1), + (3142, 1), + (3143, 5), + (3144, 1), + (3145, 1), + (3148, 2), + (3150, 1), + (3152, 1), + (3172, 3), + (3173, 1), + (3174, 2), + (3175, 3), + (3177, 3), + (3178, 3), + (3179, 7), + (3180, 5), + (3181, 5), + (3183, 1), + (3184, 1), + (3185, 2), + (3186, 1), + (3189, 1), + (3194, 4), + (3212, 3), + (3213, 2), + (3214, 7), + (3215, 5), + (3216, 2), + (3217, 4), + (3218, 11), + (3219, 1), + (3220, 2), + (3221, 1), + (3222, 1), + (3223, 2), + (3224, 1), + (3225, 2), + (3250, 6), + (3251, 1), + (3252, 5), + (3253, 6), + (3254, 3), + (3255, 3), + (3256, 5), + (3257, 1), + (3258, 3), + (3259, 5), + (3260, 1), + (3261, 2), + (3263, 2), + (3288, 1), + (3289, 6), + (3290, 1), + (3291, 3), + (3292, 2), + (3293, 5), + (3294, 4), + (3295, 5), + (3296, 6), + (3297, 7), + (3299, 2), + (3300, 1), + (3301, 3), + (3302, 2), + (3306, 1), + (3328, 6), + (3329, 3), + (3330, 4), + (3331, 2), + (3333, 10), + (3334, 5), + (3335, 2), + (3336, 3), + (3337, 4), + (3338, 1), + (3339, 1), + (3344, 3), + (3366, 7), + (3367, 6), + (3368, 5), + (3369, 4), + (3370, 4), + (3371, 8), + (3372, 3), + (3373, 3), + (3374, 6), + (3375, 4), + (3376, 4), + (3377, 1), + (3378, 2), + (3380, 1), + (3384, 1), + (3386, 1), + (3389, 6), + (3405, 1), + (3406, 4), + (3407, 2), + (3409, 3), + (3410, 6), + (3411, 6), + (3412, 1), + (3413, 4), + (3414, 2), + (3415, 3), + (3416, 4), + (3417, 1), + (3418, 2), + (3419, 1), + (3445, 2), + (3446, 1), + (3447, 2), + (3448, 2), + (3449, 3), + (3450, 6), + (3451, 2), + (3452, 7), + (3453, 5), + (3454, 5), + (3456, 1), + (3463, 1), + (3477, 1), + (3483, 1), + (3484, 8), + (3485, 2), + (3486, 1), + (3487, 5), + (3488, 1), + (3489, 5), + (3490, 4), + (3491, 2), + (3493, 2), + (3494, 3), + (3496, 1), + (3499, 1), + (3501, 1), + (3502, 1), + (3512, 4), + (3522, 1), + (3524, 4), + (3525, 2), + (3526, 4), + (3527, 2), + (3528, 3), + (3529, 2), + (3530, 3), + (3531, 5), + (3532, 2), + (3533, 3), + (3534, 3), + (3540, 1), + (3554, 1), + (3562, 1), + (3563, 2), + (3564, 13), + (3565, 5), + (3566, 4), + (3567, 4), + (3568, 3), + (3569, 11), + (3570, 4), + (3571, 1), + (3573, 2), + (3576, 1), + (3600, 1), + (3602, 4), + (3603, 6), + (3604, 4), + (3605, 3), + (3606, 6), + (3607, 4), + (3608, 5), + (3609, 6), + (3610, 4), + (3612, 2), + (3613, 1), + (3614, 1), + (3639, 1), + (3640, 1), + (3641, 3), + (3642, 5), + (3643, 2), + (3644, 3), + (3645, 2), + (3646, 1), + (3647, 4), + (3648, 2), + (3649, 4), + (3650, 5), + (3651, 1), + (3652, 1), + (3657, 1), + (3658, 1), + (3679, 2), + (3680, 3), + (3681, 5), + (3682, 2), + (3683, 3), + (3684, 5), + (3685, 2), + (3686, 4), + (3687, 2), + (3688, 3), + (3689, 2), + (3690, 1), + (3691, 3), + (3692, 1), + (3718, 2), + (3719, 5), + (3720, 5), + (3721, 7), + (3722, 2), + (3723, 5), + (3724, 3), + (3725, 7), + (3726, 5), + (3727, 1), + (3728, 4), + (3729, 3), + (3731, 1), + (3756, 2), + (3757, 2), + (3758, 11), + (3759, 3), + (3760, 5), + (3761, 2), + (3762, 2), + (3763, 3), + (3764, 1), + (3765, 4), + (3766, 2), + (3769, 1), + (3770, 1), + (3795, 1), + (3796, 4), + (3797, 6), + (3798, 7), + (3799, 3), + (3800, 5), + (3801, 3), + (3802, 2), + (3803, 5), + (3804, 9), + (3805, 1), + (3806, 3), + (3808, 1), + (3834, 2), + (3836, 4), + (3837, 6), + (3838, 3), + (3839, 2), + (3840, 1), + (3841, 2), + (3842, 5), + (3843, 4), + (3844, 2), + (3845, 3), + (3846, 2), + (3850, 1), + (3874, 2), + (3875, 2), + (3876, 8), + (3877, 3), + (3878, 2), + (3879, 4), + (3880, 3), + (3881, 4), + (3882, 4), + (3883, 2), + (3884, 4), + (3885, 2), + (3912, 1), + (3913, 1), + (3914, 4), + (3915, 4), + (3916, 2), + (3917, 3), + (3918, 4), + (3919, 2), + (3920, 3), + (3921, 1), + (3923, 1), + (3924, 1), + (3929, 1), + (3931, 1), + (3952, 2), + (3953, 3), + (3954, 2), + (3955, 4), + (3956, 4), + (3957, 3), + (3958, 3), + (3959, 3), + (3960, 1), + (3961, 2), + (3962, 1), + (3963, 4), + (3964, 1), + (3992, 3), + (3993, 6), + (3994, 6), + (3995, 1), + (3996, 3), + (3997, 2), + (3998, 2), + (3999, 1), + (4000, 2), + (4003, 1), + (4029, 1), + (4030, 1), + (4031, 3), + (4032, 3), + (4033, 2), + (4034, 1), + (4035, 3), + (4037, 3), + (4038, 4), + (4039, 2), + (4040, 3), + (4041, 3), + (4069, 1), + (4070, 6), + (4071, 2), + (4072, 1), + (4073, 2), + (4074, 6), + (4075, 1), + (4076, 4), + (4077, 2), + (4078, 4), + (4080, 1), + (4081, 1), + (4082, 2), + (4083, 1), + (4108, 2), + (4109, 3), + (4110, 3), + (4111, 2), + (4112, 1), + (4113, 5), + (4114, 2), + (4115, 5), + (4116, 2), + (4118, 1), + (4119, 3), + (4121, 1), + (4123, 1), + (4126, 1), + (4147, 2), + (4148, 3), + (4149, 6), + (4150, 5), + (4151, 3), + (4152, 4), + (4154, 5), + (4155, 2), + (4156, 1), + (4157, 7), + (4159, 1), + (4160, 2), + (4162, 2), + (4186, 3), + (4187, 2), + (4188, 6), + (4189, 3), + (4190, 5), + (4191, 4), + (4193, 4), + (4194, 3), + (4195, 4), + (4196, 2), + (4197, 2), + (4198, 3), + (4199, 1), + (4224, 1), + (4225, 3), + (4226, 1), + (4227, 3), + (4228, 3), + (4230, 3), + (4231, 3), + (4232, 3), + (4233, 1), + (4234, 3), + (4235, 5), + (4236, 3), + (4237, 1), + (4259, 2), + (4263, 2), + (4264, 2), + (4265, 6), + (4266, 5), + (4267, 2), + (4268, 6), + (4269, 1), + (4270, 3), + (4271, 1), + (4272, 1), + (4273, 4), + (4274, 2), + (4275, 3), + (4276, 2), + (4277, 1), + (4280, 5), + (4282, 1), + (4300, 2), + (4302, 2), + (4303, 4), + (4304, 8), + (4305, 3), + (4306, 3), + (4307, 3), + (4308, 1), + (4309, 1), + (4310, 3), + (4311, 2), + (4312, 3), + (4313, 3), + (4314, 3), + (4341, 2), + (4343, 2), + (4344, 9), + (4345, 2), + (4346, 3), + (4347, 1), + (4348, 2), + (4349, 6), + (4350, 1), + (4351, 2), + (4352, 1), + (4353, 1), + (4354, 1), + (4356, 2), + (4380, 2), + (4381, 1), + (4382, 3), + (4383, 8), + (4384, 3), + (4386, 2), + (4387, 5), + (4388, 1), + (4389, 3), + (4391, 1), + (4392, 1), + (4393, 1), + (4419, 2), + (4420, 3), + (4421, 1), + (4422, 4), + (4423, 5), + (4425, 5), + (4426, 2), + (4427, 1), + (4428, 2), + (4429, 1), + (4430, 2), + (4431, 3), + (4432, 7), + (4433, 3), + (4434, 1), + (4458, 2), + (4459, 6), + (4460, 5), + (4461, 4), + (4462, 9), + (4463, 2), + (4464, 1), + (4465, 1), + (4466, 1), + (4468, 7), + (4469, 3), + (4470, 2), + (4471, 2), + (4497, 1), + (4498, 1), + (4499, 9), + (4500, 3), + (4501, 5), + (4502, 2), + (4503, 5), + (4505, 5), + (4506, 3), + (4507, 2), + (4508, 1), + (4509, 1), + (4511, 2), + (4536, 3), + (4537, 4), + (4538, 3), + (4539, 3), + (4540, 2), + (4541, 3), + (4542, 2), + (4543, 1), + (4546, 4), + (4547, 4), + (4575, 1), + (4576, 1), + (4577, 2), + (4578, 1), + (4579, 2), + (4580, 1), + (4581, 6), + (4582, 3), + (4583, 5), + (4584, 1), + (4585, 4), + (4586, 2), + (4589, 1), + (4614, 1), + (4615, 1), + (4616, 1), + (4618, 7), + (4619, 2), + (4621, 2), + (4622, 2), + (4623, 2), + (4624, 3), + (4625, 1), + (4627, 1), + (4628, 3), + (4654, 5), + (4655, 1), + (4656, 3), + (4657, 6), + (4658, 2), + (4659, 4), + (4660, 2), + (4662, 1), + (4663, 3), + (4664, 1), + (4668, 1), + (4669, 1), + (4692, 1), + (4693, 2), + (4694, 2), + (4695, 3), + (4696, 2), + (4697, 1), + (4699, 3), + (4700, 1), + (4701, 1), + (4702, 2), + (4704, 3), + (4706, 1), + (4707, 2), + (4731, 1), + (4733, 4), + (4734, 4), + (4735, 3), + (4736, 1), + (4738, 1), + (4740, 2), + (4741, 2), + (4742, 3), + (4744, 2), + (4745, 3), + (4771, 4), + (4772, 4), + (4773, 4), + (4774, 2), + (4777, 4), + (4778, 3), + (4779, 4), + (4781, 4), + (4782, 1), + (4785, 2), + (4811, 1), + (4812, 5), + (4813, 1), + (4814, 3), + (4815, 2), + (4816, 3), + (4817, 4), + (4818, 5), + (4819, 2), + (4820, 2), + (4821, 1), + (4822, 1), + (4823, 2), + (4834, 1), + (4849, 2), + (4850, 2), + (4851, 2), + (4852, 3), + (4853, 3), + (4854, 4), + (4855, 2), + (4856, 5), + (4857, 2), + (4858, 3), + (4860, 1), + (4861, 1), + (4862, 1), + (4888, 1), + (4889, 1), + (4890, 3), + (4892, 3), + (4893, 1), + (4894, 6), + (4895, 6), + (4896, 6), + (4897, 2), + (4898, 1), + (4899, 1), + (4900, 2), + (4901, 1), + (4928, 1), + (4929, 3), + (4930, 2), + (4932, 4), + (4933, 5), + (4934, 6), + (4935, 3), + (4936, 2), + (4937, 1), + (4938, 1), + (4939, 4), + (4940, 1), + (4941, 1), + (4965, 1), + (4967, 2), + (4968, 2), + (4969, 1), + (4970, 2), + (4971, 2), + (4972, 5), + (4973, 1), + (4974, 2), + (4975, 1), + (4977, 2), + (4978, 1), + (5006, 2), + (5007, 3), + (5009, 2), + (5010, 3), + (5012, 1), + (5013, 1), + (5014, 2), + (5015, 4), + (5016, 3), + (5018, 1), + (5019, 3), + (5021, 1), + (5042, 1), + (5044, 2), + (5047, 1), + (5049, 3), + (5050, 2), + (5051, 1), + (5052, 3), + (5053, 1), + (5055, 1), + (5083, 1), + (5084, 3), + (5085, 3), + (5088, 1), + (5089, 5), + (5090, 2), + (5091, 3), + (5092, 2), + (5093, 1), + (5094, 1), + (5097, 1), + (5098, 1), + (5122, 1), + (5124, 2), + (5125, 1), + (5126, 1), + (5127, 2), + (5128, 3), + (5129, 5), + (5130, 2), + (5131, 6), + (5132, 1), + (5133, 3), + (5135, 1), + (5136, 2), + (5138, 1), + (5162, 1), + (5163, 3), + (5164, 1), + (5165, 2), + (5167, 4), + (5168, 4), + (5169, 1), + (5170, 4), + (5171, 1), + (5172, 1), + (5200, 1), + (5202, 1), + (5203, 1), + (5204, 1), + (5205, 1), + (5206, 1), + (5207, 1), + (5208, 3), + (5209, 5), + (5210, 1), + (5211, 2), + (5213, 2), + (5215, 1), + (5216, 1), + (5239, 3), + (5240, 1), + (5241, 1), + (5242, 2), + (5243, 2), + (5244, 3), + (5245, 1), + (5246, 4), + (5247, 2), + (5248, 3), + (5249, 2), + (5250, 1), + (5251, 2), + (5253, 2), + (5280, 1), + (5282, 2), + (5283, 2), + (5284, 3), + (5285, 3), + (5286, 1), + (5287, 3), + (5288, 1), + (5289, 2), + (5290, 1), + (5293, 1), + (5317, 1), + (5318, 1), + (5320, 1), + (5321, 3), + (5322, 3), + (5323, 2), + (5324, 3), + (5325, 4), + (5326, 3), + (5327, 3), + (5330, 2), + (5356, 3), + (5357, 1), + (5358, 1), + (5359, 1), + (5360, 1), + (5361, 5), + (5362, 3), + (5363, 4), + (5364, 3), + (5365, 3), + (5366, 1), + (5367, 1), + (5369, 1), + (5370, 1), + (5371, 1), + (5372, 1), + (5396, 1), + (5397, 1), + (5399, 1), + (5400, 2), + (5401, 4), + (5402, 4), + (5403, 2), + (5404, 3), + (5405, 3), + (5406, 2), + (5407, 1), + (5408, 1), + (5409, 2), + (5410, 2), + (5412, 1), + (5435, 1), + (5437, 1), + (5438, 3), + (5439, 8), + (5440, 3), + (5441, 3), + (5442, 6), + (5443, 2), + (5445, 3), + (5448, 2), + (5450, 1), + (5473, 1), + (5474, 1), + (5475, 1), + (5476, 1), + (5477, 1), + (5478, 1), + (5479, 4), + (5480, 2), + (5481, 2), + (5483, 1), + (5485, 1), + (5486, 3), + (5487, 2), + (5508, 5), + (5512, 2), + (5514, 1), + (5515, 4), + (5516, 3), + (5517, 1), + (5518, 5), + (5519, 1), + (5520, 7), + (5521, 1), + (5522, 3), + (5523, 1), + (5524, 2), + (5525, 6), + (5526, 1), + (5542, 3), + (5555, 4), + (5556, 3), + (5557, 1), + (5558, 2), + (5559, 5), + (5560, 4), + (5561, 5), + (5562, 2), + (5563, 1), + (5564, 1), + (5566, 1), + (5590, 1), + (5591, 2), + (5593, 1), + (5594, 1), + (5595, 1), + (5596, 5), + (5597, 3), + (5598, 2), + (5599, 4), + (5600, 1), + (5601, 2), + (5602, 1), + (5603, 3), + (5604, 1), + (5605, 1), + (5606, 1), + (5620, 6), + (5632, 2), + (5633, 3), + (5634, 5), + (5635, 3), + (5636, 5), + (5637, 3), + (5638, 5), + (5639, 2), + (5640, 5), + (5641, 5), + (5642, 2), + (5643, 1), + (5668, 1), + (5669, 2), + (5671, 1), + (5672, 3), + (5673, 2), + (5674, 6), + (5675, 3), + (5676, 4), + (5677, 5), + (5678, 3), + (5679, 3), + (5681, 2), + (5682, 2), + (5683, 2), + (5684, 2), + (5707, 1), + (5710, 3), + (5711, 6), + (5712, 6), + (5713, 2), + (5714, 3), + (5715, 4), + (5716, 4), + (5717, 3), + (5718, 2), + (5719, 4), + (5720, 1), + (5721, 2), + (5722, 1), + (5745, 5), + (5749, 1), + (5750, 6), + (5751, 8), + (5752, 3), + (5753, 3), + (5754, 4), + (5755, 2), + (5756, 2), + (5757, 1), + (5758, 3), + (5759, 1), + (5760, 1), + (5761, 3), + (5787, 2), + (5789, 5), + (5790, 9), + (5791, 1), + (5792, 3), + (5793, 4), + (5794, 5), + (5795, 2), + (5797, 3), + (5798, 6), + (5799, 1), + (5801, 1), + (5803, 1), + (5825, 2), + (5828, 2), + (5829, 9), + (5830, 3), + (5831, 1), + (5832, 7), + (5833, 4), + (5834, 1), + (5835, 8), + (5837, 1), + (5838, 2), + (5840, 1), + (5863, 1), + (5864, 1), + (5866, 1), + (5867, 2), + (5868, 3), + (5869, 6), + (5870, 4), + (5871, 6), + (5872, 4), + (5873, 1), + (5874, 7), + (5875, 4), + (5876, 2), + (5878, 4), + (5902, 2), + (5906, 2), + (5907, 6), + (5908, 3), + (5909, 1), + (5910, 1), + (5911, 2), + (5912, 5), + (5913, 2), + (5914, 3), + (5915, 1), + (5916, 1), + (5940, 1), + (5942, 2), + (5943, 1), + (5945, 2), + (5946, 3), + (5947, 6), + (5948, 5), + (5949, 2), + (5950, 2), + (5951, 1), + (5952, 1), + (5953, 4), + (5954, 4), + (5955, 1), + (5956, 2), + (5957, 1), + (5983, 1), + (5984, 3), + (5985, 2), + (5986, 3), + (5987, 5), + (5988, 1), + (5989, 4), + (5990, 2), + (5991, 4), + (5992, 4), + (5993, 2), + (5994, 2), + (5995, 1), + (5996, 2), + (5997, 1), + (5998, 1), + (6019, 1), + (6020, 1), + (6021, 1), + (6023, 2), + (6024, 4), + (6025, 2), + (6026, 5), + (6027, 1), + (6028, 5), + (6029, 2), + (6030, 4), + (6031, 3), + (6032, 1), + (6033, 1), + (6034, 1), + (6035, 1), + (6058, 2), + (6060, 2), + (6061, 3), + (6062, 1), + (6063, 4), + (6064, 3), + (6065, 4), + (6066, 5), + (6067, 5), + (6068, 3), + (6069, 4), + (6070, 1), + (6071, 4), + (6072, 3), + (6073, 2), + (6097, 1), + (6098, 1), + (6099, 1), + (6100, 1), + (6102, 4), + (6103, 1), + (6104, 5), + (6105, 3), + (6106, 2), + (6107, 1), + (6109, 1), + (6111, 2), + (6113, 1), + (6114, 2), + (6130, 1), + (6136, 1), + (6137, 2), + (6139, 1), + (6140, 1), + (6141, 1), + (6142, 4), + (6143, 2), + (6144, 2), + (6146, 5), + (6147, 3), + (6148, 4), + (6149, 3), + (6150, 1), + (6151, 4), + (6152, 2), + (6153, 1), + (6175, 1), + (6177, 4), + (6178, 1), + (6179, 4), + (6180, 3), + (6181, 4), + (6182, 7), + (6183, 3), + (6184, 4), + (6185, 5), + (6186, 2), + (6187, 4), + (6188, 1), + (6189, 3), + (6190, 3), + (6191, 1), + (6215, 1), + (6217, 3), + (6219, 2), + (6220, 1), + (6221, 5), + (6222, 2), + (6223, 1), + (6224, 4), + (6225, 1), + (6226, 3), + (6227, 2), + (6228, 2), + (6229, 4), + (6230, 2), + (6253, 1), + (6256, 1), + (6257, 1), + (6258, 3), + (6259, 4), + (6260, 6), + (6261, 4), + (6263, 3), + (6264, 3), + (6265, 4), + (6266, 5), + (6267, 1), + (6268, 2), + (6269, 2), + (6273, 1), + (6292, 2), + (6296, 2), + (6298, 3), + (6299, 8), + (6300, 5), + (6301, 2), + (6302, 5), + (6303, 2), + (6304, 3), + (6305, 3), + (6306, 4), + (6307, 5), + (6308, 3), + (6309, 1), + (6324, 1), + (6332, 1), + (6333, 1), + (6334, 4), + (6335, 1), + (6336, 1), + (6337, 6), + (6338, 5), + (6339, 4), + (6340, 1), + (6342, 4), + (6343, 4), + (6344, 1), + (6345, 1), + (6346, 1), + (6348, 3), + (6349, 1), + (6369, 1), + (6370, 2), + (6371, 1), + (6374, 1), + (6376, 2), + (6377, 3), + (6378, 3), + (6379, 2), + (6380, 2), + (6381, 2), + (6382, 1), + (6383, 2), + (6384, 1), + (6385, 3), + (6386, 2), + (6409, 1), + (6413, 2), + (6414, 1), + (6415, 4), + (6416, 2), + (6417, 2), + (6418, 4), + (6419, 2), + (6420, 3), + (6421, 2), + (6422, 3), + (6423, 6), + (6424, 3), + (6426, 3), + (6430, 1), + (6450, 1), + (6451, 1), + (6452, 2), + (6453, 2), + (6454, 1), + (6455, 2), + (6456, 2), + (6457, 7), + (6458, 1), + (6459, 7), + (6460, 2), + (6461, 3), + (6463, 2), + (6464, 3), + (6466, 2), + (6489, 1), + (6493, 2), + (6494, 7), + (6495, 2), + (6496, 4), + (6497, 2), + (6498, 8), + (6499, 1), + (6501, 4), + (6502, 2), + (6503, 4), + (6505, 1), + (6528, 2), + (6530, 4), + (6531, 1), + (6532, 2), + (6533, 1), + (6534, 4), + (6535, 4), + (6537, 1), + (6538, 3), + (6539, 4), + (6540, 2), + (6541, 2), + (6542, 4), + (6543, 1), + (6565, 1), + (6566, 1), + (6568, 1), + (6569, 3), + (6570, 4), + (6571, 3), + (6572, 4), + (6573, 1), + (6574, 2), + (6575, 3), + (6576, 3), + (6577, 1), + (6578, 3), + (6579, 3), + (6580, 4), + (6581, 1), + (6582, 2), + (6584, 1), + (6606, 1), + (6607, 2), + (6608, 2), + (6609, 3), + (6610, 2), + (6611, 4), + (6612, 4), + (6613, 2), + (6614, 1), + (6615, 1), + (6616, 6), + (6617, 1), + (6618, 1), + (6619, 1), + (6620, 1), + (6621, 2), + (6647, 3), + (6648, 5), + (6649, 3), + (6650, 2), + (6651, 4), + (6652, 3), + (6653, 3), + (6654, 1), + (6655, 5), + (6656, 3), + (6657, 1), + (6658, 3), + (6661, 1), + (6682, 1), + (6685, 4), + (6687, 1), + (6688, 3), + (6689, 5), + (6690, 5), + (6691, 1), + (6692, 2), + (6694, 5), + (6695, 3), + (6696, 2), + (6697, 2), + (6698, 5), + (6720, 2), + (6722, 1), + (6723, 1), + (6724, 2), + (6725, 3), + (6726, 5), + (6727, 5), + (6729, 5), + (6731, 2), + (6732, 2), + (6733, 4), + (6734, 2), + (6735, 5), + (6736, 3), + (6737, 2), + (6738, 1), + (6740, 1), + (6760, 1), + (6762, 1), + (6765, 5), + (6766, 1), + (6767, 4), + (6768, 4), + (6769, 2), + (6770, 3), + (6771, 10), + (6773, 3), + (6774, 4), + (6775, 4), + (6776, 1), + (6778, 1), + (6803, 3), + (6805, 3), + (6806, 4), + (6807, 2), + (6808, 6), + (6809, 2), + (6810, 5), + (6811, 3), + (6812, 3), + (6813, 2), + (6814, 3), + (6815, 1), + (6816, 1), + (6820, 1), + (6839, 1), + (6841, 2), + (6842, 1), + (6843, 4), + (6844, 1), + (6845, 3), + (6846, 2), + (6847, 1), + (6848, 4), + (6849, 4), + (6850, 7), + (6851, 3), + (6852, 6), + (6853, 4), + (6854, 2), + (6855, 2), + (6856, 1), + (6863, 6), + (6879, 1), + (6882, 4), + (6883, 3), + (6884, 2), + (6885, 3), + (6886, 4), + (6887, 2), + (6888, 2), + (6889, 2), + (6890, 1), + (6891, 4), + (6892, 1), + (6893, 1), + (6894, 1), + (6916, 1), + (6917, 1), + (6919, 1), + (6921, 3), + (6922, 3), + (6923, 3), + (6924, 8), + (6925, 2), + (6926, 2), + (6927, 2), + (6928, 1), + (6929, 3), + (6930, 3), + (6931, 2), + (6932, 1), + (6933, 1), + (6934, 1), + (6952, 6), + (6954, 1), + (6956, 1), + (6957, 1), + (6958, 1), + (6959, 3), + (6960, 2), + (6961, 3), + (6962, 4), + (6964, 2), + (6965, 3), + (6966, 3), + (6967, 3), + (6968, 1), + (6969, 6), + (6970, 1), + (6971, 2), + (6973, 1), + (6993, 1), + (6995, 2), + (6996, 1), + (6997, 1), + (6998, 2), + (6999, 1), + (7000, 1), + (7001, 3), + (7002, 6), + (7003, 1), + (7004, 1), + (7005, 3), + (7006, 6), + (7007, 4), + (7008, 2), + (7009, 5), + (7010, 2), + (7034, 1), + (7035, 1), + (7037, 3), + (7038, 1), + (7039, 1), + (7040, 5), + (7041, 1), + (7042, 4), + (7043, 6), + (7044, 2), + (7045, 2), + (7046, 2), + (7047, 4), + (7048, 2), + (7050, 1), + (7074, 1), + (7076, 1), + (7077, 4), + (7078, 4), + (7080, 6), + (7081, 2), + (7083, 5), + (7084, 3), + (7085, 1), + (7086, 1), + (7087, 2), + (7088, 1), + (7089, 1), + (7090, 1), + (7098, 6), + (7111, 1), + (7113, 1), + (7114, 2), + (7115, 2), + (7116, 4), + (7117, 2), + (7118, 2), + (7119, 4), + (7120, 3), + (7121, 3), + (7122, 7), + (7123, 5), + (7124, 1), + (7125, 4), + (7126, 2), + (7127, 1), + (7129, 3), + (7150, 2), + (7151, 1), + (7153, 5), + (7154, 2), + (7155, 1), + (7156, 1), + (7157, 6), + (7158, 2), + (7159, 2), + (7160, 3), + (7161, 1), + (7162, 4), + (7164, 4), + (7165, 1), + (7167, 1), + (7184, 2), + (7192, 1), + (7194, 3), + (7195, 3), + (7196, 1), + (7197, 4), + (7198, 1), + (7199, 5), + (7200, 6), + (7201, 2), + (7202, 6), + (7203, 1), + (7204, 5), + (7205, 2), + (7232, 2), + (7233, 2), + (7234, 4), + (7235, 6), + (7236, 2), + (7238, 1), + (7239, 4), + (7240, 2), + (7241, 4), + (7242, 3), + (7243, 4), + (7244, 1), + (7246, 3), + (7248, 2), + (7266, 1), + (7268, 1), + (7270, 1), + (7271, 3), + (7273, 4), + (7274, 4), + (7275, 1), + (7276, 3), + (7277, 2), + (7278, 2), + (7279, 2), + (7280, 4), + (7281, 2), + (7282, 3), + (7284, 1), + (7289, 1), + (7308, 1), + (7309, 1), + (7310, 3), + (7311, 1), + (7312, 5), + (7313, 3), + (7314, 1), + (7315, 6), + (7316, 3), + (7317, 2), + (7318, 3), + (7319, 3), + (7320, 4), + (7321, 3), + (7322, 1), + (7323, 1), + (7324, 3), + (7325, 1), + (7348, 2), + (7349, 2), + (7350, 1), + (7351, 3), + (7352, 4), + (7353, 3), + (7354, 4), + (7355, 2), + (7356, 3), + (7358, 4), + (7359, 3), + (7360, 5), + (7361, 3), + (7362, 1), + (7363, 1), + (7372, 6), + (7386, 1), + (7387, 1), + (7389, 3), + (7390, 7), + (7391, 2), + (7392, 4), + (7393, 4), + (7395, 3), + (7396, 3), + (7397, 3), + (7398, 5), + (7399, 2), + (7400, 1), + (7401, 3), + (7402, 2), + (7403, 1), + (7424, 2), + (7425, 1), + (7426, 2), + (7427, 7), + (7428, 6), + (7429, 2), + (7430, 3), + (7431, 4), + (7432, 3), + (7433, 1), + (7434, 2), + (7435, 3), + (7436, 1), + (7438, 4), + (7439, 1), + (7440, 1), + (7446, 1), + (7461, 1), + (7464, 1), + (7467, 2), + (7468, 2), + (7469, 2), + (7470, 5), + (7471, 4), + (7472, 2), + (7473, 1), + (7474, 2), + (7475, 8), + (7476, 3), + (7477, 6), + (7478, 4), + (7479, 1), + (7480, 1), + (7482, 1), + (7489, 1), + (7490, 6), + (7502, 2), + (7503, 1), + (7504, 1), + (7505, 3), + (7506, 2), + (7507, 1), + (7508, 2), + (7509, 4), + (7510, 3), + (7511, 3), + (7512, 1), + (7513, 5), + (7514, 7), + (7515, 5), + (7516, 7), + (7517, 2), + (7518, 4), + (7519, 1), + (7520, 2), + (7544, 4), + (7545, 4), + (7546, 3), + (7547, 3), + (7548, 6), + (7549, 2), + (7550, 2), + (7551, 3), + (7552, 1), + (7553, 2), + (7554, 4), + (7555, 3), + (7556, 1), + (7557, 3), + (7558, 2), + (7559, 2), + (7578, 1), + (7584, 2), + (7585, 5), + (7586, 4), + (7588, 3), + (7589, 2), + (7590, 2), + (7591, 4), + (7592, 6), + (7593, 3), + (7594, 3), + (7595, 4), + (7597, 1), + (7619, 1), + (7621, 1), + (7622, 2), + (7623, 1), + (7624, 3), + (7625, 1), + (7626, 1), + (7628, 3), + (7630, 5), + (7631, 4), + (7632, 2), + (7633, 4), + (7634, 5), + (7635, 4), + (7636, 1), + (7637, 1), + (7648, 6), + (7655, 6), + (7659, 2), + (7660, 1), + (7661, 3), + (7662, 4), + (7663, 3), + (7664, 2), + (7665, 3), + (7667, 2), + (7668, 2), + (7669, 2), + (7670, 4), + (7671, 3), + (7672, 4), + (7673, 5), + (7685, 1), + (7699, 1), + (7700, 1), + (7701, 2), + (7702, 6), + (7703, 3), + (7704, 2), + (7705, 4), + (7706, 1), + (7707, 4), + (7708, 3), + (7709, 3), + (7710, 3), + (7711, 4), + (7739, 2), + (7740, 3), + (7741, 4), + (7742, 6), + (7743, 2), + (7744, 6), + (7746, 4), + (7747, 2), + (7748, 4), + (7750, 2), + (7751, 2), + (7752, 1), + (7753, 2), + (7754, 1), + (7776, 2), + (7777, 1), + (7779, 3), + (7780, 1), + (7781, 6), + (7782, 4), + (7783, 2), + (7784, 3), + (7787, 3), + (7788, 4), + (7789, 3), + (7790, 3), + (7791, 3), + (7792, 2), + (7813, 1), + (7817, 4), + (7818, 1), + (7820, 3), + (7821, 2), + (7823, 1), + (7824, 4), + (7825, 2), + (7826, 3), + (7827, 2), + (7828, 5), + (7830, 2), + (7831, 2), + (7832, 1), + (7836, 6), + (7852, 1), + (7853, 2), + (7855, 1), + (7856, 1), + (7857, 4), + (7858, 1), + (7859, 4), + (7860, 2), + (7862, 5), + (7863, 1), + (7864, 2), + (7866, 1), + (7867, 2), + (7868, 1), + (7869, 1), + (7870, 1), + (7871, 1), + (7894, 1), + (7895, 2), + (7896, 4), + (7897, 3), + (7898, 4), + (7899, 1), + (7900, 3), + (7901, 6), + (7902, 1), + (7903, 3), + (7904, 7), + (7906, 4), + (7907, 2), + (7908, 2), + (7909, 1), + (7910, 1), + (7911, 1), + (7912, 1), + (7933, 6), + (7935, 2), + (7936, 5), + (7937, 3), + (7938, 2), + (7939, 1), + (7940, 2), + (7941, 1), + (7942, 2), + (7943, 1), + (7944, 4), + (7945, 3), + (7946, 6), + (7948, 1), + (7949, 1), + (7960, 6), + (7967, 2), + (7971, 1), + (7973, 5), + (7974, 2), + (7975, 4), + (7976, 2), + (7978, 2), + (7979, 1), + (7980, 3), + (7981, 1), + (7982, 5), + (7983, 3), + (7985, 1), + (7986, 1), + (7987, 6), + (8002, 8), + (8010, 1), + (8011, 2), + (8012, 1), + (8013, 3), + (8014, 2), + (8015, 1), + (8016, 1), + (8017, 3), + (8018, 2), + (8019, 1), + (8021, 2), + (8022, 3), + (8023, 3), + (8028, 2), + (8051, 5), + (8053, 2), + (8054, 4), + (8055, 1), + (8056, 1), + (8057, 3), + (8058, 1), + (8059, 8), + (8060, 5), + (8061, 4), + (8062, 5), + (8063, 2), + (8064, 2), + (8065, 2), + (8066, 2), + (8067, 1), + (8079, 1), + (8090, 2), + (8092, 4), + (8093, 2), + (8094, 1), + (8095, 1), + (8096, 2), + (8099, 2), + (8100, 4), + (8101, 4), + (8102, 2), + (8105, 2), + (8107, 1), + (8128, 1), + (8129, 2), + (8130, 11), + (8131, 2), + (8133, 4), + (8134, 1), + (8136, 3), + (8137, 3), + (8138, 4), + (8139, 3), + (8140, 3), + (8141, 2), + (8142, 1), + (8144, 1), + (8145, 1), + (8166, 1), + (8167, 2), + (8169, 3), + (8171, 3), + (8172, 1), + (8174, 2), + (8175, 2), + (8176, 1), + (8177, 1), + (8178, 3), + (8179, 1), + (8180, 2), + (8182, 1), + (8183, 1), + (8207, 2), + (8208, 4), + (8209, 2), + (8210, 3), + (8211, 1), + (8212, 1), + (8213, 2), + (8214, 4), + (8215, 2), + (8216, 3), + (8217, 4), + (8218, 4), + (8219, 1), + (8221, 1), + (8240, 6), + (8244, 1), + (8246, 2), + (8247, 4), + (8248, 3), + (8249, 3), + (8250, 2), + (8251, 1), + (8254, 3), + (8255, 2), + (8256, 4), + (8257, 5), + (8258, 2), + (8259, 1), + (8260, 1), + (8284, 1), + (8285, 4), + (8286, 4), + (8287, 2), + (8288, 3), + (8289, 2), + (8290, 2), + (8291, 5), + (8292, 1), + (8293, 2), + (8295, 3), + (8296, 2), + (8297, 1), + (8299, 1), + (8302, 1), + (8314, 1), + (8319, 1), + (8322, 1), + (8324, 3), + (8325, 4), + (8326, 3), + (8327, 2), + (8328, 1), + (8329, 1), + (8330, 2), + (8331, 3), + (8333, 3), + (8334, 4), + (8335, 3), + (8336, 3), + (8340, 1), + (8342, 6), + (8360, 1), + (8362, 1), + (8364, 8), + (8365, 1), + (8366, 1), + (8367, 1), + (8368, 1), + (8369, 3), + (8371, 3), + (8372, 2), + (8373, 2), + (8374, 4), + (8375, 5), + (8376, 2), + (8378, 1), + (8379, 1), + (8401, 3), + (8404, 2), + (8405, 1), + (8406, 1), + (8407, 1), + (8408, 2), + (8409, 1), + (8410, 4), + (8411, 4), + (8412, 4), + (8413, 1), + (8414, 3), + (8416, 1), + (8417, 1), + (8439, 2), + (8442, 4), + (8443, 2), + (8445, 1), + (8446, 3), + (8447, 2), + (8448, 1), + (8449, 2), + (8450, 3), + (8451, 7), + (8452, 2), + (8453, 2), + (8455, 2), + (8456, 3), + (8458, 1), + (8465, 1), + (8475, 1), + (8479, 2), + (8480, 2), + (8481, 3), + (8482, 9), + (8483, 5), + (8484, 4), + (8485, 3), + (8486, 1), + (8487, 3), + (8488, 4), + (8489, 1), + (8490, 2), + (8491, 2), + (8492, 2), + (8494, 1), + (8495, 1), + (8519, 1), + (8520, 1), + (8521, 6), + (8522, 5), + (8523, 1), + (8524, 2), + (8525, 1), + (8526, 4), + (8527, 2), + (8528, 1), + (8529, 1), + (8530, 4), + (8531, 2), + (8532, 3), + (8535, 1), + (8557, 1), + (8558, 1), + (8559, 1), + (8560, 1), + (8564, 2), + (8565, 1), + (8566, 3), + (8567, 2), + (8569, 3), + (8570, 3), + (8571, 3), + (8572, 2), + (8573, 1), + (8575, 1), + (8576, 6), + (8583, 1), + (8587, 4), + (8595, 1), + (8599, 4), + (8600, 5), + (8601, 1), + (8602, 2), + (8603, 2), + (8604, 3), + (8605, 1), + (8606, 1), + (8607, 1), + (8608, 4), + (8609, 2), + (8610, 2), + (8611, 2), + (8613, 1), + (8633, 1), + (8634, 6), + (8636, 2), + (8637, 1), + (8638, 1), + (8639, 2), + (8640, 1), + (8643, 1), + (8645, 1), + (8646, 3), + (8647, 1), + (8649, 3), + (8650, 4), + (8651, 1), + (8653, 5), + (8675, 2), + (8676, 2), + (8677, 2), + (8678, 4), + (8679, 3), + (8681, 1), + (8682, 4), + (8683, 2), + (8684, 2), + (8685, 2), + (8686, 1), + (8687, 2), + (8688, 5), + (8689, 2), + (8701, 6), + (8705, 6), + (8710, 1), + (8714, 3), + (8716, 1), + (8718, 2), + (8719, 1), + (8720, 1), + (8721, 2), + (8722, 1), + (8723, 2), + (8724, 3), + (8725, 2), + (8727, 2), + (8728, 2), + (8751, 1), + (8752, 1), + (8754, 2), + (8755, 3), + (8756, 1), + (8757, 1), + (8759, 6), + (8761, 2), + (8762, 1), + (8763, 1), + (8764, 4), + (8766, 1), + (8767, 1), + (8768, 2), + (8791, 1), + (8793, 3), + (8794, 2), + (8796, 1), + (8797, 1), + (8798, 2), + (8799, 1), + (8800, 6), + (8801, 4), + (8802, 1), + (8803, 2), + (8804, 2), + (8805, 3), + (8806, 1), + (8816, 1), + (8832, 3), + (8834, 1), + (8835, 3), + (8836, 1), + (8837, 1), + (8838, 1), + (8839, 2), + (8840, 1), + (8841, 3), + (8842, 3), + (8843, 2), + (8844, 2), + (8845, 1), + (8847, 2), + (8870, 3), + (8871, 1), + (8872, 6), + (8873, 3), + (8874, 1), + (8875, 2), + (8876, 4), + (8878, 1), + (8879, 4), + (8880, 4), + (8881, 1), + (8882, 1), + (8883, 4), + (8884, 4), + (8885, 2), + (8887, 6), + (8910, 1), + (8912, 3), + (8913, 1), + (8915, 1), + (8916, 1), + (8917, 2), + (8919, 1), + (8920, 2), + (8921, 4), + (8922, 3), + (8923, 1), + (8944, 1), + (8949, 2), + (8950, 8), + (8953, 3), + (8957, 7), + (8958, 1), + (8959, 2), + (8960, 1), + (8961, 1), + (8963, 1), + (8964, 1), + (8986, 1), + (8987, 1), + (8988, 1), + (8989, 4), + (8991, 2), + (8993, 3), + (8995, 2), + (8996, 4), + (8998, 2), + (8999, 1), + (9000, 2), + (9001, 1), + (9003, 1), + (9004, 5), + (9007, 5), + (9026, 1), + (9028, 2), + (9029, 1), + (9031, 1), + (9033, 3), + (9034, 2), + (9035, 1), + (9036, 4), + (9038, 1), + (9040, 3), + (9041, 2), + (9064, 1), + (9065, 2), + (9066, 2), + (9067, 4), + (9070, 1), + (9071, 1), + (9073, 1), + (9075, 2), + (9076, 3), + (9077, 4), + (9078, 3), + (9079, 2), + (9080, 2), + (9087, 1), + (9103, 1), + (9106, 2), + (9107, 3), + (9108, 1), + (9109, 1), + (9110, 1), + (9111, 1), + (9112, 2), + (9113, 1), + (9114, 5), + (9115, 4), + (9116, 1), + (9117, 5), + (9118, 1), + (9119, 4), + (9120, 1), + (9142, 1), + (9143, 1), + (9144, 1), + (9145, 1), + (9146, 1), + (9147, 1), + (9148, 1), + (9149, 1), + (9150, 2), + (9152, 3), + (9153, 6), + (9154, 3), + (9155, 5), + (9156, 1), + (9159, 1), + (9182, 1), + (9184, 7), + (9186, 2), + (9187, 1), + (9189, 1), + (9191, 2), + (9192, 2), + (9193, 1), + (9194, 1), + (9204, 6), + (9219, 1), + (9222, 4), + (9223, 1), + (9224, 1), + (9227, 3), + (9229, 2), + (9230, 3), + (9231, 1), + (9232, 2), + (9233, 3), + (9234, 1), + (9235, 1), + (9236, 1), + (9260, 2), + (9261, 1), + (9262, 3), + (9263, 1), + (9264, 1), + (9265, 1), + (9266, 1), + (9269, 3), + (9270, 2), + (9271, 4), + (9272, 2), + (9274, 2), + (9276, 1), + (9299, 1), + (9301, 3), + (9302, 1), + (9306, 1), + (9307, 1), + (9308, 1), + (9310, 2), + (9311, 1), + (9313, 1), + (9314, 1), + (9334, 3), + (9339, 1), + (9340, 2), + (9341, 1), + (9342, 1), + (9344, 2), + (9346, 1), + (9347, 1), + (9348, 4), + (9349, 2), + (9351, 3), + (9352, 2), + (9377, 4), + (9378, 1), + (9379, 2), + (9380, 2), + (9384, 1), + (9386, 3), + (9387, 6), + (9388, 2), + (9389, 8), + (9392, 2), + (9414, 1), + (9415, 1), + (9416, 1), + (9417, 1), + (9418, 3), + (9424, 1), + (9425, 1), + (9426, 3), + (9427, 1), + (9429, 1), + (9430, 3), + (9456, 1), + (9457, 2), + (9458, 4), + (9459, 1), + (9460, 2), + (9461, 3), + (9463, 1), + (9464, 1), + (9466, 2), + (9469, 7), + (9470, 1), + (9471, 1), + (9494, 1), + (9495, 1), + (9496, 3), + (9497, 3), + (9498, 2), + (9500, 1), + (9501, 1), + (9503, 1), + (9504, 2), + (9505, 3), + (9506, 6), + (9508, 2), + (9509, 1), + (9510, 1), + (9531, 1), + (9533, 1), + (9534, 5), + (9535, 2), + (9537, 2), + (9538, 1), + (9539, 2), + (9540, 3), + (9542, 3), + (9543, 2), + (9544, 3), + (9546, 1), + (9547, 2), + (9562, 6), + (9569, 1), + (9573, 1), + (9574, 1), + (9579, 1), + (9581, 1), + (9582, 2), + (9583, 3), + (9584, 1), + (9585, 3), + (9586, 3), + (9588, 1), + (9608, 1), + (9610, 2), + (9613, 1), + (9614, 2), + (9615, 1), + (9618, 2), + (9619, 1), + (9620, 1), + (9621, 3), + (9622, 1), + (9623, 3), + (9625, 4), + (9649, 1), + (9651, 2), + (9652, 1), + (9653, 2), + (9654, 1), + (9656, 2), + (9657, 1), + (9658, 1), + (9659, 2), + (9661, 2), + (9662, 1), + (9663, 2), + (9664, 2), + (9665, 2), + (9689, 1), + (9690, 1), + (9691, 1), + (9694, 1), + (9695, 3), + (9696, 2), + (9697, 2), + (9698, 4), + (9699, 2), + (9700, 1), + (9701, 5), + (9702, 2), + (9703, 3), + (9704, 1), + (9705, 1), + (9730, 1), + (9731, 1), + (9733, 3), + (9735, 1), + (9736, 1), + (9738, 1), + (9739, 1), + (9740, 1), + (9741, 1), + (9742, 2), + (9766, 1), + (9768, 1), + (9770, 2), + (9771, 1), + (9773, 1), + (9777, 2), + (9778, 2), + (9779, 5), + (9780, 3), + (9782, 1), + (9783, 1), + (9807, 2), + (9809, 1), + (9810, 2), + (9811, 1), + (9813, 2), + (9815, 3), + (9816, 1), + (9818, 2), + (9819, 2), + (9820, 1), + (9824, 1), + (9840, 3), + (9845, 2), + (9846, 2), + (9847, 1), + (9848, 2), + (9849, 8), + (9850, 1), + (9851, 1), + (9852, 2), + (9853, 1), + (9854, 1), + (9855, 1), + (9858, 2), + (9884, 1), + (9885, 1), + (9887, 3), + (9892, 2), + (9895, 5), + (9896, 1), + (9897, 3), + (9898, 2), + (9899, 1), + (9923, 1), + (9925, 1), + (9927, 1), + (9928, 3), + (9932, 1), + (9933, 1), + (9935, 2), + (9937, 1), + (9938, 1), + (9961, 1), + (9963, 1), + (9964, 2), + (9965, 3), + (9969, 2), + (9970, 3), + (9973, 1), + (9974, 7), + (9975, 2), + (9976, 3), + (9979, 1), + (9981, 1), + (9996, 1), + (10000, 1), + (10001, 2), + (10002, 2), + (10003, 2), + (10004, 2), + (10005, 1), + (10007, 1), + (10011, 4), + (10012, 1), + (10013, 1), + (10014, 1), + (10015, 1), + (10016, 1), + (10017, 1), + (10041, 2), + (10042, 3), + (10044, 1), + (10048, 1), + (10049, 1), + (10050, 2), + (10051, 1), + (10052, 2), + (10053, 2), + (10054, 2), + (10055, 1), + (10080, 1), + (10081, 1), + (10083, 1), + (10085, 1), + (10086, 1), + (10088, 1), + (10089, 1), + (10091, 1), + (10093, 1), + (10094, 1), + (10096, 6), + (10117, 6), + (10120, 1), + (10121, 2), + (10123, 4), + (10126, 2), + (10127, 1), + (10128, 1), + (10129, 1), + (10131, 2), + (10139, 6), + (10156, 1), + (10157, 1), + (10158, 2), + (10159, 2), + (10160, 1), + (10161, 1), + (10165, 1), + (10166, 2), + (10167, 2), + (10170, 1), + (10171, 1), + (10195, 2), + (10198, 1), + (10202, 1), + (10205, 2), + (10206, 2), + (10208, 1), + (10209, 1), + (10211, 1), + (10235, 1), + (10236, 2), + (10238, 1), + (10239, 2), + (10242, 1), + (10245, 3), + (10247, 1), + (10251, 1), + (10259, 1), + (10280, 1), + (10282, 1), + (10283, 1), + (10285, 1), + (10286, 1), + (10287, 1), + (10289, 3), + (10314, 2), + (10315, 2), + (10316, 1), + (10317, 1), + (10318, 1), + (10320, 1), + (10321, 1), + (10322, 2), + (10323, 2), + (10324, 1), + (10327, 2), + (10358, 1), + (10359, 1), + (10360, 1), + (10361, 1), + (10362, 3), + (10363, 1), + (10364, 1), + (10365, 2), + (10367, 1), + (10391, 1), + (10392, 2), + (10394, 3), + (10396, 2), + (10397, 1), + (10400, 2), + (10401, 1), + (10404, 1), + (10405, 1), + (10416, 6), + (10429, 1), + (10432, 2), + (10434, 1), + (10435, 2), + (10438, 3), + (10439, 2), + (10441, 1), + (10442, 2), + (10443, 1), + (10468, 1), + (10471, 1), + (10473, 1), + (10476, 2), + (10477, 3), + (10478, 1), + (10480, 3), + (10481, 3), + (10482, 1), + (10483, 2), + (10485, 1), + (10487, 1), + (10488, 1), + (10510, 1), + (10511, 1), + (10512, 3), + (10516, 2), + (10519, 1), + (10520, 2), + (10548, 1), + (10549, 1), + (10550, 4), + (10552, 1), + (10553, 2), + (10555, 2), + (10556, 1), + (10557, 2), + (10559, 3), + (10561, 2), + (10587, 2), + (10589, 1), + (10590, 1), + (10592, 1), + (10593, 2), + (10594, 2), + (10595, 3), + (10596, 1), + (10597, 1), + (10598, 1), + (10600, 1), + (10601, 2), + (10604, 1), + (10622, 1), + (10624, 2), + (10626, 3), + (10627, 2), + (10629, 7), + (10631, 1), + (10633, 2), + (10636, 3), + (10637, 1), + (10638, 1), + (10662, 11), + (10664, 2), + (10665, 1), + (10667, 1), + (10668, 1), + (10671, 1), + (10673, 1), + (10675, 1), + (10678, 1), + (10680, 1), + (10698, 72), + (10703, 1), + (10705, 2), + (10707, 5), + (10708, 1), + (10710, 1), + (10711, 2), + (10712, 1), + (10713, 3), + (10714, 2), + (10742, 1), + (10752, 3), + (10753, 4), + (10754, 3), + (10756, 1), + (10781, 1), + (10785, 1), + (10786, 1), + (10788, 1), + (10790, 2), + (10791, 8), + (10792, 3), + (10794, 2), + (10795, 2), + (10820, 1), + (10826, 1), + (10830, 1), + (10831, 1), + (10832, 1), + (10833, 3), + (10834, 1), + (10861, 1), + (10865, 1), + (10867, 2), + (10868, 1), + (10869, 4), + (10872, 2), + (10873, 2), + (10902, 1), + (10904, 3), + (10906, 1), + (10907, 3), + (10911, 1), + (10915, 2), + (10931, 5), + (10933, 1), + (10938, 1), + (10939, 2), + (10941, 1), + (10942, 1), + (10945, 1), + (10946, 1), + (10947, 2), + (10948, 1), + (10949, 2), + (10950, 5), + (10951, 1), + (10978, 1), + (10979, 1), + (10981, 1), + (10985, 2), + (10986, 1), + (10987, 2), + (11012, 1), + (11014, 1), + (11018, 1), + (11019, 1), + (11020, 4), + (11021, 1), + (11022, 1), + (11025, 1), + (11026, 1), + (11027, 1), + (11028, 2), + (11029, 2), + (11059, 2), + (11060, 3), + (11061, 1), + (11062, 1), + (11063, 2), + (11064, 1), + (11066, 1), + (11067, 2), + (11068, 1), + (11084, 1), + (11098, 1), + (11099, 3), + (11100, 1), + (11101, 1), + (11102, 2), + (11105, 1), + (11106, 1), + (11107, 1), + (11132, 1), + (11133, 1), + (11135, 1), + (11136, 2), + (11139, 1), + (11140, 1), + (11141, 1), + (11144, 4), + (11145, 2), + (11172, 1), + (11174, 1), + (11175, 2), + (11176, 2), + (11177, 2), + (11178, 1), + (11180, 3), + (11181, 5), + (11182, 1), + (11183, 1), + (11184, 3), + (11209, 1), + (11216, 1), + (11217, 1), + (11218, 2), + (11219, 1), + (11220, 1), + (11222, 1), + (11225, 1), + (11230, 1), + (11231, 1), + (11249, 1), + (11250, 1), + (11254, 6), + (11255, 3), + (11258, 1), + (11259, 2), + (11260, 4), + (11261, 3), + (11262, 1), + (11292, 1), + (11293, 1), + (11294, 2), + (11297, 3), + (11298, 1), + (11301, 1), + (11328, 5), + (11331, 1), + (11332, 1), + (11334, 3), + (11336, 1), + (11337, 3), + (11338, 2), + (11339, 1), + (11340, 2), + (11341, 1), + (11342, 1), + (11366, 2), + (11367, 1), + (11369, 2), + (11372, 1), + (11373, 1), + (11375, 2), + (11377, 1), + (11379, 1), + (11380, 1), + (11406, 1), + (11410, 1), + (11412, 1), + (11413, 2), + (11414, 1), + (11417, 1), + (11418, 2), + (11422, 1), + (11444, 1), + (11445, 1), + (11447, 1), + (11448, 1), + (11450, 1), + (11454, 1), + (11456, 1), + (11457, 1), + (11459, 1), + (11481, 6), + (11487, 1), + (11490, 1), + (11492, 3), + (11493, 2), + (11494, 2), + (11495, 1), + (11497, 1), + (11524, 1), + (11525, 2), + (11530, 2), + (11533, 2), + (11536, 1), + (11561, 1), + (11565, 1), + (11569, 1), + (11572, 3), + (11574, 1), + (11575, 3), + (11599, 1), + (11601, 2), + (11606, 1), + (11607, 1), + (11609, 1), + (11611, 2), + (11614, 1), + (11615, 2), + (11631, 1), + (11637, 1), + (11639, 1), + (11640, 2), + (11642, 2), + (11645, 1), + (11647, 2), + (11648, 2), + (11649, 1), + (11651, 2), + (11652, 2), + (11653, 1), + (11655, 1), + (11681, 1), + (11682, 5), + (11685, 1), + (11686, 1), + (11687, 1), + (11688, 2), + (11690, 1), + (11720, 3), + (11721, 6), + (11723, 1), + (11724, 1), + (11725, 1), + (11726, 2), + (11729, 2), + (11730, 2), + (11731, 1), + (11732, 1), + (11750, 6), + (11755, 3), + (11757, 1), + (11761, 2), + (11762, 1), + (11764, 1), + (11766, 3), + (11767, 1), + (11803, 2), + (11804, 1), + (11806, 2), + (11807, 2), + (11808, 1), + (11833, 1), + (11836, 1), + (11838, 1), + (11841, 2), + (11842, 4), + (11845, 3), + (11848, 2), + (11849, 1), + (11870, 1), + (11875, 2), + (11876, 1), + (11877, 1), + (11878, 2), + (11879, 1), + (11881, 2), + (11882, 2), + (11883, 7), + (11884, 1), + (11885, 3), + (11886, 2), + (11887, 2), + (11912, 1), + (11914, 1), + (11916, 1), + (11917, 1), + (11924, 1), + (11925, 1), + (11950, 1), + (11951, 1), + (11953, 1), + (11959, 2), + (11960, 3), + (11961, 1), + (11963, 1), + (11964, 1), + (11966, 1), + (11990, 1), + (11993, 1), + (11997, 1), + (11998, 2), + (11999, 2), + (12000, 1), + (12001, 1), + (12033, 1), + (12037, 2), + (12038, 2), + (12039, 2), + (12040, 1), + (12041, 2), + (12043, 3), + (12044, 1), + (12068, 1), + (12072, 3), + (12074, 2), + (12075, 1), + (12076, 1), + (12077, 4), + (12078, 4), + (12079, 6), + (12080, 2), + (12108, 2), + (12114, 1), + (12115, 2), + (12116, 3), + (12117, 1), + (12118, 2), + (12119, 1), + (12120, 2), + (12148, 1), + (12149, 1), + (12152, 1), + (12153, 2), + (12154, 1), + (12155, 1), + (12156, 1), + (12157, 2), + (12158, 2), + (12159, 1), + (12191, 1), + (12193, 1), + (12194, 1), + (12195, 2), + (12196, 1), + (12197, 3), + (12198, 1), + (12199, 2), + (12200, 1), + (12225, 1), + (12230, 1), + (12233, 1), + (12234, 3), + (12235, 3), + (12236, 1), + (12237, 4), + (12264, 1), + (12269, 1), + (12270, 1), + (12271, 3), + (12272, 2), + (12273, 1), + (12274, 2), + (12276, 1), + (12277, 4), + (12278, 1), + (12303, 1), + (12304, 1), + (12305, 2), + (12307, 2), + (12308, 1), + (12309, 4), + (12310, 2), + (12312, 1), + (12313, 1), + (12314, 3), + (12315, 1), + (12317, 1), + (12344, 1), + (12350, 6), + (12351, 2), + (12352, 3), + (12353, 2), + (12354, 1), + (12385, 1), + (12387, 1), + (12388, 1), + (12389, 1), + (12390, 1), + (12391, 1), + (12392, 1), + (12421, 3), + (12425, 1), + (12427, 2), + (12428, 1), + (12429, 1), + (12430, 2), + (12431, 2), + (12432, 3), + (12462, 1), + (12464, 1), + (12466, 1), + (12468, 3), + (12469, 2), + (12470, 4), + (12471, 3), + (12472, 1), + (12498, 5), + (12503, 2), + (12505, 1), + (12507, 1), + (12508, 3), + (12509, 1), + (12510, 1), + (12511, 1), + (12539, 1), + (12540, 2), + (12542, 2), + (12543, 1), + (12544, 2), + (12546, 1), + (12547, 2), + (12548, 3), + (12549, 1), + (12550, 1), + (12577, 1), + (12578, 1), + (12581, 1), + (12582, 2), + (12584, 1), + (12585, 2), + (12586, 1), + (12587, 1), + (12620, 1), + (12621, 1), + (12625, 2), + (12626, 1), + (12627, 2), + (12628, 2), + (12629, 1), + (12630, 1), + (12653, 1), + (12656, 1), + (12657, 3), + (12658, 2), + (12659, 1), + (12661, 3), + (12662, 2), + (12663, 2), + (12664, 1), + (12666, 1), + (12668, 1), + (12682, 1), + (12694, 1), + (12696, 2), + (12698, 1), + (12699, 1), + (12702, 1), + (12703, 2), + (12704, 1), + (12705, 1), + (12706, 2), + (12732, 1), + (12741, 1), + (12742, 4), + (12743, 1), + (12744, 1), + (12773, 1), + (12774, 1), + (12778, 2), + (12780, 3), + (12781, 1), + (12782, 1), + (12785, 1), + (12813, 1), + (12816, 1), + (12817, 1), + (12819, 3), + (12821, 2), + (12823, 2), + (12824, 2), + (12825, 1), + (12854, 1), + (12856, 2), + (12857, 1), + (12858, 1), + (12859, 5), + (12860, 2), + (12861, 1), + (12890, 1), + (12894, 3), + (12897, 3), + (12899, 1), + (12900, 1), + (12901, 1), + (12903, 1), + (12927, 1), + (12928, 2), + (12933, 1), + (12934, 2), + (12935, 1), + (12936, 1), + (12938, 2), + (12939, 1), + (12941, 1), + (12964, 1), + (12966, 1), + (12972, 1), + (12973, 1), + (12974, 1), + (12975, 2), + (12976, 2), + (12977, 1), + (12979, 1), + (12980, 1), + (12982, 1), + (13006, 1), + (13013, 3), + (13014, 2), + (13016, 1), + (13020, 1), + (13050, 2), + (13052, 1), + (13053, 1), + (13054, 1), + (13055, 3), + (13058, 1), + (13085, 1), + (13088, 1), + (13090, 2), + (13091, 1), + (13094, 2), + (13095, 1), + (13096, 1), + (13123, 1), + (13124, 1), + (13128, 1), + (13130, 1), + (13131, 1), + (13132, 2), + (13133, 1), + (13134, 1), + (13136, 1), + (13162, 1), + (13168, 3), + (13169, 1), + (13171, 2), + (13172, 2), + (13206, 1), + (13207, 2), + (13209, 2), + (13212, 1), + (13239, 1), + (13240, 1), + (13243, 1), + (13245, 1), + (13246, 1), + (13248, 2), + (13250, 1), + (13251, 1), + (13277, 1), + (13282, 5), + (13284, 1), + (13285, 1), + (13286, 1), + (13287, 3), + (13288, 2), + (13291, 1), + (13321, 1), + (13324, 2), + (13325, 1), + (13326, 3), + (13328, 1), + (13354, 2), + (13356, 5), + (13357, 1), + (13359, 1), + (13360, 1), + (13363, 1), + (13364, 2), + (13366, 1), + (13368, 3), + (13369, 1), + (13370, 1), + (13397, 1), + (13399, 1), + (13401, 3), + (13403, 1), + (13404, 1), + (13406, 2), + (13408, 1), + (13409, 1), + (13410, 1), + (13411, 2), + (13434, 1), + (13436, 2), + (13439, 2), + (13440, 1), + (13441, 1), + (13442, 2), + (13443, 1), + (13445, 1), + (13447, 1), + (13474, 1), + (13475, 1), + (13479, 3), + (13481, 1), + (13482, 3), + (13484, 1), + (13486, 1), + (13487, 1), + (13514, 1), + (13517, 1), + (13520, 2), + (13521, 1), + (13522, 1), + (13523, 1), + (13524, 1), + (13525, 1), + (13550, 2), + (13555, 1), + (13556, 1), + (13557, 2), + (13559, 2), + (13560, 2), + (13562, 1), + (13591, 1), + (13596, 1), + (13597, 1), + (13598, 1), + (13601, 2), + (13631, 1), + (13633, 1), + (13638, 2), + (13642, 1), + (13677, 1), + (13712, 1), + (13713, 1), + (13714, 1), + (13716, 1), + (13717, 1), + (13721, 1), + (13752, 2), + (13753, 1), + (13755, 1), + (13757, 1), + (13758, 1), + (13761, 1), + (13787, 1), + (13790, 1), + (13792, 1), + (13794, 1), + (13799, 1), + (13823, 1), + (13825, 2), + (13831, 1), + (13832, 3), + (13837, 1), + (13868, 1), + (13872, 2), + (13874, 2), + (13876, 2), + (13877, 1), + (13879, 1), + (13906, 1), + (13911, 2), + (13912, 1), + (13913, 1), + (13914, 2), + (13917, 1), + (13946, 1), + (13947, 3), + (13950, 1), + (13953, 2), + (13956, 1), + (13985, 1), + (13987, 3), + (13989, 3), + (13992, 1), + (13993, 1), + (13996, 1), + (14018, 6), + (14024, 1), + (14025, 1), + (14027, 2), + (14029, 2), + (14031, 1), + (14033, 2), + (14034, 1), + (14056, 1), + (14058, 1), + (14063, 5), + (14064, 2), + (14066, 1), + (14067, 1), + (14102, 5), + (14104, 2), + (14106, 1), + (14107, 2), + (14110, 1), + (14111, 1), + (14143, 1), + (14144, 1), + (14148, 1), + (14180, 2), + (14181, 1), + (14183, 1), + (14185, 2), + (14213, 1), + (14216, 1), + (14218, 1), + (14221, 1), + (14222, 1), + (14223, 1), + (14257, 1), + (14264, 2), + (14266, 1), + (14297, 3), + (14298, 1), + (14304, 1), + (14336, 1), + (14337, 1), + (14339, 1), + (14340, 1), + (14341, 2), + (14342, 1), + (14373, 5), + (14376, 1), + (14379, 1), + (14381, 1), + (14414, 2), + (14416, 1), + (14417, 1), + (14418, 1), + (14419, 1), + (14420, 1), + (14447, 1), + (14448, 5), + (14449, 1), + (14453, 2), + (14455, 1), + (14456, 1), + (14458, 2), + (14459, 2), + (14488, 1), + (14492, 1), + (14493, 1), + (14495, 1), + (14496, 2), + (14497, 2), + (14498, 1), + (14500, 1), + (14530, 2), + (14532, 2), + (14534, 1), + (14535, 1), + (14537, 1), + (14538, 2), + (14541, 1), + (14568, 1), + (14571, 1), + (14572, 1), + (14573, 1), + (14574, 2), + (14605, 1), + (14608, 1), + (14609, 1), + (14610, 1), + (14611, 1), + (14615, 1), + (14616, 2), + (14646, 1), + (14648, 2), + (14649, 1), + (14650, 1), + (14653, 1), + (14655, 2), + (14656, 1), + (14685, 1), + (14688, 2), + (14691, 4), + (14692, 1), + (14725, 1), + (14727, 1), + (14728, 1), + (14769, 2), + (14770, 2), + (14804, 1), + (14806, 1), + (14808, 1), + (14810, 2), + (14846, 1), + (14848, 2), + (14849, 1), + (14854, 1), + (14877, 1), + (14879, 1), + (14882, 1), + (14885, 1), + (14886, 2), + (14887, 1), + (14889, 1), + (14915, 1), + (14917, 1), + (14918, 1), + (14921, 1), + (14924, 1), + (14925, 1), + (14956, 1), + (14958, 2), + (14960, 2), + (14962, 1), + (14963, 1), + (14964, 1), + (14965, 1), + (14967, 1), + (14968, 1), + (15000, 2), + (15001, 1), + (15002, 2), + (15033, 1), + (15035, 1), + (15036, 2), + (15038, 1), + (15039, 1), + (15043, 1), + (15045, 1), + (15074, 2), + (15075, 1), + (15080, 1), + (15083, 1), + (15086, 1), + (15087, 1), + (15114, 1), + (15118, 1), + (15119, 1), + (15121, 1), + (15155, 1), + (15158, 1), + (15160, 1), + (15161, 1), + (15197, 1), + (15200, 2), + (15231, 1), + (15233, 1), + (15235, 1), + (15237, 1), + (15238, 1), + (15239, 1), + (15242, 1), + (15268, 1), + (15270, 1), + (15272, 1), + (15274, 1), + (15275, 2), + (15279, 2), + (15309, 1), + (15312, 1), + (15313, 2), + (15314, 1), + (15346, 1), + (15348, 1), + (15349, 1), + (15350, 2), + (15353, 3), + (15354, 2), + (15355, 2), + (15384, 1), + (15392, 2), + (15393, 1), + (15428, 1), + (15430, 1), + (15431, 2), + (15432, 1), + (15469, 1), + (15474, 1), + (15503, 1), + (15508, 2), + (15509, 2), + (15510, 1), + (15545, 1), + (15549, 1), + (15550, 1), + (15552, 1), + (15580, 1), + (15582, 1), + (15588, 2), + (15594, 1), + (15621, 1), + (15623, 1), + (15624, 1), + (15659, 1), + (15665, 1), + (15669, 1), + (15697, 1), + (15699, 1), + (15701, 1), + (15705, 3), + (15736, 1), + (15737, 2), + (15738, 1), + (15740, 1), + (15744, 2), + (15777, 1), + (15778, 1), + (15780, 1), + (15782, 4), + (15783, 1), + (15818, 1), + (15819, 1), + (15820, 1), + (15821, 2), + (15823, 1), + (15825, 2), + (15827, 1), + (15855, 3), + (15860, 1), + (15863, 1), + (15865, 1), + (15891, 2), + (15893, 1), + (15896, 1), + (15897, 1), + (15901, 1), + (15930, 1), + (15941, 1), + (15972, 2), + (15974, 1), + (16009, 1), + (16011, 1), + (16018, 1), + (16052, 1), + (16053, 1), + (16094, 1), + (16096, 2), + (16098, 1), + (16100, 1), + (16130, 1), + (16134, 1), + (16136, 1), + (16138, 2), + (16166, 1), + (16167, 1), + (16172, 2), + (16173, 2), + (16245, 1), + (16249, 1), + (16288, 1), + (16296, 1), + (16322, 2), + (16330, 1), + (16364, 1), + (16369, 1), + (16370, 1), + (16371, 1), + (16398, 1), + (16399, 1), + (16400, 1), + (16403, 1), + (16437, 1), + (16440, 1), + (16444, 1), + (16447, 1), + (16483, 1), + (16485, 1), + (16486, 1), + (16491, 1), + (16518, 1), + (16521, 1), + (16523, 1), + (16525, 1), + (16526, 1), + (16559, 1), + (16597, 1), + (16600, 1), + (16601, 1), + (16604, 1), + (16634, 1), + (16636, 1), + (16639, 1), + (16670, 1), + (16678, 1), + (16680, 1), + (16711, 1), + (16714, 1), + (16718, 1), + (16721, 1), + (16752, 1), + (16754, 1), + (16757, 1), + (16758, 2), + (16759, 1), + (16761, 2), + (16791, 1), + (16794, 1), + (16797, 1), + (16798, 1), + (16802, 1), + (16833, 1), + (16835, 1), + (16836, 2), + (16838, 2), + (16839, 1), + (16874, 1), + (16911, 1), + (16914, 1), + (16949, 1), + (16952, 2), + (16953, 2), + (16956, 2), + (16985, 1), + (17030, 1), + (17031, 1), + (17033, 1), + (17061, 1), + (17065, 1), + (17066, 2), + (17069, 1), + (17071, 1), + (17073, 1), + (17104, 1), + (17106, 1), + (17108, 1), + (17110, 1), + (17143, 1), + (17144, 1), + (17147, 2), + (17148, 1), + (17187, 1), + (17190, 1), + (17221, 1), + (17224, 1), + (17227, 1), + (17262, 1), + (17263, 1), + (17265, 1), + (17278, 1), + (17303, 1), + (17304, 1), + (17307, 1), + (17334, 1), + (17340, 1), + (17341, 2), + (17379, 1), + (17415, 1), + (17419, 1), + (17458, 1), + (17461, 1), + (17463, 1), + (17495, 2), + (17496, 1), + (17499, 2), + (17500, 1), + (17535, 1), + (17536, 1), + (17538, 1), + (17540, 1), + (17572, 2), + (17580, 1), + (17610, 1), + (17613, 1), + (17614, 2), + (17615, 1), + (17682, 5), + (17727, 1), + (17769, 1), + (17776, 1), + (17809, 1), + (17810, 1), + (17811, 1), + (17812, 1), + (17846, 2), + (17850, 1), + (17853, 1), + (17884, 2), + (17922, 1), + (17925, 1), + (17931, 1), + (17963, 1), + (17968, 1), + (17972, 1), + (18002, 1), + (18010, 1), + (18030, 1), + (18040, 1), + (18078, 1), + (18080, 1), + (18083, 1), + (18086, 1), + (18118, 1), + (18120, 2), + (18124, 2), + (18159, 1), + (18162, 1), + (18164, 1), + (18198, 1), + (18201, 1), + (18203, 1), + (18234, 1), + (18236, 1), + (18238, 1), + (18239, 2), + (18241, 1), + (18243, 2), + (18279, 1), + (18318, 1), + (18354, 1), + (18355, 1), + (18356, 1), + (18357, 1), + (18358, 2), + (18392, 2), + (18394, 1), + (18396, 3), + (18398, 1), + (18429, 1), + (18436, 1), + (18470, 1), + (18475, 1), + (18508, 1), + (18514, 1), + (18545, 1), + (18554, 1), + (18591, 1), + (18592, 2), + (18626, 2), + (18630, 1), + (18664, 1), + (18668, 1), + (18743, 1), + (18746, 1), + (18747, 1), + (18748, 1), + (18783, 2), + (18790, 1), + (18818, 1), + (18825, 1), + (18826, 1), + (18859, 2), + (18860, 1), + (18861, 1), + (18863, 1), + (18864, 1), + (18866, 1), + (18904, 1), + (18939, 1), + (18940, 1), + (18976, 1), + (18980, 2), + (18981, 1), + (19015, 1), + (19019, 2), + (19054, 1), + (19058, 2), + (19061, 1), + (19095, 1), + (19099, 1), + (19131, 1), + (19133, 1), + (19139, 1), + (19171, 1), + (19177, 1), + (19178, 1), + (19201, 5), + (19209, 1), + (19215, 1), + (19216, 1), + (19253, 1), + (19280, 1), + (19292, 1), + (19296, 1), + (19328, 1), + (19329, 1), + (19330, 1), + (19331, 2), + (19332, 1), + (19337, 6), + (19371, 1), + (19408, 1), + (19410, 2), + (19444, 1), + (19450, 2), + (19486, 2), + (19487, 2), + (19528, 1), + (19560, 1), + (19564, 1), + (19603, 2), + (19606, 1), + (19643, 1), + (19644, 1), + (19679, 1), + (19680, 1), + (19681, 1), + (19682, 2), + (19683, 1), + (19684, 1), + (19718, 1), + (19722, 1), + (19755, 1), + (19758, 1), + (19759, 2), + (19837, 1), + (19838, 1), + (19877, 1), + (19878, 1), + (19914, 1), + (19916, 3), + (19954, 1), + (19989, 1), + (19991, 6), + (19992, 27), + (19993, 18), + (19994, 9), + (19995, 3), + (19996, 4), + (19997, 3), + (20024, 1), + (20029, 2), + (20031, 2), + (20033, 1), + (20068, 1), + (20069, 1), + (20187, 1), + (20188, 1), + (20228, 1), + (20303, 1), + (20304, 1), + (20342, 1), + (20344, 2), + (20347, 1), + (20381, 1), + (20423, 1), + (20424, 1), + (20457, 1), + (20461, 1), + (20542, 1), + (20543, 1), + (20577, 1), + (20578, 1), + (20618, 1), + (20656, 1), + (20657, 1), + (20658, 1), + (20693, 1), + (20733, 1), + (20773, 1), + (20813, 1), + (20850, 1), + (20851, 1), + (20883, 1), + (20888, 2), + (20890, 1), + (20929, 1), + (20967, 2), + (21044, 1), + (21045, 1), + (21128, 1), + (21162, 1), + (21280, 1), + (21318, 1), + (21358, 1), + (21359, 1), + (21395, 1), + (21434, 1), + (21435, 1), + (21473, 1), + (21514, 1), + (21551, 1), + (21552, 1), + (21629, 2), + (21668, 1), + (21708, 1), + (21712, 1), + (21747, 1), + (21983, 1), + (22020, 1), + (22097, 1), + (22529, 1), + (23381, 5), + (27166, 6), + (27623, 7), + (31645, 5), + (37476, 6), + (66530, 1), + (236741, 1), + (266960, 1), + (410116, 1), + (452279, 1), + (521150, 1), + (531415, 1), + (531469, 1), + (533889, 1), + (534391, 1), + (537072, 1), + (546820, 1), + (554056, 1), + (562513, 1), + (570304, 1), + (571882, 1), + (580008, 1), + (586561, 1), + (589436, 1), + (593061, 2), + (625907, 1), + (633533, 1), + (637743, 1), + (644603, 1), + (646180, 1), + (655481, 1), + (701633, 1), + (728784, 1), + (741162, 1), + (751759, 1), + (782221, 1), + (785912, 1), + (901532, 1), + (902834, 1), + (952321, 1), + (964030, 1), + (977740, 1), + (992978, 1), + (1024668, 1), + (1052088, 1), + (1094674, 1), + (1123764, 1), + (1145006, 1), + (1149240, 1), + (1162664, 1), + (1181063, 1), + (1237621, 1), + (1238079, 1), + (1304137, 1), + (1318405, 1), + (1338999, 1), + (1346855, 1), + (1379530, 1), + (1381203, 1), + (1430590, 1), + (1448224, 1), + (1455881, 1), + (1473348, 1), + (1482046, 1), + (1487730, 1), + (1492627, 1), + (1514540, 1), + (1534484, 1), + (1684302, 1), + (1910865, 1), +]; diff --git a/admin/src/multitree_bench/mod.rs b/admin/src/multitree_bench/mod.rs new file mode 100644 index 00000000..c7464110 --- /dev/null +++ b/admin/src/multitree_bench/mod.rs @@ -0,0 +1,1282 @@ +// Copyright 2021-2022 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or MIT. + +use super::*; + +mod data; + +pub use parity_db::{CompressionType, Db, Key, TreeReader, Value}; +use parity_db::{NewNode, NodeRef, Operation}; + +use parking_lot::{RwLock, RwLockReadGuard}; + +use rand::{RngCore, SeedableRng}; +use std::{ + collections::{BTreeMap, HashMap, HashSet}, + io::Write, + ops::Deref, + sync::{ + atomic::{AtomicBool, AtomicUsize, Ordering}, + Arc, + }, + thread, +}; + +static COMMITS: AtomicUsize = AtomicUsize::new(0); +static NEXT_COMMIT: AtomicUsize = AtomicUsize::new(0); +static NUM_REMOVED: AtomicUsize = AtomicUsize::new(0); +static TARGET_NUM_REMOVED: AtomicUsize = AtomicUsize::new(0); +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 THREAD_PRUNING: bool = true; +const FORCE_NO_MULTIPART_VALUES: bool = true; +const FIXED_TEXT_POSITION: bool = true; + +/// Stress tests (warning erase db first). +#[derive(Debug, clap::Parser)] +pub struct MultiTreeStress { + #[clap(flatten)] + pub shared: Shared, + + /// Number of reading threads [default: 0]. + #[clap(long)] + pub readers: Option, + + /// Number of iterating threads [default: 0]. + #[clap(long)] + pub iter: Option, + + /// Number of writing threads [default: 1]. + #[clap(long)] + pub writers: Option, + + /// Total number of inserted commits. + #[clap(long)] + pub commits: Option, + + /// Random seed used for key generation. + #[clap(long)] + pub seed: Option, + + /// Open an existing database. + #[clap(long)] + pub append: bool, + + /// Remove all trees on shutdown and wait for the database to be empty. + #[clap(long)] + pub empty_on_shutdown: bool, + + /// Number of trees to keep (Older are removed). 0 means never remove. [default: 8] + #[clap(long)] + pub pruning: Option, + + /// Enable compression. + #[clap(long)] + pub compress: bool, + + /// Time (in milliseconds) between commits. + #[clap(long)] + pub commit_time: Option, +} + +#[derive(Clone)] +pub struct Args { + pub readers: usize, + pub iter: usize, + pub writers: usize, + pub commits: usize, + pub seed: Option, + pub append: bool, + pub empty_on_shutdown: bool, + pub pruning: u64, + pub compress: bool, + pub commit_time: u64, +} + +impl MultiTreeStress { + pub(super) fn get_args(&self) -> Args { + Args { + readers: self.readers.unwrap_or(0), + iter: self.iter.unwrap_or(0), + writers: self.writers.unwrap_or(1), + commits: self.commits.unwrap_or(100_000), + seed: self.seed, + append: self.append, + empty_on_shutdown: self.empty_on_shutdown, + pruning: self.pruning.unwrap_or(8), + compress: self.compress, + commit_time: self.commit_time.unwrap_or(0), + } + } +} + +struct OutputHelper { + last_fixed: String, + stdout: std::io::Stdout, +} + +impl OutputHelper { + fn new() -> OutputHelper { + println!(""); + OutputHelper { last_fixed: "".to_string(), stdout: std::io::stdout() } + } + + fn println(&mut self, text: String) { + if FIXED_TEXT_POSITION { + let overwrite = format!("{:<1$}", text, self.last_fixed.len()); + println!("\r{}", overwrite); + print!("{}", self.last_fixed); + self.stdout.flush().unwrap(); + } else { + println!("{}", text); + } + } + + fn print_fixed(&mut self, text: String) { + if FIXED_TEXT_POSITION { + let overwrite = format!("{:<1$}", text, self.last_fixed.len()); + print!("\r{}", overwrite); + self.last_fixed = text; + self.stdout.flush().unwrap(); + } else { + println!(" {}", text); + } + } + + fn println_final(&mut self, text: String) { + if FIXED_TEXT_POSITION { + println!(""); + println!("{}", text); + self.stdout.flush().unwrap(); + } else { + println!("{}", text); + } + } +} + +struct Histogram { + distribution: BTreeMap, + total: u32, +} + +impl Histogram { + fn new(histogram_data: &[(u32, u32)]) -> Histogram { + let mut distribution = BTreeMap::default(); + let mut total = 0; + for (size, count) in histogram_data { + total += count; + if *count > 0 { + distribution.insert(total, *size); + } + } + Histogram { distribution, total } + } + + fn sample(&self, rnd: u64) -> u32 { + let sr = (rnd % self.total as u64) as u32; + let mut range = self + .distribution + .range((std::ops::Bound::Included(sr), std::ops::Bound::Unbounded)); + let size = *range.next().unwrap().1; + size + } +} + +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), +} + +struct ChainGenerator { + depth_child_count_histograms: Vec, + depth_age_histograms: 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)])], + 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 { + assert_eq!(*depth, depth_child_count_histograms.len() as u32); + + let data: Vec<(u32, u32)> = + histogram_data.iter().enumerate().map(|(a, b)| (a as u32, *b)).collect(); + let histogram = Histogram::new(data.as_slice()); + + 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 value_length_histogram = Histogram::new(value_length_histogram); + + ChainGenerator { + depth_child_count_histograms, + depth_age_histograms, + value_length_histogram, + seed, + compressable, + pruning, + } + } + + fn root_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); + let seed = hasher.finish(); + seed + } + + fn key(&self, seed: u64) -> Key { + let mut rng = rand::rngs::SmallRng::seed_from_u64(seed); + let mut key = Key::default(); + rng.fill_bytes(&mut key); + key + } + + fn num_node_children(&self, _tree_index: u64, depth: u32, seed: u64) -> u32 { + 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 + }; + + num_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( + &self, + tree_index: u64, + depth: u32, + seed: u64, + only_direct_children: bool, + ) -> (Vec, Vec) { + 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 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 + }; + + // Restrict to within the pruning window + let age = if self.pruning > 0 { std::cmp::min(age, self.pruning) } else { age }; + + let child_tree_index = if age > tree_index { 0 } else { tree_index - age }; + + 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()); + } 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 + } + + // 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 child_index = path_rng.next_u64() % num_direct_children as u64; + + 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); + + // 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); + + other_tree_index = *new_index; + other_depth = *new_depth; + other_seed = *new_seed; + + 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 + } + } + + 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(), + )); + }, + } + } + } + } + + if only_direct_children { + return (Vec::new(), children) + } + + // 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); + } + } + 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, children) + } + + 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()) + } + } + Ok((tree_index, depth, seed)) + } +} + +fn informant( + db: Arc, + shutdown: Arc, + shutdown_final: Arc, + output_helper: Arc>, +) -> Result<(), String> { + let mut num_expected_entries = 0; + let mut num_entries = 0; + while !shutdown_final.load(Ordering::Relaxed) { + if FIXED_TEXT_POSITION { + thread::sleep(std::time::Duration::from_millis(100)); + } else { + thread::sleep(std::time::Duration::from_secs(1)); + } + + 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 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 + )); + + if num_entries == 0 { + if shutdown.load(Ordering::Relaxed) { + shutdown_final.store(true, Ordering::SeqCst); + } + } + } + } + Ok(()) +} + +fn find_dependent_trees( + node_data: &(Vec, Vec), + 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); + }, + } + } + Ok(()) +} + +fn build_commit_tree<'s, 'd: 's>( + node_data: (Vec, Vec), + db: &Db, + chain_generator: &ChainGenerator, + tree_refs: &'s HashMap>, + tree_guards: &mut HashMap>, +) -> 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); + }, + 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()), + } + } + } + } + + 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); + }, + } + }, + } + } + let new_node = NewNode { data: node_data.0, children }; + Ok(NodeRef::New(new_node)) +} + +fn num_new_nodes(node: &NodeRef, num_existing: &mut u32) -> u32 { + match node { + NodeRef::New(node) => { + let mut num = 1; + for child in &node.children { + num += num_new_nodes(child, num_existing); + } + num + }, + NodeRef::Existing(_) => { + *num_existing += 1; + 0 + }, + } +} + +fn read_value( + tree_index: u64, + 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()); + + let mut generated_children = gen_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, + ); + match reader.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 => panic!("Child address not in database"), + } + } + + 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"); + } + } + }, + } + }, + 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 + ); + } + } + }, + } + + 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, + shutdown: Arc, + start_commit: usize, + output_helper: Arc>, +) -> Result<(), String> { + //let seed = args.seed.unwrap_or(0); + let mut commit = Vec::new(); + + loop { + let n = NEXT_COMMIT.fetch_add(1, Ordering::SeqCst); + if n >= start_commit + args.commits || shutdown.load(Ordering::Relaxed) { + break + } + + 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); + + // 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)?; + + 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. + }, + } + } + + /* for (key, tree_ref) in tree_refs.iter() { + tree_guards.insert(key.clone(), tree_ref.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); + + commit.push((TREE_COLUMN, Operation::InsertTree(key.to_vec(), node))); + + 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(); + + output_helper.write().println(format!( + "Commit tree {}, new: {}, existing: {}", + tree_index, num_new_nodes, num_existing_nodes + )); + + 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 mut rng = rand::rngs::SmallRng::seed_from_u64(seed + n as u64); + read_value(tree_index, &mut rng, &db, &args, &chain_generator)?; */ + + if args.pruning > 0 && !THREAD_PRUNING { + try_prune(&db, &args, &chain_generator, &mut commit, &output_helper)?; + } + + if args.commit_time > 0 { + thread::sleep(std::time::Duration::from_millis(args.commit_time)); + } + } + } + + Ok(()) +} + +fn try_prune( + db: &Db, + 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); + let commits = COMMITS.load(Ordering::Relaxed); + + let target_num_removed = if target_override > 0 { + target_override as u64 + } else { + if commits as u64 > args.pruning { + commits as u64 - args.pruning + } else { + 0 + } + }; + + if target_num_removed > num_removed as u64 { + // Need to remove a tree + let tree_index = num_removed as u64; + 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, + Operation::Set( + KEY_NUM_REMOVED.to_vec(), + ((num_removed + 1) as u64).to_be_bytes().to_vec(), + ), + )); + + NUM_REMOVED.fetch_add(1, Ordering::SeqCst); + db.commit_changes(commit.drain(..)).unwrap(); + commit.clear(); + } + + Ok(()) +} + +fn pruner( + db: Arc, + 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)?; + } + + Ok(()) +} + +fn reader( + db: Arc, + args: Arc, + chain_generator: Arc, + index: u64, + shutdown: Arc, +) -> Result<(), String> { + // Query random values from random trees while writing + let offset = args.seed.unwrap_or(0); + 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)?; + } + + Ok(()) +} + +fn iter_children<'a>( + depth: u32, + generated_children: &mut Vec, + database_children: &mut 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) + }, + }; + + let child_address = database_children[child_index as usize]; + + 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); + assert_eq!(gen_children.len(), db_children.len()); + + iter_children( + depth + 1, + &mut gen_children, + &mut db_children, + reader, + chain_generator, + )?; + }, + None => panic!("Child address not in database"), + } + } + + Ok(()) +} + +fn iter( + db: Arc, + args: Arc, + chain_generator: Arc, + index: u64, + shutdown: Arc, +) -> Result<(), String> { + // Iterate over nodes in random trees while writing + let offset = args.seed.unwrap_or(0); + 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 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 { + let num_removed = NUM_REMOVED.load(Ordering::Relaxed); + if tree_index >= num_removed as u64 { + panic!( + "Tree not in database during iterator (index: {}, removed: {})", + tree_index, num_removed + ); + } + } + }, + } + } + + Ok(()) +} + +pub fn run_internal(args: Args, db: Db) -> Result<(), String> { + let args = Arc::new(args); + let shutdown = Arc::new(AtomicBool::new(false)); + let shutdown_final = Arc::new(AtomicBool::new(false)); + let db = Arc::new(db); + let output_helper = Arc::new(RwLock::new(OutputHelper::new())); + + let mut threads = Vec::new(); + + let start_commit = if let Some(start) = db.get(INFO_COLUMN, &KEY_LAST_COMMIT).unwrap() { + let mut buf = [0u8; 8]; + buf.copy_from_slice(&start[0..8]); + u64::from_be_bytes(buf) as usize + 1 + } else { + 0 + }; + + let num_removed = if let Some(start) = db.get(INFO_COLUMN, &KEY_NUM_REMOVED).unwrap() { + let mut buf = [0u8; 8]; + buf.copy_from_slice(&start[0..8]); + u64::from_be_bytes(buf) as usize + } else { + 0 + }; + + output_helper + .write() + .println(format!("Expected average num tree nodes: {}", data::NUM_NODES)); + output_helper + .write() + .println(format!("Expected average num new nodes: {}", data::AVERAGE_NUM_NEW_NODES)); + + let chain_generator = ChainGenerator::new( + data::DEPTH_CHILD_COUNT_HISTOGRAMS, + data::DEPTH_AGE_HISTOGRAMS, + data::VALUE_LENGTH_HISTOGRAM, + args.seed.unwrap_or(0), + args.compress, + args.pruning, + ); + let chain_generator = Arc::new(chain_generator); + + let start_time = std::time::Instant::now(); + + COMMITS.store(start_commit, Ordering::SeqCst); + NEXT_COMMIT.store(start_commit, Ordering::SeqCst); + NUM_REMOVED.store(num_removed, Ordering::SeqCst); + + { + let db = db.clone(); + let shutdown = shutdown.clone(); + let shutdown_final = shutdown_final.clone(); + let output_helper = output_helper.clone(); + + threads.push(thread::spawn(move || informant(db, shutdown, shutdown_final, output_helper))); + } + + for i in 0..args.readers { + let db = db.clone(); + let shutdown = shutdown.clone(); + let args = args.clone(); + let chain_generator = chain_generator.clone(); + + threads.push( + thread::Builder::new() + .name(format!("reader {i}")) + .spawn(move || reader(db, args, chain_generator, i as u64, shutdown)) + .unwrap(), + ); + } + + let iter_start_index = args.readers; + for i in 0..args.iter { + let db = db.clone(); + let shutdown = shutdown.clone(); + let args = args.clone(); + let chain_generator = chain_generator.clone(); + + threads.push( + thread::Builder::new() + .name(format!("iter {i}")) + .spawn(move || { + iter(db, args, chain_generator, (iter_start_index + i) as u64, shutdown) + }) + .unwrap(), + ); + } + + for i in 0..args.writers { + let db = db.clone(); + let shutdown = shutdown.clone(); + let args = args.clone(); + let chain_generator = chain_generator.clone(); + let output_helper = output_helper.clone(); + + threads.push( + thread::Builder::new() + .name(format!("writer {i}")) + .spawn(move || { + writer(db, args, chain_generator, shutdown, start_commit, output_helper) + }) + .unwrap(), + ); + } + + if args.pruning > 0 && THREAD_PRUNING { + let db = db.clone(); + 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)) + .unwrap(), + ); + } + + while COMMITS.load(Ordering::Relaxed) < start_commit + args.commits { + thread::sleep(std::time::Duration::from_millis(50)); + } + shutdown.store(true, Ordering::SeqCst); + + let commits = COMMITS.load(Ordering::SeqCst); + let commits = commits - start_commit; + let elapsed_time = start_time.elapsed().as_secs_f64(); + + let queries = QUERIES.load(Ordering::SeqCst); + let iterations = ITERATIONS.load(Ordering::SeqCst); + + output_helper.write().println(format!( + "Completed {} commits in {} seconds. {} cps. {} queries, {} iterations", + commits, + elapsed_time, + commits as f64 / elapsed_time, + queries, + iterations + )); + + if args.empty_on_shutdown && args.pruning > 0 { + // Continue removing trees until they are all gone. + TARGET_NUM_REMOVED.store(start_commit + args.commits, Ordering::SeqCst); + while NUM_REMOVED.load(Ordering::Relaxed) < start_commit + args.commits { + thread::sleep(std::time::Duration::from_millis(50)); + } + + // Wait for all entries to actually be removed from Db. + while !shutdown_final.load(Ordering::Relaxed) { + thread::sleep(std::time::Duration::from_millis(50)); + } + } else { + shutdown_final.store(true, Ordering::SeqCst); + } + + for t in threads.into_iter() { + t.join().unwrap()?; + } + + if args.empty_on_shutdown && args.pruning > 0 { + let elapsed_time = start_time.elapsed().as_secs_f64(); + output_helper + .write() + .println_final(format!("Removed all entries. Total time: {}", elapsed_time)); + } + + Ok(()) +} diff --git a/src/btree/btree.rs b/src/btree/btree.rs index 746ba9a8..c1434de1 100644 --- a/src/btree/btree.rs +++ b/src/btree/btree.rs @@ -96,7 +96,7 @@ impl BTree { if let Some(address) = root.get(key, values, log)? { let key_query = TableKeyQuery::Fetch(None); let r = Column::get_value(key_query, address, values, log)?; - Ok(r.map(|r| r.1)) + Ok(r.map(|r| r.2)) } else { Ok(None) } diff --git a/src/btree/mod.rs b/src/btree/mod.rs index 6393a87f..bb1177d2 100644 --- a/src/btree/mod.rs +++ b/src/btree/mod.rs @@ -169,7 +169,7 @@ impl BTreeTable { let mut depth = 0; let key_query = TableKeyQuery::Fetch(None); if let Some(encoded) = Column::get_value(key_query, HEADER_ADDRESS, values, log)? { - let mut buf: ValueTableEntry> = ValueTableEntry::new(encoded.1); + let mut buf: ValueTableEntry> = ValueTableEntry::new(encoded.2); buf.check_remaining_len(8 + 4, || Error::Corruption("Invalid header length.".into()))?; root = Address::from_u64(buf.read_u64()); depth = buf.read_u32(); @@ -185,7 +185,7 @@ impl BTreeTable { ) -> Result> { let tables = self.tables.read(); let btree = self.locked(&tables); - Column::get_value(key, address, btree, log) + Ok(Column::get_value(key, address, btree, log)?.map(|(tier, _rc, value)| (tier, value))) } pub fn flush(&self) -> Result<()> { @@ -209,7 +209,7 @@ impl BTreeTable { fn get_encoded_entry(at: Address, log: &impl LogQuery, tables: TablesRef) -> Result> { let key_query = TableKeyQuery::Check(&TableKey::NoHash); - if let Some((_tier, value)) = Column::get_value(key_query, at, tables, log)? { + if let Some((_tier, _rc, value)) = Column::get_value(key_query, at, tables, log)? { Ok(value) } else { Err(Error::Corruption(format!("Missing btree entry at {at}"))) @@ -383,13 +383,21 @@ pub mod commit_overlay { BTreeChangeSet { col, changes: Default::default() } } - pub fn push(&mut self, change: Operation) { + pub fn push(&mut self, change: Operation) -> Result<()> { // No key hashing self.changes.push(match change { Operation::Set(k, v) => Operation::Set(k.into(), v.into()), Operation::Dereference(k) => Operation::Dereference(k.into()), Operation::Reference(k) => Operation::Reference(k.into()), + Operation::InsertTree(..) | + Operation::ReferenceTree(..) | + Operation::DereferenceTree(..) => + return Err(Error::InvalidInput(format!( + "Invalid operation for column {}", + self.col + ))), }); + Ok(()) } pub fn copy_to_overlay( @@ -426,6 +434,13 @@ pub mod commit_overlay { ))) } }, + Operation::InsertTree(..) | + Operation::ReferenceTree(..) | + Operation::DereferenceTree(..) => + return Err(Error::InvalidInput(format!( + "Invalid operation for column {}", + self.col + ))), } } Ok(()) diff --git a/src/column.rs b/src/column.rs index 36c1ebb8..f50f9e09 100644 --- a/src/column.rs +++ b/src/column.rs @@ -4,13 +4,15 @@ use crate::{ btree::BTreeTable, compress::Compress, - db::{check::CheckDisplay, Operation, RcValue}, + db::{check::CheckDisplay, NodeChange, Operation, RcValue}, display::hex, error::{try_io, Error, Result}, index::{Address, IndexTable, PlanOutcome, TableId as IndexTableId}, log::{Log, LogAction, LogOverlays, LogQuery, LogReader, LogWriter}, + multitree::{Children, NewNode, NodeAddress, NodeRef}, options::{ColumnOptions, Metadata, Options, DEFAULT_COMPRESSION_THRESHOLD}, parking_lot::{RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard}, + ref_count::{RefCountTable, RefCountTableId}, stats::{ColumnStatSummary, ColumnStats}, table::{ key::{TableKey, TableKeyQuery}, @@ -19,7 +21,7 @@ use crate::{ Key, }; use std::{ - collections::VecDeque, + collections::{HashMap, VecDeque}, path::PathBuf, sync::{ atomic::{AtomicU64, Ordering}, @@ -28,6 +30,7 @@ use std::{ }; pub const MIN_INDEX_BITS: u8 = 16; +pub const MIN_REF_COUNT_BITS: u8 = 11; // Measured in index entries const MAX_REINDEX_BATCH: usize = 8192; @@ -75,11 +78,24 @@ const SIZES: [u16; SIZE_TIERS - 1] = [ struct Tables { index: IndexTable, value: Vec, + ref_count: Option, +} + +impl Tables { + fn get_ref_count(&self) -> &RefCountTable { + self.ref_count.as_ref().unwrap() + } +} + +#[derive(Debug)] +enum ReindexEntry { + Index(IndexTable), + RefCount(RefCountTable), } #[derive(Debug)] struct Reindex { - queue: VecDeque, + queue: VecDeque, progress: AtomicU64, } @@ -95,11 +111,13 @@ pub struct HashColumn { col: ColId, tables: RwLock, reindex: RwLock, + ref_count_cache: Option>>, path: PathBuf, preimage: bool, uniform_keys: bool, collect_stats: bool, ref_counted: bool, + append_only: bool, salt: Salt, stats: ColumnStats, compression: Compress, @@ -196,24 +214,29 @@ pub fn hash_key(key: &[u8], salt: &Salt, uniform: bool, db_version: u32) -> Key pub struct ReindexBatch { pub drop_index: Option, pub batch: Vec<(Key, Address)>, + pub drop_ref_count: Option, + pub ref_count_batch: Vec<(Address, u64)>, + pub ref_count_batch_source: Option, } impl HashColumn { - pub fn get(&self, key: &Key, log: &impl LogQuery) -> Result> { + pub fn get(&self, key: &Key, log: &impl LogQuery) -> Result> { let tables = self.tables.read(); let values = self.as_ref(&tables.value); - if let Some((tier, value)) = self.get_in_index(key, &tables.index, values, log)? { + if let Some((tier, rc, value)) = self.get_in_index(key, &tables.index, values, log)? { if self.collect_stats { self.stats.query_hit(tier); } - return Ok(Some(value)) + return Ok(Some((value, rc))) } - for r in &self.reindex.read().queue { - if let Some((tier, value)) = self.get_in_index(key, r, values, log)? { - if self.collect_stats { - self.stats.query_hit(tier); + for entry in &self.reindex.read().queue { + if let ReindexEntry::Index(r) = entry { + if let Some((tier, rc, value)) = self.get_in_index(key, r, values, log)? { + if self.collect_stats { + self.stats.query_hit(tier); + } + return Ok(Some((value, rc))) } - return Ok(Some(value)) } } if self.collect_stats { @@ -223,7 +246,24 @@ impl HashColumn { } pub fn get_size(&self, key: &Key, log: &RwLock) -> Result> { - self.get(key, log).map(|v| v.map(|v| v.len() as u32)) + Ok(self.get(key, log)?.map(|(v, _rc)| v.len() as u32)) + } + + pub fn get_value(&self, address: Address, log: &impl LogQuery) -> Result> { + let tables = self.tables.read(); + let values = self.as_ref(&tables.value); + if let Some((tier, _rc, value)) = + Column::get_value(TableKeyQuery::Check(&TableKey::NoHash), address, values, log)? + { + if self.collect_stats { + self.stats.query_hit(tier); + } + return Ok(Some(value)) + } + if self.collect_stats { + self.stats.query_miss(); + } + Ok(None) } fn get_in_index( @@ -232,7 +272,7 @@ impl HashColumn { index: &IndexTable, tables: TablesRef, log: &impl LogQuery, - ) -> Result> { + ) -> Result> { let (mut entry, mut sub_index) = index.get(key, 0, log)?; while !entry.is_empty() { let address = entry.address(index.id.index_bits()); @@ -271,13 +311,13 @@ impl Column { address: Address, tables: TablesRef, log: &impl LogQuery, - ) -> Result> { + ) -> Result> { let size_tier = address.size_tier() as usize; - if let Some((value, compressed, _rc)) = + if let Some((value, compressed, rc)) = tables.tables[size_tier].query(&mut key, address.offset(), log)? { let value = if compressed { tables.compression.decompress(&value)? } else { value }; - return Ok(Some((size_tier as u8, value))) + return Ok(Some((size_tier as u8, rc, value))) } Ok(None) } @@ -345,7 +385,8 @@ impl Column { let entry = try_io!(entry); if let Some(file) = entry.path().file_name().and_then(|f| f.to_str()) { if crate::index::TableId::is_file_name(column, file) || - crate::table::TableId::is_file_name(column, file) + crate::table::TableId::is_file_name(column, file) || + crate::ref_count::RefCountTableId::is_file_name(column, file) { to_delete.push(PathBuf::from(file)); } @@ -361,6 +402,30 @@ impl Column { } } +pub fn packed_node_size(data: &Vec, num_children: u8) -> usize { + data.len() + num_children as usize * 8 + 1 +} + +pub fn unpack_node_data(data: Vec) -> Result<(Vec, Children)> { + 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::new(); + 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); + } + let data = data.split_at(data_len).0.to_vec(); + Ok((data, children)) +} + impl HashColumn { fn open( col: ColId, @@ -368,19 +433,29 @@ impl HashColumn { options: &Options, metadata: &Metadata, ) -> Result { - let (index, reindexing, stats) = Self::open_index(&options.path, col)?; + let (index, mut reindexing, stats) = Self::open_index(&options.path, col)?; let collect_stats = options.stats; let path = &options.path; let col_options = &metadata.columns[col as usize]; let db_version = metadata.version; + let (ref_count, ref_count_cache) = if col_options.multitree && !col_options.append_only { + ( + Some(Self::open_ref_count(&options.path, col, &mut reindexing)?), + Some(RwLock::new(Default::default())), + ) + } else { + (None, None) + }; Ok(HashColumn { col, - tables: RwLock::new(Tables { index, value }), + tables: RwLock::new(Tables { index, value, ref_count }), reindex: RwLock::new(Reindex { queue: reindexing, progress: AtomicU64::new(0) }), + ref_count_cache, path: path.into(), preimage: col_options.preimage, uniform_keys: col_options.uniform, ref_counted: col_options.ref_counted, + append_only: col_options.append_only, collect_stats, salt: metadata.salt, stats, @@ -396,6 +471,44 @@ impl HashColumn { }) } + pub fn init_table_data(&mut self) -> Result<()> { + let mut tables = self.tables.write(); + for table in &mut tables.value { + table.init_table_data()?; + } + + if let Some(cache) = &self.ref_count_cache { + let mut cache = cache.write(); + + for entry in &self.reindex.read().queue { + if let ReindexEntry::RefCount(table) = entry { + for index in 0..table.id.total_chunks() { + let entries = table.table_entries(index)?; + for entry in entries.iter() { + if !entry.is_empty() { + cache.insert(entry.address().as_u64(), entry.ref_count()); + } + } + } + } + } + + let table = &tables.ref_count; + if let Some(table) = table { + for index in 0..table.id.total_chunks() { + let entries = table.table_entries(index)?; + for entry in entries.iter() { + if !entry.is_empty() { + cache.insert(entry.address().as_u64(), entry.ref_count()); + } + } + } + } + } + + Ok(()) + } + pub fn hash_key(&self, key: &[u8]) -> Key { hash_key(key, &self.salt, self.uniform_keys, self.db_version) } @@ -406,13 +519,16 @@ impl HashColumn { for t in tables.value.iter() { t.flush()?; } + if tables.ref_count.is_some() { + tables.get_ref_count().flush()?; + } Ok(()) } fn open_index( path: &std::path::Path, col: ColId, - ) -> Result<(IndexTable, VecDeque, ColumnStats)> { + ) -> Result<(IndexTable, VecDeque, ColumnStats)> { let mut reindexing = VecDeque::new(); let mut top = None; let mut stats = ColumnStats::empty(); @@ -425,7 +541,7 @@ impl HashColumn { top = Some(table); } else { log::trace!(target: "parity-db", "Opened stale index {}", table.id); - reindexing.push_front(table); + reindexing.push_front(ReindexEntry::Index(table)); } } } @@ -436,6 +552,31 @@ impl HashColumn { Ok((table, reindexing, stats)) } + fn open_ref_count( + path: &std::path::Path, + col: ColId, + reindexing: &mut VecDeque, + ) -> Result { + let mut top = None; + for bits in (MIN_REF_COUNT_BITS..65).rev() { + let id = RefCountTableId::new(col, bits); + if let Some(table) = RefCountTable::open_existing(path, id)? { + if top.is_none() { + log::trace!(target: "parity-db", "Opened main ref count {}", table.id); + top = Some(table); + } else { + log::trace!(target: "parity-db", "Opened stale ref count {}", table.id); + reindexing.push_front(ReindexEntry::RefCount(table)); + } + } + } + let table = match top { + Some(table) => table, + None => RefCountTable::create_new(path, RefCountTableId::new(col, MIN_REF_COUNT_BITS)), + }; + Ok(table) + } + fn trigger_reindex<'a, 'b>( tables: RwLockUpgradableReadGuard<'a, Tables>, reindex: RwLockUpgradableReadGuard<'b, Reindex>, @@ -453,7 +594,7 @@ impl HashColumn { IndexTableId::new(tables.index.id.col(), tables.index.id.index_bits() + 1); let new_table = IndexTable::create_new(path, new_index_id); let old_table = std::mem::replace(&mut tables.index, new_table); - reindex.queue.push_back(old_table); + reindex.queue.push_back(ReindexEntry::Index(old_table)); ( RwLockWriteGuard::downgrade_to_upgradable(tables), RwLockWriteGuard::downgrade_to_upgradable(reindex), @@ -550,9 +691,11 @@ impl HashColumn { } // Check old indexes // TODO: don't search if index precedes reindex progress - for index in &reindex.queue { - if let Some(r) = Self::search_index(key, index, tables, log)? { - return Ok(Some(r)) + for entry in &reindex.queue { + if let ReindexEntry::Index(index) = entry { + if let Some(r) = Self::search_index(key, index, tables, log)? { + return Ok(Some(r)) + } } } Ok(None) @@ -589,6 +732,10 @@ impl HashColumn { } Ok(PlanOutcome::Skipped) }, + Operation::InsertTree(..) | + Operation::ReferenceTree(..) | + Operation::DereferenceTree(..) => + Err(Error::InvalidConfiguration("Unsupported operation on hash column".into())), } } } @@ -663,6 +810,489 @@ impl HashColumn { Ok((outcome, tables, reindex)) } + fn trigger_ref_count_reindex<'a, 'b>( + tables: RwLockUpgradableReadGuard<'a, Tables>, + reindex: RwLockUpgradableReadGuard<'b, Reindex>, + path: &std::path::Path, + ) -> (RwLockUpgradableReadGuard<'a, Tables>, RwLockUpgradableReadGuard<'b, Reindex>) { + let mut tables = RwLockUpgradableReadGuard::upgrade(tables); + let mut reindex = RwLockUpgradableReadGuard::upgrade(reindex); + log::info!( + target: "parity-db", + "Started reindex for ref count {}", + tables.get_ref_count().id, + ); + // Start reindex + let new_id = RefCountTableId::new( + tables.get_ref_count().id.col(), + tables.get_ref_count().id.index_bits() + 1, + ); + let new_table = Some(RefCountTable::create_new(path, new_id)); + let old_table = std::mem::replace(&mut tables.ref_count, new_table); + reindex.queue.push_back(ReindexEntry::RefCount(old_table.unwrap())); + ( + RwLockWriteGuard::downgrade_to_upgradable(tables), + RwLockWriteGuard::downgrade_to_upgradable(reindex), + ) + } + + pub fn write_ref_count_reindex_plan( + &self, + address: Address, + ref_count: u64, + source: RefCountTableId, + log: &mut LogWriter, + ) -> Result { + let tables = self.tables.upgradable_read(); + let reindex = self.reindex.upgradable_read(); + self.write_ref_count_reindex_plan_locked(tables, reindex, address, ref_count, source, log) + } + + fn write_ref_count_reindex_plan_locked( + &self, + mut tables: RwLockUpgradableReadGuard, + mut reindex: RwLockUpgradableReadGuard, + address: Address, + ref_count: u64, + source: RefCountTableId, + log: &mut LogWriter, + ) -> Result { + if let Some((_ref_count, _sub_index)) = tables.get_ref_count().get(address, log)? { + log::trace!(target: "parity-db", "{}: Skipped ref count reindex entry {} when reindexing", tables.get_ref_count().id, address); + return Ok(PlanOutcome::Skipped) + } + // An intermediate reindex table might contain a more recent value for the ref count so need + // to check for this and skip. + for entry in reindex.queue.iter().rev() { + if let ReindexEntry::RefCount(ref_count_table) = entry { + if ref_count_table.id == source { + break + } + if let Some(_r) = Self::search_ref_count(address, ref_count_table, log)? { + log::trace!(target: "parity-db", "{}: Skipped ref count reindex entry {} when reindexing", ref_count_table.id, address); + return Ok(PlanOutcome::Skipped) + } + } + } + let mut outcome = PlanOutcome::Written; + while let PlanOutcome::NeedReindex = + tables.get_ref_count().write_insert_plan(address, ref_count, None, log)? + { + log::debug!(target: "parity-db", "{}: Ref count chunk full {} when reindexing", tables.get_ref_count().id, address); + (tables, reindex) = + Self::trigger_ref_count_reindex(tables, reindex, self.path.as_path()); + outcome = PlanOutcome::NeedReindex; + } + Ok(outcome) + } + + fn search_ref_count<'a>( + address: Address, + ref_count_table: &'a RefCountTable, + log: &LogWriter, + ) -> Result> { + if let Some((ref_count, sub_index)) = ref_count_table.get(address, log)? { + return Ok(Some((ref_count_table, sub_index, ref_count))) + } + Ok(None) + } + + fn search_all_ref_count<'a>( + address: Address, + tables: &'a Tables, + reindex: &'a Reindex, + log: &LogWriter, + ) -> Result> { + if let Some(r) = Self::search_ref_count(address, tables.get_ref_count(), log)? { + return Ok(Some(r)) + } + // Check old tables + // TODO: don't search if table precedes reindex progress + for entry in reindex.queue.iter().rev() { + if let ReindexEntry::RefCount(ref_count_table) = entry { + if let Some(r) = Self::search_ref_count(address, ref_count_table, log)? { + return Ok(Some(r)) + } + } + } + Ok(None) + } + + fn write_ref_count_plan_existing<'a>( + &self, + tables: &Tables, + reindex: &'a Reindex, + change: (Address, Option), + log: &mut LogWriter, + ref_count_table: &RefCountTable, + sub_index: usize, + ) -> Result { + let (address, ref_count) = change; + if let Some(ref_count) = ref_count { + // Replacing + assert!(ref_count_table.id == tables.get_ref_count().id); + tables + .get_ref_count() + .write_insert_plan(address, ref_count, Some(sub_index), log) + } else { + // Removing + let result = ref_count_table.write_remove_plan(address, sub_index, log); + // Need to remove from all old tables in reindex otherwise it will appear that this + // entry still exists and it might get reintroduced during reindex. + { + if ref_count_table.id != tables.get_ref_count().id { + if let Some((table, sub_index, _ref_count)) = + Self::search_ref_count(address, tables.get_ref_count(), log)? + { + table.write_remove_plan(address, sub_index, log)?; + } + } + for entry in &reindex.queue { + if let ReindexEntry::RefCount(table) = entry { + if table.id != ref_count_table.id { + if let Some((table, sub_index, _ref_count)) = + Self::search_ref_count(address, table, log)? + { + table.write_remove_plan(address, sub_index, log)?; + } + } + } + } + } + result + } + } + + fn write_ref_count_plan_new<'a, 'b>( + &self, + mut tables: RwLockUpgradableReadGuard<'a, Tables>, + mut reindex: RwLockUpgradableReadGuard<'b, Reindex>, + address: Address, + ref_count: u64, + log: &mut LogWriter, + ) -> Result<( + PlanOutcome, + RwLockUpgradableReadGuard<'a, Tables>, + RwLockUpgradableReadGuard<'b, Reindex>, + )> { + let mut outcome = PlanOutcome::Written; + while let PlanOutcome::NeedReindex = + tables.get_ref_count().write_insert_plan(address, ref_count, None, log)? + { + log::debug!(target: "parity-db", "{}: Ref count chunk full {}", tables.get_ref_count().id, address); + (tables, reindex) = + Self::trigger_ref_count_reindex(tables, reindex, self.path.as_path()); + outcome = PlanOutcome::NeedReindex; + } + let (test_ref_count, _test_sub_index) = tables.get_ref_count().get(address, log)?.unwrap(); + assert!(test_ref_count == ref_count); + Ok((outcome, tables, reindex)) + } + + fn prepare_children( + &self, + children: &Vec, + tables: TablesRef, + tier_count: &mut HashMap, + ) -> Result<()> { + for child in children { + match child { + NodeRef::New(node) => self.prepare_node(node, tables, tier_count)?, + NodeRef::Existing(_address) => {}, + }; + } + Ok(()) + } + + fn prepare_node( + &self, + node: &NewNode, + tables: TablesRef, + tier_count: &mut HashMap, + ) -> Result<()> { + let data_size = packed_node_size(&node.data, node.children.len() as u8); + + let table_key = TableKey::NoHash; + + let target_tier = tables + .tables + .iter() + .position(|t| t.value_size(&table_key).map_or(false, |s| data_size <= s as usize)); + let target_tier = target_tier.unwrap_or_else(|| tables.tables.len() - 1); + + // Check it isn't multipart + //assert!(target_tier < (SIZE_TIERS - 1)); + + match tier_count.entry(target_tier) { + std::collections::hash_map::Entry::Occupied(mut entry) => { + *entry.get_mut() += 1; + }, + std::collections::hash_map::Entry::Vacant(entry) => { + entry.insert(1); + }, + } + + self.prepare_children(&node.children, tables, tier_count)?; + + Ok(()) + } + + fn claim_children_to_data( + &self, + children: &Vec, + tables: TablesRef, + tier_addresses: &HashMap>, + tier_index: &mut HashMap, + node_values: &mut Vec, + data: &mut Vec, + ) -> Result<()> { + for child in children { + let address = match child { + NodeRef::New(node) => + self.claim_node(node, tables, tier_addresses, tier_index, node_values)?, + NodeRef::Existing(address) => { + if !self.append_only { + node_values.push(NodeChange::IncrementReference(*address)); + } + *address + }, + }; + data.extend_from_slice(&address.to_le_bytes()); + } + Ok(()) + } + + fn claim_node( + &self, + node: &NewNode, + tables: TablesRef, + tier_addresses: &HashMap>, + tier_index: &mut HashMap, + node_values: &mut Vec, + ) -> Result { + let num_children = node.children.len(); + + let data_size = packed_node_size(&node.data, num_children as u8); + + let table_key = TableKey::NoHash; + + let target_tier = tables + .tables + .iter() + .position(|t| t.value_size(&table_key).map_or(false, |s| data_size <= s as usize)); + let target_tier = target_tier.unwrap_or_else(|| tables.tables.len() - 1); + + let index = *tier_index.get(&target_tier).unwrap(); + tier_index.insert(target_tier, index + 1); + + let offset = tier_addresses.get(&target_tier).unwrap()[index]; + + let mut data: Vec = Vec::with_capacity(data_size); + data.extend_from_slice(&node.data); + self.claim_children_to_data( + &node.children, + tables, + tier_addresses, + tier_index, + node_values, + &mut data, + )?; + data.push(num_children as u8); + + // Can't support compression as we need to know the size earlier to get the tier. + let val: RcValue = data.into(); + + let address = Address::new(offset, target_tier as u8); + + node_values.push(NodeChange::NewValue(address.as_u64(), val)); + + Ok(address.as_u64()) + } + + /// returns value for the root node and vector of NodeChange for nodes. + pub fn claim_tree_values( + &self, + change: &Operation, + ) -> Result<(Vec, Vec)> { + match change { + Operation::InsertTree(_key, node) => { + let tables = self.tables.upgradable_read(); + + let values = self.as_ref(&tables.value); + + let mut tier_count: HashMap = Default::default(); + self.prepare_children(&node.children, values, &mut tier_count)?; + + let mut tier_addresses: HashMap> = Default::default(); + let mut tier_index: HashMap = Default::default(); + for (tier, count) in tier_count { + let offsets = values.tables[tier].claim_entries(count)?; + tier_addresses.insert(tier, offsets); + tier_index.insert(tier, 0); + } + + let mut node_values: Vec = Default::default(); + + let num_children = node.children.len(); + let data_size = packed_node_size(&node.data, num_children as u8); + let mut data: Vec = Vec::with_capacity(data_size); + data.extend_from_slice(&node.data); + self.claim_children_to_data( + &node.children, + values, + &tier_addresses, + &mut tier_index, + &mut node_values, + &mut data, + )?; + data.push(num_children as u8); + + return Ok((data, node_values)) + }, + Operation::ReferenceTree(..) | Operation::DereferenceTree(..) => + return Err(Error::InvalidInput(format!( + "claim_tree_values should not be called from ReferenceTree or DereferenceTree" + ))), + _ => + return Err(Error::InvalidInput(format!( + "Invalid operation for column {}", + self.col + ))), + } + } + + pub fn write_address_value_plan( + &self, + address: u64, + cval: RcValue, + compressed: bool, + val_len: u32, + log: &mut LogWriter, + ) -> Result { + let tables = self.tables.upgradable_read(); + let tables = self.as_ref(&tables.value); + let address = Address::from_u64(address); + let target_tier = address.size_tier(); + let offset = address.offset(); + tables.tables[target_tier as usize].write_claimed_plan( + offset, + &TableKey::NoHash, + cval.as_ref(), + log, + compressed, + )?; + + let stats = self.collect_stats.then_some(&self.stats); + if let Some(stats) = stats { + stats.insert_val(val_len, cval.value().len() as u32); + } + + Ok(PlanOutcome::Written) + } + + pub fn write_address_inc_ref_plan( + &self, + address: u64, + log: &mut LogWriter, + ) -> Result { + let tables = self.tables.upgradable_read(); + let reindex = self.reindex.upgradable_read(); + let address = Address::from_u64(address); + let cached = self + .ref_count_cache + .as_ref() + .map_or(None, |c| c.read().get(&address.as_u64()).cloned()); + if let Some(cached_ref_count) = cached { + let existing: Option<(&RefCountTable, usize, u64)> = + Self::search_all_ref_count(address, &tables, &reindex, log)?; + let (table, sub_index, table_ref_count) = existing.unwrap(); + assert!(cached_ref_count > 1); + assert!(table_ref_count == cached_ref_count); + let new_ref_count = cached_ref_count + 1; + self.ref_count_cache + .as_ref() + .map(|c| c.write().insert(address.as_u64(), new_ref_count)); + if table.id == tables.get_ref_count().id { + self.write_ref_count_plan_existing( + &tables, + &reindex, + (address, Some(new_ref_count)), + log, + table, + sub_index, + ) + } else { + let (r, _, _) = + self.write_ref_count_plan_new(tables, reindex, address, new_ref_count, log)?; + Ok(r) + } + } else { + // inc ref is only called on addresses that already exist, so we know they must have + // only 1 reference. + self.ref_count_cache.as_ref().map(|c| c.write().insert(address.as_u64(), 2)); + let (r, _, _) = self.write_ref_count_plan_new(tables, reindex, address, 2, log)?; + Ok(r) + } + } + + pub fn write_address_dec_ref_plan( + &self, + address: u64, + log: &mut LogWriter, + ) -> Result<(bool, PlanOutcome)> { + let tables = self.tables.upgradable_read(); + let reindex = self.reindex.upgradable_read(); + let address = Address::from_u64(address); + let cached = self + .ref_count_cache + .as_ref() + .map_or(None, |c| c.read().get(&address.as_u64()).cloned()); + if let Some(cached_ref_count) = cached { + let existing: Option<(&RefCountTable, usize, u64)> = + Self::search_all_ref_count(address, &tables, &reindex, log)?; + let (table, sub_index, table_ref_count) = existing.unwrap(); + assert!(cached_ref_count > 1); + assert!(table_ref_count == cached_ref_count); + let new_ref_count = cached_ref_count - 1; + self.ref_count_cache.as_ref().map(|c| { + if new_ref_count > 1 { + c.write().insert(address.as_u64(), new_ref_count); + } else { + c.write().remove(&address.as_u64()); + } + }); + let new_ref_count = if new_ref_count > 1 { Some(new_ref_count) } else { None }; + let outcome = if new_ref_count.is_some() && table.id != tables.get_ref_count().id { + let (r, _, _) = self.write_ref_count_plan_new( + tables, + reindex, + address, + new_ref_count.unwrap(), + log, + )?; + r + } else { + self.write_ref_count_plan_existing( + &tables, + &reindex, + (address, new_ref_count), + log, + table, + sub_index, + )? + }; + Ok((true, outcome)) + } else { + // dec ref is only called on addresses that already exist, so we know they must have + // only 1 reference. + let tables = self.as_ref(&tables.value); + let target_tier = address.size_tier(); + let offset = address.offset(); + tables.tables[target_tier as usize].write_remove_plan(offset, log)?; + Ok((false, PlanOutcome::Written)) + } + } + pub fn enact_plan(&self, action: LogAction, log: &mut LogReader) -> Result<()> { let tables = self.tables.read(); let reindex = self.reindex.read(); @@ -670,10 +1300,15 @@ impl HashColumn { LogAction::InsertIndex(record) => { if tables.index.id == record.table { tables.index.enact_plan(record.index, log)?; - } else if let Some(table) = reindex.queue.iter().find(|r| r.id == record.table) { + } else if let Some(table) = reindex + .queue + .iter() + .filter_map(|s| if let ReindexEntry::Index(t) = s { Some(t) } else { None }) + .find(|r| r.id == record.table) + { table.enact_plan(record.index, log)?; } else { - // This may happen when removal is planed for an old index when reindexing. + // This may happen when removal is planned for an old index when reindexing. // We can safely skip the removal since the new index does not have the entry // anyway and the old index is already dropped. log::debug!( @@ -687,6 +1322,28 @@ impl HashColumn { LogAction::InsertValue(record) => { tables.value[record.table.size_tier() as usize].enact_plan(record.index, log)?; }, + LogAction::InsertRefCount(record) => { + if tables.get_ref_count().id == record.table { + tables.get_ref_count().enact_plan(record.index, log)?; + } else if let Some(table) = reindex + .queue + .iter() + .filter_map(|s| if let ReindexEntry::RefCount(t) = s { Some(t) } else { None }) + .find(|r| r.id == record.table) + { + table.enact_plan(record.index, log)?; + } else { + // This may happen when removal is planned for an old ref count when reindexing. + // We can safely skip the removal since the new ref count does not have the + // entry anyway and the old ref count is already dropped. + log::debug!( + target: "parity-db", + "Missing ref count {}. Skipped", + record.table, + ); + RefCountTable::skip_plan(log)?; + } + }, // This should never happen, unless something has modified the log file while the // database is running. Existing logs should be validated with `validate_plan` on // startup. @@ -702,7 +1359,12 @@ impl HashColumn { LogAction::InsertIndex(record) => { if tables.index.id == record.table { tables.index.validate_plan(record.index, log)?; - } else if let Some(table) = reindex.queue.iter().find(|r| r.id == record.table) { + } else if let Some(table) = reindex + .queue + .iter() + .filter_map(|s| if let ReindexEntry::Index(t) = s { Some(t) } else { None }) + .find(|r| r.id == record.table) + { table.validate_plan(record.index, log)?; } else { if record.table.index_bits() < tables.index.id.index_bits() { @@ -725,6 +1387,35 @@ impl HashColumn { LogAction::InsertValue(record) => { tables.value[record.table.size_tier() as usize].validate_plan(record.index, log)?; }, + LogAction::InsertRefCount(record) => { + if tables.get_ref_count().id == record.table { + tables.get_ref_count().validate_plan(record.index, log)?; + } else if let Some(table) = reindex + .queue + .iter() + .filter_map(|s| if let ReindexEntry::RefCount(t) = s { Some(t) } else { None }) + .find(|r| r.id == record.table) + { + table.validate_plan(record.index, log)?; + } else { + if record.table.index_bits() < tables.get_ref_count().id.index_bits() { + // Insertion into a previously dropped ref count. + log::warn!( target: "parity-db", "Ref count {} is too old. Current is {}", record.table, tables.get_ref_count().id); + return Err(Error::Corruption("Unexpected log ref count id".to_string())) + } + // Re-launch previously started reindex + // TODO: add explicit log records for reindexing events. + log::warn!( + target: "parity-db", + "Missing ref count {}, starting reindex", + record.table, + ); + let lock = + Self::trigger_ref_count_reindex(tables, reindex, self.path.as_path()); + std::mem::drop(lock); + return self.validate_plan(LogAction::InsertRefCount(record), log) + } + }, _ => { log::error!(target: "parity-db", "Unexpected log action"); return Err(Error::Corruption("Unexpected log action".to_string())) @@ -1047,45 +1738,99 @@ impl HashColumn { let reindex = self.reindex.read(); let mut plan = Vec::new(); let mut drop_index = None; + let mut ref_count_plan = Vec::new(); + let mut ref_count_source = None; + let mut drop_ref_count = None; if let Some(source) = reindex.queue.front() { let progress = reindex.progress.load(Ordering::Relaxed); - if progress != source.id.total_chunks() { - let mut source_index = progress; - if source_index % 500 == 0 { - log::debug!(target: "parity-db", "{}: Reindexing at {}/{}", tables.index.id, source_index, source.id.total_chunks()); - } - log::debug!(target: "parity-db", "{}: Continue reindex at {}/{}", tables.index.id, source_index, source.id.total_chunks()); - while source_index < source.id.total_chunks() && plan.len() < MAX_REINDEX_BATCH { - log::trace!(target: "parity-db", "{}: Reindexing {}", source.id, source_index); - let entries = source.entries(source_index, log.overlays())?; - for entry in entries.iter() { - if entry.is_empty() { - continue + match source { + ReindexEntry::Index(source) => { + if progress != source.id.total_chunks() { + let mut source_index = progress; + if source_index % 500 == 0 { + log::debug!(target: "parity-db", "{}: Reindexing at {}/{}", tables.index.id, source_index, source.id.total_chunks()); + } + log::debug!(target: "parity-db", "{}: Continue reindex at {}/{}", tables.index.id, source_index, source.id.total_chunks()); + while source_index < source.id.total_chunks() && + plan.len() < MAX_REINDEX_BATCH + { + log::trace!(target: "parity-db", "{}: Reindexing {}", source.id, source_index); + let entries = source.entries(source_index, log.overlays())?; + for entry in entries.iter() { + if entry.is_empty() { + continue + } + // We only need key prefix to reindex. + let key = source.recover_key_prefix(source_index, *entry); + plan.push((key, entry.address(source.id.index_bits()))) + } + source_index += 1; + } + log::trace!(target: "parity-db", "{}: End reindex batch {} ({})", tables.index.id, source_index, plan.len()); + reindex.progress.store(source_index, Ordering::Relaxed); + if source_index == source.id.total_chunks() { + log::info!(target: "parity-db", "Completed reindex {} into {}", source.id, tables.index.id); + drop_index = Some(source.id); } - // We only need key prefix to reindex. - let key = source.recover_key_prefix(source_index, *entry); - plan.push((key, entry.address(source.id.index_bits()))) } - source_index += 1; - } - log::trace!(target: "parity-db", "{}: End reindex batch {} ({})", tables.index.id, source_index, plan.len()); - reindex.progress.store(source_index, Ordering::Relaxed); - if source_index == source.id.total_chunks() { - log::info!(target: "parity-db", "Completed reindex {} into {}", source.id, tables.index.id); - drop_index = Some(source.id); - } + }, + ReindexEntry::RefCount(source) => + if progress != source.id.total_chunks() { + let mut source_index = progress; + if source_index % 500 == 0 { + log::debug!(target: "parity-db", "{}: Reindexing ref count at {}/{}", tables.get_ref_count().id, source_index, source.id.total_chunks()); + } + ref_count_source = Some(source.id); + log::debug!(target: "parity-db", "{}: Continue reindex ref count at {}/{}", tables.get_ref_count().id, source_index, source.id.total_chunks()); + while source_index < source.id.total_chunks() && + ref_count_plan.len() < MAX_REINDEX_BATCH + { + log::trace!(target: "parity-db", "{}: Reindexing ref count {}", source.id, source_index); + let entries = source.entries(source_index, log.overlays())?; + for entry in entries.iter() { + if entry.is_empty() { + continue + } + ref_count_plan.push((entry.address(), entry.ref_count())); + } + source_index += 1; + } + log::trace!(target: "parity-db", "{}: End reindex ref count batch {} ({})", tables.get_ref_count().id, source_index, ref_count_plan.len()); + reindex.progress.store(source_index, Ordering::Relaxed); + if source_index == source.id.total_chunks() { + log::info!(target: "parity-db", "Completed reindex ref count {} into {}", source.id, tables.get_ref_count().id); + drop_ref_count = Some(source.id); + } + }, } } - Ok(ReindexBatch { drop_index, batch: plan }) + Ok(ReindexBatch { + drop_index, + batch: plan, + drop_ref_count, + ref_count_batch: ref_count_plan, + ref_count_batch_source: ref_count_source, + }) } pub fn drop_index(&self, id: IndexTableId) -> Result<()> { log::debug!(target: "parity-db", "Dropping {}", id); let mut reindex = self.reindex.write(); - if reindex.queue.front_mut().map_or(false, |index| index.id == id) { - let table = reindex.queue.pop_front(); + if reindex.queue.front_mut().map_or(false, |e| { + if let ReindexEntry::Index(t) = e { + t.id == id + } else { + false + } + }) { reindex.progress.store(0, Ordering::Relaxed); - table.unwrap().drop_file()?; + let table = reindex.queue.pop_front().unwrap(); + let table = if let ReindexEntry::Index(table) = table { + table + } else { + return Err(Error::Corruption(format!("Incorrect reindex type"))) + }; + table.drop_file()?; } else { log::warn!(target: "parity-db", "Dropping invalid index {}", id); return Ok(()) @@ -1093,6 +1838,41 @@ impl HashColumn { log::debug!(target: "parity-db", "Dropped {}", id); Ok(()) } + + pub fn drop_ref_count(&self, id: RefCountTableId) -> Result<()> { + log::debug!(target: "parity-db", "Dropping ref count {}", id); + let mut reindex = self.reindex.write(); + if reindex.queue.front_mut().map_or(false, |e| { + if let ReindexEntry::RefCount(t) = e { + t.id == id + } else { + false + } + }) { + reindex.progress.store(0, Ordering::Relaxed); + let table = reindex.queue.pop_front().unwrap(); + let table = if let ReindexEntry::RefCount(table) = table { + table + } else { + return Err(Error::Corruption(format!("Incorrect reindex type"))) + }; + table.drop_file()?; + } else { + log::warn!(target: "parity-db", "Dropping invalid ref count {}", id); + return Ok(()) + } + log::debug!(target: "parity-db", "Dropped ref count {}", id); + Ok(()) + } + + pub fn get_num_value_entries(&self) -> Result { + let tables = self.tables.read(); + let mut num_entries = 0; + for value_table in &tables.value { + num_entries += value_table.get_num_entries()?; + } + Ok(num_entries) + } } impl Column { @@ -1205,6 +1985,10 @@ impl Column { Ok((Some(PlanOutcome::Written), None)) } }, + Operation::InsertTree(..) | + Operation::ReferenceTree(..) | + Operation::DereferenceTree(..) => + Err(Error::InvalidInput(format!("Invalid operation for column {}", tables.col))), } } @@ -1250,6 +2034,13 @@ impl Column { } } + pub fn init_table_data(&mut self) -> Result<()> { + match self { + Column::Hash(column) => column.init_table_data(), + Column::Tree(_column) => Ok(()), + } + } + pub fn flush(&self) -> Result<()> { match self { Column::Hash(column) => column.flush(), diff --git a/src/db.rs b/src/db.rs index f9685a29..55f7b272 100644 --- a/src/db.rs +++ b/src/db.rs @@ -20,24 +20,30 @@ use crate::{ btree::{commit_overlay::BTreeChangeSet, BTreeIterator, BTreeTable}, - column::{hash_key, ColId, Column, IterState, ReindexBatch, ValueIterState}, + column::{ + hash_key, unpack_node_data, ColId, Column, HashColumn, IterState, ReindexBatch, + ValueIterState, + }, error::{try_io, Error, Result}, hash::IdentityBuildHasher, - index::PlanOutcome, + index::{Address, PlanOutcome}, log::{Log, LogAction}, + multitree::{Children, NewNode, NodeAddress}, options::{Options, CURRENT_VERSION}, - parking_lot::{Condvar, Mutex, RwLock}, + parking_lot::{ + Condvar, Mutex, MutexGuard, RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard, + }, stats::StatSummary, ColumnOptions, Key, }; use fs2::FileExt; use std::{ borrow::Borrow, - collections::{BTreeMap, HashMap, VecDeque}, + collections::{BTreeMap, HashMap, HashSet, VecDeque}, ops::Bound, sync::{ atomic::{AtomicBool, AtomicU64, Ordering}, - Arc, + Arc, Weak, }, thread, }; @@ -130,6 +136,13 @@ struct CommitQueue { commits: VecDeque, } +#[derive(Debug)] +struct Trees { + readers: HashMap>>, IdentityBuildHasher>, + /// Number of queued dereferences for each tree + to_dereference: HashMap, +} + #[derive(Debug)] struct DbInner { columns: Vec, @@ -142,6 +155,7 @@ struct DbInner { commit_worker_wait: Arc>, // Overlay of most recent values in the commit queue. commit_overlay: RwLock>, + trees: RwLock>, // This may underflow occasionally, but is bound for 0 eventually. log_queue_wait: WaitCondvar, flush_worker_wait: Arc>, @@ -226,6 +240,7 @@ impl DbInner { log_worker_wait: WaitCondvar::new(), commit_worker_wait: Arc::new(WaitCondvar::new()), commit_overlay: RwLock::new(commit_overlay), + trees: RwLock::new(Default::default()), log_queue_wait: WaitCondvar::new(), flush_worker_wait: Arc::new(WaitCondvar::new()), cleanup_worker_wait: WaitCondvar::new(), @@ -239,7 +254,19 @@ impl DbInner { }) } - fn get(&self, col: ColId, key: &[u8]) -> Result> { + fn init_table_data(&mut self) -> Result<()> { + for column in &mut self.columns { + column.init_table_data()?; + } + Ok(()) + } + + fn get(&self, col: ColId, key: &[u8], external_call: bool) -> Result> { + if self.options.columns[col as usize].multitree && external_call { + return Err(Error::InvalidConfiguration( + "get not supported for multitree columns.".to_string(), + )) + } match &self.columns[col as usize] { Column::Hash(column) => { let key = column.hash_key(key); @@ -250,7 +277,7 @@ impl DbInner { } // Go into tables and log overlay. let log = self.log.overlays(); - column.get(&key, log) + Ok(column.get(&key, log)?.map(|(v, _rc)| v)) }, Column::Tree(column) => { let overlay = self.commit_overlay.read(); @@ -265,6 +292,11 @@ impl DbInner { } fn get_size(&self, col: ColId, key: &[u8]) -> Result> { + if self.options.columns[col as usize].multitree { + return Err(Error::InvalidConfiguration( + "get_size not supported for multitree columns.".to_string(), + )) + } match &self.columns[col as usize] { Column::Hash(column) => { let key = column.hash_key(key); @@ -289,6 +321,113 @@ impl DbInner { } } + fn get_root(&self, col: ColId, key: &[u8]) -> Result, Children)>> { + 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 + { + return Err(Error::InvalidConfiguration( + "get_root can only be called on a column with append_only or allow_direct_node_access options.".to_string(), + )) + } + let value = self.get(col, key, false)?; + if let Some(data) = value { + return Ok(Some(unpack_node_data(data)?)) + } + Ok(None) + } + + fn get_node( + &self, + col: ColId, + node_address: NodeAddress, + external_call: bool, + ) -> Result, Children)>> { + 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 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_data(v.value().clone())?)) + } + 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_data(data)?)) + } + Ok(None) + }, + Column::Tree(_) => Err(Error::InvalidConfiguration("Not a HashColumn.".to_string())), + } + } + + fn get_tree( + &self, + db: &Arc, + col: ColId, + key: &[u8], + check_existence: bool, + ) -> Result>>>> { + if !self.options.columns[col as usize].multitree { + return Err(Error::InvalidConfiguration("Not a multitree column.".to_string())) + } + match &self.columns[col as usize] { + Column::Hash(column) => { + // Check if the tree actually exists. We can't return the data from this function as + // TreeReader is not locked. That is done by the client. + if check_existence { + let root = self.get(col, key, false).unwrap(); + if root.is_none() { + return Ok(None) + } + } + + let hash_key = column.hash_key(key); + + let trees = self.trees.upgradable_read(); + + if let Some(column_trees) = trees.get(&col) { + if let Some(reader) = column_trees.readers.get(&hash_key) { + let reader = reader.upgrade(); + if let Some(reader) = reader { + return Ok(Some(reader)) + } + } + } + + let mut trees = RwLockUpgradableReadGuard::upgrade(trees); + + let column_trees = trees.entry(col).or_insert_with(|| Trees { + readers: Default::default(), + to_dereference: Default::default(), + }); + + let reader: Box = + Box::new(DbTreeReader { db: db.clone(), col, key: hash_key }); + let reader = Arc::new(RwLock::new(reader)); + + column_trees.readers.insert(hash_key, Arc::downgrade(&reader)); + + Ok(Some(reader)) + }, + Column::Tree(_) => Err(Error::InvalidConfiguration("Not a HashColumn.".to_string())), + } + } + fn btree_iter(&self, col: ColId) -> Result { match &self.columns[col as usize] { Column::Hash(_column) => @@ -329,13 +468,123 @@ impl DbInner { .btree_indexed .entry(col) .or_insert_with(|| BTreeChangeSet::new(col)) - .push(change) + .push(change)? + } else if self.options.columns[col as usize].multitree { + match &self.columns[col as usize] { + Column::Hash(column) => + match change { + Operation::Set(..) | + Operation::Reference(..) | + Operation::Dereference(..) => + return Err(Error::InvalidConfiguration( + "Invalid operation for multitree column".to_string(), + )), + Operation::InsertTree(..) => { + let (root_data, node_values) = column.claim_tree_values(&change)?; + + let trees = self.trees.read(); + if let Some(column_trees) = trees.get(&col) { + for (hash, count) in &column_trees.to_dereference { + assert!(*count > 0); + + // Check if TreeReader is active for this tree + let mut tree_active = false; + if let Some(reader) = column_trees.readers.get(hash) { + let reader = reader.upgrade(); + if let Some(reader) = reader { + if reader.is_locked() { + tree_active = true; + } + } + } + if tree_active { + commit + .indexed + .entry(col) + .or_insert_with(|| IndexedChangeSet::new(col)) + .used_trees + .insert(*hash); + } + } + } + drop(trees); + + let root_operation = Operation::Set(change.key(), root_data); + commit + .indexed + .entry(col) + .or_insert_with(|| IndexedChangeSet::new(col)) + .push(root_operation, &self.options, self.db_version)?; + + for node_change in node_values { + commit + .indexed + .entry(col) + .or_insert_with(|| IndexedChangeSet::new(col)) + .push_node_change(node_change); + } + }, + Operation::ReferenceTree(..) => { + if !self.options.columns[col as usize].append_only { + let root_operation = Operation::Reference(change.key()); + commit + .indexed + .entry(col) + .or_insert_with(|| IndexedChangeSet::new(col)) + .push(root_operation, &self.options, self.db_version)?; + } + }, + Operation::DereferenceTree(key) => { + if self.options.columns[col as usize].append_only { + return Err(Error::InvalidConfiguration("Attempting to dereference a tree from an append_only column.".to_string())) + } + let value = self.get(col, &key, false)?; + if let Some(data) = value { + let root_data = unpack_node_data(data)?; + let children = root_data.1; + let salt = self.options.salt.unwrap_or_default(); + let hash = hash_key( + &key, + &salt, + self.options.columns[col as usize].uniform, + self.db_version, + ); + + 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); + } + drop(trees); + + commit.check_for_deferral = true; + + let node_change = + NodeChange::DereferenceChildren(key, hash, children); + + commit + .indexed + .entry(col) + .or_insert_with(|| IndexedChangeSet::new(col)) + .push_node_change(node_change); + } else { + return Err(Error::InvalidConfiguration( + "No entry for tree root".to_string(), + )) + } + }, + }, + Column::Tree(_) => + return Err(Error::InvalidConfiguration("Not a HashColumn".to_string())), + } } else { commit.indexed.entry(col).or_insert_with(|| IndexedChangeSet::new(col)).push( change, &self.options, self.db_version, - ) + )? } } @@ -399,7 +648,73 @@ impl DbInner { Ok(()) } - fn process_commits(&self) -> Result { + fn defer_commit( + &self, + mut queue: MutexGuard, + mut commit: CommitChangeSet, + old_bytes: usize, + old_id: u64, + new_id: Option, + ) -> Result<()> { + let record_id = if let Some(id) = new_id { + id + } else { + queue.record_id += 1; + queue.record_id + }; + + let bytes = if record_id != old_id { + let mut overlay = self.commit_overlay.write(); + + let mut bytes = 0; + + for (c, indexed) in &commit.indexed { + indexed.copy_to_overlay( + &mut overlay[*c as usize], + record_id, + &mut bytes, + &self.options, + )?; + } + + for (c, iterset) in &commit.btree_indexed { + iterset.copy_to_overlay( + &mut overlay[*c as usize].btree_indexed, + record_id, + &mut bytes, + &self.options, + )?; + } + + { + // Cleanup the commit overlay with old id. + for (c, key_values) in commit.indexed.iter() { + key_values.clean_overlay(&mut overlay[*c as usize], old_id); + } + for (c, iterset) in commit.btree_indexed.iter_mut() { + iterset.clean_overlay(&mut overlay[*c as usize].btree_indexed, old_id); + } + } + + bytes + } else { + old_bytes + }; + + let commit = Commit { id: record_id, changeset: commit, bytes }; + + log::debug!( + target: "parity-db", + "Deferred commit, old id: {}, new id: {}", + old_id, + record_id, + ); + queue.commits.push_back(commit); + queue.bytes += bytes; + Ok(()) + } + + fn process_commits(&self, db: &Arc) -> Result { #[cfg(any(test, feature = "instrumentation"))] let might_wait_because_the_queue_is_full = self.options.with_background_thread; #[cfg(not(any(test, feature = "instrumentation")))] @@ -439,6 +754,79 @@ impl DbInner { }; if let Some(mut commit) = commit { + if commit.changeset.check_for_deferral { + let mut defer = false; + 'outer: for (col, key_values) in commit.changeset.indexed.iter() { + for change in &key_values.node_changes { + if let NodeChange::DereferenceChildren(_key, hash, _children) = change { + // Check if there are currently any locks on the tree. Will need to + // defer if there are. + let trees = self.trees.read(); + if let Some(column_trees) = trees.get(&col) { + let mut tree_active = false; + if let Some(reader) = column_trees.readers.get(hash) { + let reader = reader.upgrade(); + if let Some(reader) = reader { + if reader.is_locked() { + tree_active = true; + } + } + } + if tree_active { + defer = true; + break 'outer + } + } + drop(trees); + + // Also check if there are any later commits in the queue that use this + // tree. Will need to defer if there are. + let queue = self.commit_queue.lock(); + for commit in &queue.commits { + for (_col, change_set) in &commit.changeset.indexed { + for tree in &change_set.used_trees { + if tree == hash { + defer = true; + break 'outer + } + } + } + } + } + } + } + if defer { + let queue = self.commit_queue.lock(); + let new_id = if queue.commits.len() > 0 { + // Generate a new id + None + } else { + // Nothing else in the queue so can reuse same id + Some(commit.id) + }; + self.defer_commit(queue, commit.changeset, commit.bytes, commit.id, new_id)?; + + return Ok(true) + } else { + for (col, key_values) in commit.changeset.indexed.iter() { + for change in &key_values.node_changes { + if let NodeChange::DereferenceChildren(_key, hash, _children) = change { + 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); + assert!(*count > 0); + if *count == 1 { + column_trees.to_dereference.remove(hash); + } else { + column_trees.to_dereference.insert(*hash, count - 1); + } + } + } + } + } + } + } + let mut reindex = false; let mut writer = self.log.begin_record(); log::debug!( @@ -451,6 +839,8 @@ impl DbInner { let mut ops: u64 = 0; for (c, key_values) in commit.changeset.indexed.iter() { key_values.write_plan( + db, + *c, &self.columns[*c as usize], &mut writer, &mut ops, @@ -527,8 +917,19 @@ impl DbInner { // Process any pending reindexes for column in self.columns.iter() { let column = if let Column::Hash(c) = column { c } else { continue }; - let ReindexBatch { drop_index, batch } = column.reindex(&self.log)?; + let ReindexBatch { + drop_index, + batch, + drop_ref_count, + ref_count_batch, + ref_count_batch_source, + } = column.reindex(&self.log)?; if !batch.is_empty() || drop_index.is_some() { + debug_assert!( + ref_count_batch.is_empty() && + ref_count_batch_source.is_none() && + drop_ref_count.is_none() + ); let mut next_reindex = false; let mut writer = self.log.begin_record(); log::debug!( @@ -564,6 +965,48 @@ impl DbInner { self.flush_worker_wait.signal(); return Ok(true) } + if !ref_count_batch.is_empty() || drop_ref_count.is_some() { + debug_assert!(batch.is_empty() && drop_index.is_none()); + debug_assert!(ref_count_batch_source.is_some()); + let ref_count_source = ref_count_batch_source.unwrap(); + let mut next_reindex = false; + let mut writer = self.log.begin_record(); + log::debug!( + target: "parity-db", + "Creating ref count reindex record {}", + writer.record_id(), + ); + for (address, ref_count) in ref_count_batch.into_iter() { + if let PlanOutcome::NeedReindex = column.write_ref_count_reindex_plan( + address, + ref_count, + ref_count_source, + &mut writer, + )? { + next_reindex = true + } + } + if let Some(table) = drop_ref_count { + writer.drop_ref_count_table(table); + } + let record_id = writer.record_id(); + let l = writer.drain(); + + let mut logged_bytes = self.log_queue_wait.work.lock(); + let bytes = self.log.end_record(l)?; + log::debug!( + target: "parity-db", + "Created ref count reindex record {}, {} bytes", + record_id, + bytes, + ); + *logged_bytes += bytes as i64; + if next_reindex { + self.start_reindex(record_id); + } + self.flush_worker_wait.signal(); + return Ok(true) + } } self.next_reindex.store(0, Ordering::SeqCst); Ok(false) @@ -650,7 +1093,24 @@ impl DbInner { return Ok(false) } }, - LogAction::DropTable(_) => continue, + LogAction::InsertRefCount(insertion) => { + let col = insertion.table.col() as usize; + if let Err(e) = self.columns.get(col).map_or_else( + || Err(Error::Corruption(format!("Invalid column id {col}"))), + |col| { + col.validate_plan( + LogAction::InsertRefCount(insertion), + &mut reader, + ) + }, + ) { + log::warn!(target: "parity-db", "Error validating log: {:?}.", e); + drop(reader); + self.log.clear_replay_logs(); + return Ok(false) + } + }, + LogAction::DropTable(_) | LogAction::DropRefCountTable(_) => continue, } } reader.reset()?; @@ -669,6 +1129,10 @@ impl DbInner { self.columns[insertion.table.col() as usize] .enact_plan(LogAction::InsertValue(insertion), &mut reader)?; }, + LogAction::InsertRefCount(insertion) => { + self.columns[insertion.table.col() as usize] + .enact_plan(LogAction::InsertRefCount(insertion), &mut reader)?; + }, LogAction::DropTable(id) => { log::debug!( target: "parity-db", @@ -684,6 +1148,21 @@ impl DbInner { Column::Tree(_) => (), } }, + LogAction::DropRefCountTable(id) => { + log::debug!( + target: "parity-db", + "Dropping ref count {}", + id, + ); + match &self.columns[id.col() as usize] { + Column::Hash(col) => { + col.drop_ref_count(id)?; + // Check if there's another reindex on the next iteration + self.start_reindex(reader.record_id()); + }, + Column::Tree(_) => (), + } + }, } } log::debug!( @@ -799,7 +1278,7 @@ impl DbInner { self.cleanup_worker_wait.signal(); } - fn kill_logs(&self) -> Result<()> { + fn kill_logs(&self, db: &Arc) -> Result<()> { { if let Some(err) = self.bg_err.lock().as_ref() { // On error the log reader may be left in inconsistent state. So it is important @@ -813,7 +1292,7 @@ impl DbInner { // Finish logged records and proceed to log and enact queued commits. while self.enact_logs(false)? {} self.flush_logs(0)?; - while self.process_commits()? {} + while self.process_commits(db)? {} while self.enact_logs(false)? {} self.flush_logs(0)?; while self.enact_logs(false)? {} @@ -925,7 +1404,7 @@ impl Db { fn open_inner(options: &Options, opening_mode: OpeningMode) -> Result { assert!(options.is_valid()); - let db = DbInner::open(options, opening_mode)?; + let mut db = DbInner::open(options, opening_mode)?; // This needs to be call before log thread: so first reindexing // will run in correct state. if let Err(e) = db.replay_all_logs() { @@ -936,6 +1415,7 @@ impl Db { db.clean_all_logs()?; db.log.kill_logs()?; } + db.init_table_data()?; let db = Arc::new(db); #[cfg(any(test, feature = "instrumentation"))] let start_threads = opening_mode != OpeningMode::ReadOnly && options.with_background_thread; @@ -982,7 +1462,7 @@ impl Db { /// Get a value in a specified column by key. Returns `None` if the key does not exist. pub fn get(&self, col: ColId, key: &[u8]) -> Result> { - self.inner.get(col, key) + self.inner.get(col, key, true) } /// Get value size by key. Returns `None` if the key does not exist. @@ -996,6 +1476,26 @@ impl Db { self.inner.btree_iter(col) } + pub fn get_tree( + &self, + col: ColId, + key: &[u8], + ) -> Result>>>> { + self.inner.get_tree(&self.inner, col, key, true) + } + + pub fn get_root(&self, col: ColId, key: &[u8]) -> Result, Children)>> { + self.inner.get_root(col, key) + } + + pub fn get_node( + &self, + col: ColId, + node_address: NodeAddress, + ) -> Result, Children)>> { + self.inner.get_node(col, node_address, true) + } + /// Commit a set of changes to the database. pub fn commit(&self, tx: I) -> Result<()> where @@ -1067,7 +1567,7 @@ impl Db { db.log_worker_wait.wait(); } - more_commits = db.process_commits()?; + more_commits = db.process_commits(&db)?; more_reindex = db.process_reindex()?; } log::debug!(target: "parity-db", "Log worker shutdown"); @@ -1129,6 +1629,17 @@ impl Db { self.inner.stats() } + pub fn get_num_column_value_entries(&self, col: ColId) -> Result { + let column = &self.inner.columns[col as usize]; + match column { + Column::Hash(column) => return column.get_num_value_entries(), + Column::Tree(..) => + return Err(Error::InvalidConfiguration( + "get_num_column_value_entries not implemented for tree columns.".to_string(), + )), + } + } + // We open the DB before to check metadata validity and make sure there are no pending WAL // logs. fn precheck_column_operation(options: &mut Options) -> Result<[u8; 32]> { @@ -1201,7 +1712,7 @@ impl Db { #[cfg(feature = "instrumentation")] pub fn process_commits(&self) -> Result<()> { - self.inner.process_commits()?; + self.inner.process_commits(&self.inner)?; Ok(()) } @@ -1253,7 +1764,7 @@ impl Db { log::warn!(target: "parity-db", "Cleanup thread shutdown error: {:?}", e); } } - if let Err(e) = self.inner.kill_logs() { + if let Err(e) = self.inner.kill_logs(&self.inner) { log::warn!(target: "parity-db", "Shutdown error: {:?}", e); } if let Err(e) = self.inner.lock_file.unlock() { @@ -1262,23 +1773,81 @@ impl Db { } } +// Use a trait here to allow client code to have better control over lock guard lifetime without +// lifetime proliferation within Db (which would be required if not using a dynamic object). +pub trait TreeReader { + fn get_root(&self) -> Result, Children)>>; + fn get_node(&self, node_address: NodeAddress) -> Result, Children)>>; +} + +#[derive(Debug)] +pub struct DbTreeReader { + db: Arc, + col: ColId, + key: Key, +} + +impl TreeReader for DbTreeReader { + fn get_root(&self) -> Result, Children)>> { + /* let value = self.db.get(self.col, &self.key)?; + if let Some(data) = value { + return unpack_node_data(data).map(|x| Some(x)) + } + Err(Error::InvalidValueData) */ + + match &self.db.columns[self.col as usize] { + Column::Hash(column) => { + let overlay = self.db.commit_overlay.read(); + // Check commit overlay first + let value = if let Some(v) = + overlay.get(self.col as usize).and_then(|o| o.get(&self.key)) + { + Ok(v.map(|i| i.value().clone())) + } else { + // Go into tables and log overlay. + let log = self.db.log.overlays(); + Ok(column.get(&self.key, log)?.map(|(v, _rc)| v)) + }?; + + if let Some(data) = value { + return unpack_node_data(data).map(|x| Some(x)) + } + + return Ok(None) + }, + Column::Tree(..) => + return Err(Error::InvalidConfiguration("Not a HashColumn.".to_string())), + }; + } + + fn get_node(&self, node_address: NodeAddress) -> Result, Children)>> { + self.db.get_node(self.col, node_address, false) + } +} + pub type IndexedCommitOverlay = HashMap), IdentityBuildHasher>; +pub type AddressCommitOverlay = HashMap; pub type BTreeCommitOverlay = BTreeMap)>; #[derive(Debug)] pub struct CommitOverlay { indexed: IndexedCommitOverlay, + address: AddressCommitOverlay, btree_indexed: BTreeCommitOverlay, } impl CommitOverlay { fn new() -> Self { - CommitOverlay { indexed: Default::default(), btree_indexed: Default::default() } + CommitOverlay { + indexed: Default::default(), + address: Default::default(), + btree_indexed: Default::default(), + } } #[cfg(test)] fn is_empty(&self) -> bool { - self.indexed.is_empty() && self.btree_indexed.is_empty() + self.indexed.is_empty() && self.address.is_empty() && self.btree_indexed.is_empty() } } @@ -1295,6 +1864,10 @@ impl CommitOverlay { self.get_ref(key).map(|res| res.as_ref().map(|b| b.value().len() as u32)) } + fn get_address(&self, address: u64) -> Option { + self.address.get(&address).map(|(_, v)| v.clone()) + } + fn btree_get(&self, key: &[u8]) -> Option> { self.btree_indexed.get(key).map(|(_, v)| v.as_ref()) } @@ -1368,6 +1941,16 @@ pub enum Operation { /// Increment the reference count counter of an existing value for a given key. /// If no value exists for the key, this operation is skipped. Reference(Key), + + /// Insert a new tree into a MultiTree column using root key and node structure. + InsertTree(Key, NewNode), + + /// Increment the reference count of a tree (at root Key) from a MultiTree column. + ReferenceTree(Key), + + /// Dereference an existing tree (at root Key) from a MultiTree column, resulting in either + /// removal of the tree or decrement of its reference count. + DereferenceTree(Key), } impl PartialOrd for Operation { @@ -1385,13 +1968,23 @@ impl Ord for Operation { impl Operation { pub fn key(&self) -> &Key { match self { - Operation::Set(k, _) | Operation::Dereference(k) | Operation::Reference(k) => k, + Operation::Set(k, _) | + Operation::Dereference(k) | + Operation::Reference(k) | + Operation::InsertTree(k, _) | + Operation::ReferenceTree(k) | + Operation::DereferenceTree(k) => k, } } pub fn into_key(self) -> Key { match self { - Operation::Set(k, _) | Operation::Dereference(k) | Operation::Reference(k) => k, + Operation::Set(k, _) | + Operation::Dereference(k) | + Operation::Reference(k) | + Operation::InsertTree(k, _) | + Operation::ReferenceTree(k) | + Operation::DereferenceTree(k) => k, } } } @@ -1402,25 +1995,46 @@ impl, Value> Operation { Operation::Set(k, v) => Operation::Set(k.as_ref().to_vec(), v), Operation::Dereference(k) => Operation::Dereference(k.as_ref().to_vec()), Operation::Reference(k) => Operation::Reference(k.as_ref().to_vec()), + Operation::InsertTree(k, n) => Operation::InsertTree(k.as_ref().to_vec(), n), + Operation::ReferenceTree(k) => Operation::ReferenceTree(k.as_ref().to_vec()), + Operation::DereferenceTree(k) => Operation::DereferenceTree(k.as_ref().to_vec()), } } } +#[derive(Debug, PartialEq, Eq)] +pub enum NodeChange { + /// (address, value) + NewValue(u64, RcValue), + /// (address) + IncrementReference(u64), + /// Dereference and remove any of the children in the tree + DereferenceChildren(Vec, Key, Children), +} + #[derive(Debug, Default)] pub struct CommitChangeSet { pub indexed: HashMap, pub btree_indexed: HashMap, + pub check_for_deferral: bool, } #[derive(Debug)] pub struct IndexedChangeSet { pub col: ColId, pub changes: Vec>, + pub node_changes: Vec, + pub used_trees: HashSet, } impl IndexedChangeSet { pub fn new(col: ColId) -> Self { - IndexedChangeSet { col, changes: Default::default() } + IndexedChangeSet { + col, + changes: Default::default(), + node_changes: Default::default(), + used_trees: Default::default(), + } } fn push>( @@ -1428,7 +2042,7 @@ impl IndexedChangeSet { change: Operation>, options: &Options, db_version: u32, - ) { + ) -> Result<()> { let salt = options.salt.unwrap_or_default(); let hash_key = |key: &[u8]| -> Key { hash_key(key, &salt, options.columns[self.col as usize].uniform, db_version) @@ -1438,13 +2052,26 @@ impl IndexedChangeSet { Operation::Set(k, v) => Operation::Set(hash_key(k.as_ref()), v.into()), Operation::Dereference(k) => Operation::Dereference(hash_key(k.as_ref())), Operation::Reference(k) => Operation::Reference(hash_key(k.as_ref())), - }) + Operation::InsertTree(..) | + Operation::ReferenceTree(..) | + Operation::DereferenceTree(..) => + return Err(Error::InvalidInput(format!( + "Invalid operation for column {}", + self.col + ))), + }); + + Ok(()) } fn push_change_hashed(&mut self, change: Operation) { self.changes.push(change); } + fn push_node_change(&mut self, change: NodeChange) { + self.node_changes.push(change); + } + fn copy_to_overlay( &self, overlay: &mut CommitOverlay, @@ -1473,6 +2100,18 @@ impl IndexedChangeSet { return Err(Error::InvalidInput(format!("No Rc for column {}", self.col))) } }, + Operation::InsertTree(..) | + Operation::ReferenceTree(..) | + Operation::DereferenceTree(..) => + return Err(Error::InvalidInput(format!( + "Invalid operation for column {}", + self.col + ))), + } + } + for change in self.node_changes.iter() { + if let NodeChange::NewValue(address, val) = change { + overlay.address.insert(*address, (record_id, val.clone())); } } Ok(()) @@ -1480,6 +2119,8 @@ impl IndexedChangeSet { fn write_plan( &self, + db: &Arc, + col: ColId, column: &Column, writer: &mut crate::log::LogWriter, ops: &mut u64, @@ -1499,6 +2140,78 @@ impl IndexedChangeSet { } *ops += 1; } + for change in self.node_changes.iter() { + match change { + NodeChange::NewValue(address, val) => { + column.write_address_value_plan( + *address, + val.clone(), + false, + val.value().len() as u32, + writer, + )?; + }, + NodeChange::IncrementReference(address) => { + if let PlanOutcome::NeedReindex = + column.write_address_inc_ref_plan(*address, writer)? + { + *reindex = true; + } + }, + NodeChange::DereferenceChildren(key, hash, children) => { + if let Some((_root, rc)) = column.get(hash, writer)? { + column.write_plan(&Operation::Dereference(*hash), writer)?; + log::debug!(target: "parity-db", "Dereferencing root, rc={}", rc); + if rc == 1 { + let tree = db.get_tree(db, col, key, false).unwrap(); + if let Some(tree) = tree { + let guard = tree.write(); + let mut num_removed = 0; + self.write_dereference_children_plan( + column, + &guard, + children, + &mut num_removed, + writer, + )?; + log::debug!(target: "parity-db", "Dereferenced tree {:?}, removed {}", &key[0..3], num_removed); + } + } + } + // TODO: Remove TreeReader from Db. + }, + } + } + Ok(()) + } + + fn write_dereference_children_plan( + &self, + column: &HashColumn, + guard: &RwLockWriteGuard<'_, Box>, + children: &Vec, + num_removed: &mut u64, + 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 { + self.write_dereference_children_plan( + column, + guard, + &children, + num_removed, + writer, + )?; + } else { + return Err(Error::InvalidConfiguration("Missing node data".to_string())) + } + } + } Ok(()) } @@ -1513,7 +2226,15 @@ impl IndexedChangeSet { } } }, - Operation::Reference(..) => (), + Operation::Reference(..) | + Operation::InsertTree(..) | + Operation::ReferenceTree(..) | + Operation::DereferenceTree(..) => (), + } + } + for change in self.node_changes.iter() { + if let NodeChange::NewValue(address, _val) = change { + overlay.address.remove(address); } } } @@ -1629,7 +2350,7 @@ mod tests { if *self == EnableCommitPipelineStages::DbFile || *self == EnableCommitPipelineStages::LogOverlay { - while db.process_commits().unwrap() {} + while db.process_commits(db).unwrap() {} while db.process_reindex().unwrap() {} } if *self == EnableCommitPipelineStages::DbFile { diff --git a/src/lib.rs b/src/lib.rs index b7b43191..75a64f86 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,19 +14,22 @@ mod hash; mod index; mod log; mod migration; +mod multitree; mod options; mod parking_lot; +mod ref_count; mod stats; mod table; pub use btree::BTreeIterator; pub use column::{ColId, ValueIterState}; pub use compress::CompressionType; -pub use db::{check::CheckOptions, Db, Operation, Value}; +pub use db::{check::CheckOptions, Db, Operation, TreeReader, Value}; #[cfg(feature = "instrumentation")] pub use error::set_number_of_allowed_io_operations; pub use error::{Error, Result}; pub use migration::{clear_column, migrate}; +pub use multitree::{Children, NewNode, NodeAddress, NodeRef}; pub use options::{ColumnOptions, Options}; pub use stats::{ColumnStatSummary, StatSummary}; diff --git a/src/log.rs b/src/log.rs index 07e59cb2..e0152f20 100644 --- a/src/log.rs +++ b/src/log.rs @@ -8,6 +8,7 @@ use crate::{ index::{Chunk as IndexChunk, TableId as IndexTableId, ENTRY_BYTES}, options::Options, parking_lot::{RwLock, RwLockWriteGuard}, + ref_count::{Chunk as RefCountChunk, RefCountTableId, ENTRY_BYTES as REF_COUNT_ENTRY_BYTES}, table::TableId as ValueTableId, }; use std::{ @@ -24,6 +25,8 @@ const INSERT_INDEX: u8 = 2; const INSERT_VALUE: u8 = 3; const END_RECORD: u8 = 4; const DROP_TABLE: u8 = 5; +const INSERT_REF_COUNT: u8 = 6; +const DROP_REF_COUNT_TABLE: u8 = 7; // Once index overly uses less than 1/10 of its capacity, it will be reclaimed. const INDEX_OVERLAY_RECLAIM_FACTOR: usize = 10; @@ -31,6 +34,8 @@ const INDEX_OVERLAY_RECLAIM_FACTOR: usize = 10; const VALUE_OVERLAY_RECLAIM_FACTOR: usize = 10; // Min number of value items to initiate reclaim. Each item is around 40 bytes. const VALUE_OVERLAY_MIN_RECLAIM_ITEMS: usize = 10240; +// Once ref count overlay uses less than 1/10 of its capacity, it will be reclaimed. +const REF_COUNT_OVERLAY_RECLAIM_FACTOR: usize = 10; #[derive(Debug)] pub struct InsertIndexAction { @@ -44,12 +49,20 @@ pub struct InsertValueAction { pub index: u64, } +#[derive(Debug)] +pub struct InsertRefCountAction { + pub table: RefCountTableId, + pub index: u64, +} + #[derive(Debug)] pub enum LogAction { BeginRecord, InsertIndex(InsertIndexAction), InsertValue(InsertValueAction), + InsertRefCount(InsertRefCountAction), DropTable(IndexTableId), + DropRefCountTable(RefCountTableId), EndRecord, } @@ -66,12 +79,20 @@ pub trait LogQuery { ) -> Option; fn value(&self, table: ValueTableId, index: u64, dest: &mut [u8]) -> bool; fn value_ref<'a>(&'a self, table: ValueTableId, index: u64) -> Option>; + + fn ref_count R>( + &self, + table: RefCountTableId, + index: u64, + f: F, + ) -> Option; } #[derive(Debug)] pub struct LogOverlays { index: Vec, value: Vec, + ref_count: Vec, last_record_ids: Vec, } @@ -88,6 +109,9 @@ impl LogOverlays { value: (0..ValueTableId::max_log_tables(count)) .map(|_| ValueLogOverlay::default()) .collect(), + ref_count: (0..RefCountTableId::max_log_indicies(count)) + .map(|_| RefCountLogOverlay::default()) + .collect(), last_record_ids: (0..count).map(|_| 0).collect(), } } @@ -120,6 +144,15 @@ impl LogQuery for RwLock { fn value_ref<'a>(&'a self, table: ValueTableId, index: u64) -> Option> { self.read().value_ref(table, index).map(|o| MappedBytesGuard::new(o.to_vec())) } + + fn ref_count R>( + &self, + table: RefCountTableId, + index: u64, + f: F, + ) -> Option { + (&*self.read()).ref_count(table, index, f) + } } impl LogQuery for LogOverlays { @@ -154,12 +187,24 @@ impl LogQuery for LogOverlays { .get(table.log_index()) .and_then(|o| o.map.get(&index).map(|(_id, data)| data.as_slice())) } + + fn ref_count R>( + &self, + table: RefCountTableId, + index: u64, + f: F, + ) -> Option { + self.ref_count + .get(table.log_index()) + .and_then(|o| o.map.get(&index).map(|(_id, _mask, data)| f(data))) + } } #[derive(Debug, Default)] pub struct Cleared { index: Vec<(IndexTableId, u64)>, values: Vec<(ValueTableId, u64)>, + ref_count: Vec<(RefCountTableId, u64)>, } #[derive(Debug)] @@ -239,6 +284,15 @@ impl<'a> LogReader<'a> { self.cleared.values.push((table, index)); Ok(LogAction::InsertValue(InsertValueAction { table, index })) }, + INSERT_REF_COUNT => { + read_buf(2, &mut buf)?; + let table = + RefCountTableId::from_u16(u16::from_le_bytes(buf[0..2].try_into().unwrap())); + read_buf(8, &mut buf)?; + let index = u64::from_le_bytes(buf); + self.cleared.ref_count.push((table, index)); + Ok(LogAction::InsertRefCount(InsertRefCountAction { table, index })) + }, END_RECORD => { try_io!(self.reading.as_mut().unwrap().file.read_exact(&mut buf[0..4])); self.read_bytes += 4; @@ -264,6 +318,12 @@ impl<'a> LogReader<'a> { IndexTableId::from_u16(u16::from_le_bytes(buf[0..2].try_into().unwrap())); Ok(LogAction::DropTable(table)) }, + DROP_REF_COUNT_TABLE => { + read_buf(2, &mut buf)?; + let table = + RefCountTableId::from_u16(u16::from_le_bytes(buf[0..2].try_into().unwrap())); + Ok(LogAction::DropRefCountTable(table)) + }, _ => Err(Error::Corruption("Bad log entry type".into())), } } @@ -290,8 +350,10 @@ impl<'a> LogReader<'a> { pub struct LogChange { local_index: HashMap, local_values: HashMap, + local_ref_count: HashMap, record_id: u64, dropped_tables: Vec, + dropped_ref_count_tables: Vec, } impl LogChange { @@ -299,7 +361,9 @@ impl LogChange { LogChange { local_index: Default::default(), local_values: Default::default(), + local_ref_count: Default::default(), dropped_tables: Default::default(), + dropped_ref_count_tables: Default::default(), record_id, } } @@ -344,17 +408,44 @@ impl LogChange { write(value)?; } } + for (id, overlay) in self.local_ref_count.iter() { + for (index, (_, modified_entries_mask, chunk)) in overlay.map.iter() { + write(INSERT_REF_COUNT.to_le_bytes().as_ref())?; + write(&id.as_u16().to_le_bytes())?; + write(&index.to_le_bytes())?; + write(&modified_entries_mask.to_le_bytes())?; + let mut mask = *modified_entries_mask; + while mask != 0 { + let i = mask.trailing_zeros(); + mask &= !(1 << i); + write( + &chunk.0[i as usize * REF_COUNT_ENTRY_BYTES.. + (i as usize + 1) * REF_COUNT_ENTRY_BYTES], + )?; + } + } + } for id in self.dropped_tables.iter() { log::debug!(target: "parity-db", "Finalizing drop {}", id); write(DROP_TABLE.to_le_bytes().as_ref())?; write(&id.as_u16().to_le_bytes())?; } + for id in self.dropped_ref_count_tables.iter() { + log::debug!(target: "parity-db", "Finalizing ref count drop {}", id); + write(DROP_REF_COUNT_TABLE.to_le_bytes().as_ref())?; + write(&id.as_u16().to_le_bytes())?; + } write(&END_RECORD.to_le_bytes())?; let checksum: u32 = crc32.finalize(); try_io!(file.write_all(&checksum.to_le_bytes())); bytes += 4; try_io!(file.flush()); - Ok(FlushedLog { index: self.local_index, values: self.local_values, bytes }) + Ok(FlushedLog { + index: self.local_index, + values: self.local_values, + ref_count: self.local_ref_count, + bytes, + }) } } @@ -362,6 +453,7 @@ impl LogChange { struct FlushedLog { index: HashMap, values: HashMap, + ref_count: HashMap, bytes: u64, } @@ -400,10 +492,31 @@ impl<'a> LogWriter<'a> { .insert(index, (self.log.record_id, data)); } + pub fn insert_ref_count( + &mut self, + table: RefCountTableId, + index: u64, + sub: u8, + data: RefCountChunk, + ) { + match self.log.local_ref_count.entry(table).or_default().map.entry(index) { + std::collections::hash_map::Entry::Occupied(mut entry) => { + *entry.get_mut() = (self.log.record_id, entry.get().1 | (1 << sub), data); + }, + std::collections::hash_map::Entry::Vacant(entry) => { + entry.insert((self.log.record_id, 1 << sub, data)); + }, + } + } + pub fn drop_table(&mut self, id: IndexTableId) { self.log.dropped_tables.push(id); } + pub fn drop_ref_count_table(&mut self, id: RefCountTableId) { + self.log.dropped_ref_count_tables.push(id); + } + pub fn drain(self) -> LogChange { self.log } @@ -470,6 +583,23 @@ impl<'q> LogQuery for LogWriter<'q> { .map(|data| LogWriterValueGuard::Overlay(data)) }) } + + fn ref_count R>( + &self, + table: RefCountTableId, + index: u64, + f: F, + ) -> Option { + match self + .log + .local_ref_count + .get(&table) + .and_then(|o| o.map.get(&index).map(|(_id, _mask, data)| data)) + { + Some(data) => Some(f(data)), + None => self.overlays.ref_count(table, index, f), + } + } } // Identity hash. @@ -531,6 +661,11 @@ pub struct ValueLogOverlayLocal { pub map: HashMap), BuildIdHash>, // index -> (record_id, entry) } +#[derive(Debug, Default)] +pub struct RefCountLogOverlay { + pub map: HashMap, // index -> (record_id, modified_mask, entry) +} + #[derive(Debug)] struct Appending { id: u32, @@ -662,6 +797,9 @@ impl Log { for o in overlays.value.iter_mut() { o.map.clear(); } + for o in overlays.ref_count.iter_mut() { + o.map.clear(); + } for r in overlays.last_record_ids.iter_mut() { *r = 0; } @@ -697,7 +835,8 @@ impl Log { *appending = Some(Appending { size: 0, file: std::io::BufWriter::new(file), id }); } let appending = appending.as_mut().unwrap(); - let FlushedLog { index, values, bytes } = log.flush_to_file(&mut appending.file)?; + let FlushedLog { index, values, ref_count, bytes } = + log.flush_to_file(&mut appending.file)?; let mut overlays = self.overlays.write(); let mut total_index = 0; for (id, overlay) in index.into_iter() { @@ -710,13 +849,19 @@ impl Log { overlays.last_record_ids[id.col() as usize] = record_id; overlays.value[id.log_index()].map.extend(overlay.map.into_iter()); } + let mut total_ref_count = 0; + for (id, overlay) in ref_count.into_iter() { + total_ref_count += overlay.map.len(); + overlays.ref_count[id.log_index()].map.extend(overlay.map.into_iter()); + } log::debug!( target: "parity-db", - "Finalizing log record {} ({} index, {} value)", + "Finalizing log record {} ({} index, {} value, {} ref count)", record_id, total_index, total_value, + total_ref_count, ); appending.size += bytes; self.dirty.store(true, Ordering::Relaxed); @@ -746,6 +891,15 @@ impl Log { } } } + for (table, index) in cleared.ref_count.into_iter() { + if let Some(ref mut overlay) = overlays.ref_count.get_mut(table.log_index()) { + if let std::collections::hash_map::Entry::Occupied(e) = overlay.map.entry(index) { + if e.get().0 == record_id { + e.remove_entry(); + } + } + } + } // Reclaim overlay memory for (i, o) in overlays.index.iter_mut().enumerate() { if o.map.capacity() > o.map.len() * INDEX_OVERLAY_RECLAIM_FACTOR { @@ -771,6 +925,17 @@ impl Log { o.map.shrink_to_fit(); } } + for (i, o) in overlays.ref_count.iter_mut().enumerate() { + if o.map.capacity() > o.map.len() * REF_COUNT_OVERLAY_RECLAIM_FACTOR { + log::trace!( + "Schrinking ref count overlay {}: {}/{}", + RefCountTableId::from_log_index(i), + o.map.len(), + o.map.capacity(), + ); + o.map.shrink_to_fit(); + } + } } pub fn flush_one(&self, min_size: u64) -> Result { diff --git a/src/multitree.rs b/src/multitree.rs new file mode 100644 index 00000000..3d956e03 --- /dev/null +++ b/src/multitree.rs @@ -0,0 +1,17 @@ +// Copyright 2021-2022 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or MIT. + +pub type NodeAddress = u64; +pub type Children = Vec; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum NodeRef { + New(NewNode), + Existing(NodeAddress), +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct NewNode { + pub data: Vec, + pub children: Vec, +} diff --git a/src/options.rs b/src/options.rs index abdb621b..7fefbf86 100644 --- a/src/options.rs +++ b/src/options.rs @@ -65,6 +65,14 @@ pub struct ColumnOptions { /// Column is configured to use Btree storage. Btree columns allow for ordered key iteration /// and key retrieval, but are significantly less performant and require more disk space. pub btree_index: bool, + /// Column supports Multitree operations. This allows committing and querying of tree + /// structures. + pub multitree: bool, + /// Column is append-only. Delete operations are ignored. + pub append_only: bool, + /// Allow Multitree root and child nodes to be accessed directly without using TreeReader. + /// Client code must ensure this is safe. + pub allow_direct_node_access: bool, } /// Database metadata. @@ -81,8 +89,15 @@ pub struct Metadata { impl ColumnOptions { fn as_string(&self) -> String { format!( - "preimage: {}, uniform: {}, refc: {}, compression: {}, ordered: {}", - self.preimage, self.uniform, self.ref_counted, self.compression as u8, self.btree_index, + "preimage: {}, uniform: {}, refc: {}, compression: {}, ordered: {}, multitree: {}, append_only: {}, allow_direct_node_access: {}", + self.preimage, + self.uniform, + self.ref_counted, + self.compression as u8, + self.btree_index, + self.multitree, + self.append_only, + self.allow_direct_node_access, ) } @@ -91,6 +106,14 @@ impl ColumnOptions { log::error!(target: "parity-db", "Using `ref_counted` option without `preimage` enabled is not supported"); return false } + if self.ref_counted && self.append_only { + log::error!(target: "parity-db", "`ref_counted` option is redundant when `append_only` is enabled"); + return false + } + if self.multitree && self.compression != CompressionType::NoCompression { + log::error!(target: "parity-db", "Compression is not currently supported with multitree columns"); + return false + } true } @@ -111,6 +134,12 @@ impl ColumnOptions { let ref_counted = vals.get("refc")?.parse().ok()?; let compression: u8 = vals.get("compression").and_then(|c| c.parse().ok()).unwrap_or(0); let btree_index = vals.get("ordered").and_then(|c| c.parse().ok()).unwrap_or(false); + let multitree = vals.get("multitree").and_then(|c| c.parse().ok()).unwrap_or(false); + let append_only = vals.get("append_only").and_then(|c| c.parse().ok()).unwrap_or(false); + let allow_direct_node_access = vals + .get("allow_direct_node_access") + .and_then(|c| c.parse().ok()) + .unwrap_or(false); Some(ColumnOptions { preimage, @@ -118,6 +147,9 @@ impl ColumnOptions { ref_counted, compression: compression.into(), btree_index, + multitree, + append_only, + allow_direct_node_access, }) } } @@ -130,6 +162,9 @@ impl Default for ColumnOptions { ref_counted: false, compression: CompressionType::NoCompression, btree_index: false, + multitree: false, + append_only: false, + allow_direct_node_access: false, } } } diff --git a/src/parking_lot.rs b/src/parking_lot.rs index 90ef5735..e10f3bcf 100644 --- a/src/parking_lot.rs +++ b/src/parking_lot.rs @@ -87,6 +87,10 @@ mod with_loom { pub fn write(&self) -> RwLockWriteGuard { RwLockWriteGuard(self.0.write().unwrap()) } + + pub fn is_locked(&self) -> bool { + !self.0.try_write().is_ok() + } } #[derive(Debug)] diff --git a/src/ref_count.rs b/src/ref_count.rs new file mode 100644 index 00000000..b546d95e --- /dev/null +++ b/src/ref_count.rs @@ -0,0 +1,547 @@ +// Copyright 2021-2022 Parity Technologies (UK) Ltd. +// This file is dual-licensed as Apache-2.0 or MIT. + +use crate::{ + column::{ColId, MIN_REF_COUNT_BITS}, + error::{try_io, Error, Result}, + file::madvise_random, + index::{Address, PlanOutcome}, + log::{LogQuery, LogReader, LogWriter}, + parking_lot::{RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard}, +}; +use std::convert::TryInto; + +const CHUNK_LEN: usize = CHUNK_ENTRIES * ENTRY_BYTES; +const CHUNK_ENTRIES: usize = 1 << CHUNK_ENTRIES_BITS; +const CHUNK_ENTRIES_BITS: u8 = 5; +const META_SIZE: usize = 0; +const ENTRY_BITS: u8 = 128; +pub const ENTRY_BYTES: usize = ENTRY_BITS as usize / 8; + +const EMPTY_CHUNK: Chunk = Chunk([0u8; CHUNK_LEN]); +const EMPTY_ENTRIES: [Entry; CHUNK_ENTRIES] = [Entry::empty(); CHUNK_ENTRIES]; + +#[repr(C, align(8))] +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct Chunk(pub [u8; CHUNK_LEN]); + +#[derive(PartialEq, Eq, Clone, Copy)] +pub struct Entry(u64, u64); + +impl Entry { + #[inline] + fn new(address: Address, ref_count: u64) -> Entry { + Entry(address.as_u64(), ref_count) + } + + #[inline] + pub fn address(&self) -> Address { + Address::from_u64(self.0) + } + + #[inline] + pub fn ref_count(&self) -> u64 { + self.1 + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.0 == 0 + } + + pub fn as_u128(&self) -> u128 { + self.0 as u128 | (self.1 as u128) << 64 + } + + const fn empty() -> Self { + Entry(0, 0) + } + + fn from_u128(e: u128) -> Self { + Entry((e & u64::MAX as u128) as u64, (e >> 64) as u64) + } +} + +#[derive(Debug)] +pub struct RefCountTable { + pub id: RefCountTableId, + map: RwLock>, + path: std::path::PathBuf, +} + +fn total_entries(index_bits: u8) -> u64 { + total_chunks(index_bits) * CHUNK_ENTRIES as u64 +} + +fn total_chunks(index_bits: u8) -> u64 { + 1u64 << index_bits +} + +fn file_size(index_bits: u8) -> u64 { + total_entries(index_bits) * ENTRY_BYTES as u64 + META_SIZE as u64 +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub struct RefCountTableId(u16); + +impl RefCountTableId { + pub fn new(col: ColId, index_bits: u8) -> RefCountTableId { + RefCountTableId(((col as u16) << 8) | (index_bits as u16)) + } + + pub fn from_u16(id: u16) -> RefCountTableId { + RefCountTableId(id) + } + + pub fn col(&self) -> ColId { + (self.0 >> 8) as ColId + } + + pub fn index_bits(&self) -> u8 { + (self.0 & 0xff) as u8 + } + + pub fn file_name(&self) -> String { + format!("refcount_{:02}_{}", self.col(), self.index_bits()) + } + + pub fn is_file_name(col: ColId, name: &str) -> bool { + name.starts_with(&format!("refcount_{col:02}_")) + } + + pub fn as_u16(&self) -> u16 { + self.0 + } + + pub fn total_chunks(&self) -> u64 { + total_chunks(self.index_bits()) + } + + pub fn log_index(&self) -> usize { + self.col() as usize * (64 - MIN_REF_COUNT_BITS) as usize + self.index_bits() as usize + } + + pub fn from_log_index(i: usize) -> Self { + let col = i / (64 - MIN_REF_COUNT_BITS) as usize; + let bits = i % (64 - MIN_REF_COUNT_BITS) as usize; + RefCountTableId::new(col as ColId, bits as u8) + } + + pub const fn max_log_indicies(num_columns: usize) -> usize { + (64 - MIN_REF_COUNT_BITS) as usize * num_columns + } +} + +impl std::fmt::Display for RefCountTableId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "rc{:02}-{:02}", self.col(), self.index_bits()) + } +} + +impl RefCountTable { + pub fn open_existing( + path: &std::path::Path, + id: RefCountTableId, + ) -> Result> { + let mut path: std::path::PathBuf = path.into(); + path.push(id.file_name()); + + let file = match std::fs::OpenOptions::new().read(true).write(true).open(path.as_path()) { + Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(None), + Err(e) => return Err(Error::Io(e)), + Ok(file) => file, + }; + + try_io!(file.set_len(file_size(id.index_bits()))); + let mut map = try_io!(unsafe { memmap2::MmapMut::map_mut(&file) }); + madvise_random(&mut map); + log::debug!(target: "parity-db", "Opened existing refcount table {}", id); + Ok(Some(RefCountTable { id, path, map: RwLock::new(Some(map)) })) + } + + pub fn create_new(path: &std::path::Path, id: RefCountTableId) -> RefCountTable { + let mut path: std::path::PathBuf = path.into(); + path.push(id.file_name()); + RefCountTable { id, path, map: RwLock::new(None) } + } + + fn chunk_at(index: u64, map: &memmap2::MmapMut) -> Result<&Chunk> { + let offset = META_SIZE + index as usize * CHUNK_LEN; + let ptr = unsafe { &*(map[offset..offset + CHUNK_LEN].as_ptr() as *const Chunk) }; + Ok(try_io!(Ok(ptr))) + } + + fn find_entry(&self, address: u64, chunk: &Chunk) -> Option<(Entry, usize)> { + self.find_entry_base(address, chunk) + } + + fn find_entry_base(&self, address: u64, chunk: &Chunk) -> Option<(Entry, usize)> { + for i in 0..CHUNK_ENTRIES { + let entry = Self::read_entry(chunk, i); + if entry.address().as_u64() == address && !entry.is_empty() { + return Some((entry, i)) + } + } + None + } + + pub fn get(&self, address: Address, log: &impl LogQuery) -> Result> { + log::trace!(target: "parity-db", "{}: Querying ref count {}", self.id, address); + let chunk_index = self.chunk_index(address); + + if let Some(entry) = log.ref_count(self.id, chunk_index, |chunk| { + log::trace!(target: "parity-db", "{}: Querying ref count overlay at {}", self.id, chunk_index); + self.find_entry(address.as_u64(), chunk) + }) { + return Ok(entry.map(|(e, sub_index)| (e.ref_count(), sub_index))) + } + + if let Some(map) = &*self.map.read() { + log::trace!(target: "parity-db", "{}: Querying ref count chunk at {}", self.id, chunk_index); + let chunk = Self::chunk_at(chunk_index, map)?; + return Ok(self + .find_entry(address.as_u64(), chunk) + .map(|(e, sub_index)| (e.ref_count(), sub_index))) + } + Ok(None) + } + + pub fn entries(&self, chunk_index: u64, log: &impl LogQuery) -> Result<[Entry; CHUNK_ENTRIES]> { + if let Some(entry) = + log.ref_count(self.id, chunk_index, |chunk| *Self::transmute_chunk(chunk)) + { + return Ok(entry) + } + if let Some(map) = &*self.map.read() { + let chunk = Self::chunk_at(chunk_index, map)?; + return Ok(*Self::transmute_chunk(chunk)) + } + Ok(EMPTY_ENTRIES) + } + + pub fn table_entries(&self, chunk_index: u64) -> Result<[Entry; CHUNK_ENTRIES]> { + if let Some(map) = &*self.map.read() { + let chunk = Self::chunk_at(chunk_index, map)?; + return Ok(*Self::transmute_chunk(chunk)) + } + Ok(EMPTY_ENTRIES) + } + + #[inline(always)] + fn transmute_chunk(chunk: &Chunk) -> &[Entry; CHUNK_ENTRIES] { + unsafe { std::mem::transmute(chunk) } + } + + #[inline(always)] + fn write_entry(entry: &Entry, at: usize, chunk: &mut Chunk) { + chunk.0[at * ENTRY_BYTES..at * ENTRY_BYTES + ENTRY_BYTES] + .copy_from_slice(&entry.as_u128().to_le_bytes()); + } + + #[inline(always)] + fn read_entry(chunk: &Chunk, at: usize) -> Entry { + Entry::from_u128(u128::from_le_bytes( + chunk.0[at * ENTRY_BYTES..at * ENTRY_BYTES + ENTRY_BYTES].try_into().unwrap(), + )) + } + + #[inline(always)] + fn chunk_index(&self, address: Address) -> u64 { + use std::hash::Hasher; + let mut hasher = siphasher::sip::SipHasher::new(); + hasher.write_u64(address.as_u64()); + let hash = hasher.finish(); + hash >> (64 - self.id.index_bits()) + } + + fn plan_insert_chunk( + &self, + address: Address, + ref_count: u64, + mut chunk: Chunk, + sub_index: Option, + log: &mut LogWriter, + ) -> Result { + let chunk_index = self.chunk_index(address); + let new_entry = Entry::new(address, ref_count); + if let Some(i) = sub_index { + let entry = Self::read_entry(&chunk, i); + assert_eq!(entry.address(), new_entry.address()); + Self::write_entry(&new_entry, i, &mut chunk); + log::trace!(target: "parity-db", "{}: Replaced ref count at {}.{}: {}", self.id, chunk_index, i, new_entry.address()); + log.insert_ref_count(self.id, chunk_index, i as u8, chunk); + return Ok(PlanOutcome::Written) + } + for i in 0..CHUNK_ENTRIES { + let entry = Self::read_entry(&chunk, i); + if entry.is_empty() { + Self::write_entry(&new_entry, i, &mut chunk); + log::trace!(target: "parity-db", "{}: Inserted ref count at {}.{}: {}", self.id, chunk_index, i, new_entry.address()); + log.insert_ref_count(self.id, chunk_index, i as u8, chunk); + return Ok(PlanOutcome::Written) + } + } + log::debug!(target: "parity-db", "{}: Ref count chunk full at {}", self.id, chunk_index); + Ok(PlanOutcome::NeedReindex) + } + + pub fn write_insert_plan( + &self, + address: Address, + ref_count: u64, + sub_index: Option, + log: &mut LogWriter, + ) -> Result { + log::trace!(target: "parity-db", "{}: Inserting ref count {} -> {}", self.id, address, ref_count); + let chunk_index = self.chunk_index(address); + + if let Some(chunk) = log.ref_count(self.id, chunk_index, |chunk| chunk.clone()) { + return self.plan_insert_chunk(address, ref_count, chunk, sub_index, log) + } + + if let Some(map) = &*self.map.read() { + let chunk = Self::chunk_at(chunk_index, map)?.clone(); + return self.plan_insert_chunk(address, ref_count, chunk, sub_index, log) + } + + let chunk = EMPTY_CHUNK.clone(); + self.plan_insert_chunk(address, ref_count, chunk, sub_index, log) + } + + fn plan_remove_chunk( + &self, + address: Address, + mut chunk: Chunk, + sub_index: usize, + log: &mut LogWriter, + ) -> Result { + let chunk_index = self.chunk_index(address); + + let i = sub_index; + let entry = Self::read_entry(&chunk, i); + if !entry.is_empty() && entry.address() == address { + let new_entry = Entry::empty(); + Self::write_entry(&new_entry, i, &mut chunk); + log.insert_ref_count(self.id, chunk_index, i as u8, chunk); + log::trace!(target: "parity-db", "{}: Removed ref count at {}.{}", self.id, chunk_index, i); + return Ok(PlanOutcome::Written) + } + assert!(false); + Ok(PlanOutcome::Skipped) + } + + pub fn write_remove_plan( + &self, + address: Address, + sub_index: usize, + log: &mut LogWriter, + ) -> Result { + log::trace!(target: "parity-db", "{}: Removing ref count {}", self.id, address); + let chunk_index = self.chunk_index(address); + + if let Some(chunk) = log.ref_count(self.id, chunk_index, |chunk| chunk.clone()) { + return self.plan_remove_chunk(address, chunk, sub_index, log) + } + + if let Some(map) = &*self.map.read() { + let chunk = Self::chunk_at(chunk_index, map)?.clone(); + return self.plan_remove_chunk(address, chunk, sub_index, log) + } + + assert!(false); + Ok(PlanOutcome::Skipped) + } + + pub fn enact_plan(&self, index: u64, log: &mut LogReader) -> Result<()> { + let mut map = self.map.upgradable_read(); + if map.is_none() { + let mut wmap = RwLockUpgradableReadGuard::upgrade(map); + let file = try_io!(std::fs::OpenOptions::new() + .write(true) + .read(true) + .create_new(true) + .open(self.path.as_path())); + log::debug!(target: "parity-db", "Created new ref count {}", self.id); + try_io!(file.set_len(file_size(self.id.index_bits()))); + let mut mmap = try_io!(unsafe { memmap2::MmapMut::map_mut(&file) }); + madvise_random(&mut mmap); + *wmap = Some(mmap); + map = RwLockWriteGuard::downgrade_to_upgradable(wmap); + } + + let map = map.as_ref().unwrap(); + let offset = META_SIZE + index as usize * CHUNK_LEN; + // Nasty mutable pointer cast. We do ensure that all chunks that are being written are + // accessed through the overlay in other threads. + let ptr: *mut u8 = map.as_ptr() as *mut u8; + let chunk: &mut [u8] = unsafe { + let ptr = ptr.add(offset); + std::slice::from_raw_parts_mut(ptr, CHUNK_LEN) + }; + let mut mask_buf = [0u8; 8]; + log.read(&mut mask_buf)?; + let mut mask = u64::from_le_bytes(mask_buf); + while mask != 0 { + let i = mask.trailing_zeros(); + mask &= !(1 << i); + log.read(try_io!(Ok( + &mut chunk[i as usize * ENTRY_BYTES..(i as usize + 1) * ENTRY_BYTES] + )))?; + } + log::trace!(target: "parity-db", "{}: Enacted ref count chunk {}", self.id, index); + Ok(()) + } + + pub fn validate_plan(&self, index: u64, log: &mut LogReader) -> Result<()> { + if index >= self.id.total_chunks() { + return Err(Error::Corruption("Bad index".into())) + } + let mut mask_buf = [0u8; 8]; + let mut entry_buf = [0u8; ENTRY_BYTES]; + log.read(&mut mask_buf)?; + let mut mask = u64::from_le_bytes(mask_buf); + while mask != 0 { + let i = mask.trailing_zeros(); + mask &= !(1 << i); + log.read(&mut entry_buf[..])?; + } + log::trace!(target: "parity-db", "{}: Validated ref count chunk {}", self.id, index); + Ok(()) + } + + pub fn skip_plan(log: &mut LogReader) -> Result<()> { + let mut mask_buf = [0u8; 8]; + let mut entry_buf = [0u8; ENTRY_BYTES]; + log.read(&mut mask_buf)?; + let mut mask = u64::from_le_bytes(mask_buf); + while mask != 0 { + let i = mask.trailing_zeros(); + mask &= !(1 << i); + log.read(&mut entry_buf[..])?; + } + Ok(()) + } + + pub fn drop_file(self) -> Result<()> { + drop(self.map); + try_io!(std::fs::remove_file(self.path.as_path())); + log::debug!(target: "parity-db", "{}: Dropped ref count table", self.id); + Ok(()) + } + + pub fn flush(&self) -> Result<()> { + if let Some(map) = &*self.map.read() { + // Flush everything except stats. + try_io!(map.flush_range(META_SIZE, map.len() - META_SIZE)); + } + Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::*; + use rand::{Rng, SeedableRng}; + use siphasher::sip128::Hasher128; + + #[cfg(feature = "bench")] + use test::Bencher; + #[cfg(feature = "bench")] + extern crate test; + + #[test] + fn test_entries() { + let mut chunk = RefCountTable::transmute_chunk(&EMPTY_CHUNK).clone(); + let mut chunk2 = EMPTY_CHUNK; + for (i, chunk_entry) in chunk.iter_mut().enumerate().take(CHUNK_ENTRIES) { + use std::hash::Hash; + let mut hasher = siphasher::sip128::SipHasher::new(); + i.hash(&mut hasher); + let hash = hasher.finish128().as_u128(); + let entry = Entry::from_u128(hash); + RefCountTable::write_entry(&entry, i, &mut chunk2); + assert_eq!(entry.as_u128(), RefCountTable::read_entry(&chunk2, i).as_u128()); + *chunk_entry = entry; + } + + assert!(RefCountTable::transmute_chunk(&chunk2) == &chunk); + } + + #[test] + fn test_find_any_entry() { + let table = RefCountTable { + id: RefCountTableId(18), + map: RwLock::new(None), + path: Default::default(), + }; + let mut chunk = Chunk([0u8; CHUNK_LEN]); + let mut entries = [Entry::empty(); CHUNK_ENTRIES]; + let mut addresses = [0u64; CHUNK_ENTRIES]; + let mut rng = rand::prelude::SmallRng::from_seed(Default::default()); + for i in 0..CHUNK_ENTRIES { + addresses[i] = rng.gen(); + let ref_count = rng.gen(); + let e = Entry::new(Address::from_u64(addresses[i]), ref_count); + entries[i] = e; + RefCountTable::write_entry(&e, i, &mut chunk); + } + + for target in 0..CHUNK_ENTRIES { + let result = table.find_entry_base(addresses[target], &chunk); + assert!(result.is_some()); + if let Some((e, i)) = result { + assert_eq!((e.as_u128(), i), (entries[target].as_u128(), target)); + } + } + } + + #[test] + fn test_find_entry_zero() { + let table = RefCountTable { + id: RefCountTableId(16), + map: RwLock::new(None), + path: Default::default(), + }; + let mut chunk = Chunk([0u8; CHUNK_LEN]); + let address = Address::new(1, 1); + let entry = Entry::new(address, 0); + + // Write at index 1. Index 0 contains an empty entry. + RefCountTable::write_entry(&entry, 1, &mut chunk); + + let result = table.find_entry_base(address.as_u64(), &chunk); + assert!(result.is_some()); + if let Some((_e, i)) = result { + assert_eq!(i, 1); + } + } + + #[cfg(feature = "bench")] + #[bench] + fn bench_find_entry(b: &mut Bencher) { + let table = RefCountTable { + id: RefCountTableId(18), + map: RwLock::new(None), + path: Default::default(), + }; + let mut chunk = Chunk([0u8; CHUNK_LEN]); + let mut addresses = [0u64; CHUNK_ENTRIES]; + let mut rng = rand::prelude::SmallRng::from_seed(Default::default()); + for i in 0..CHUNK_ENTRIES { + addresses[i] = rng.gen(); + let ref_count = rng.gen(); + let e = Entry::new(Address::from_u64(addresses[i]), ref_count); + RefCountTable::write_entry(&e, i, &mut chunk); + } + + let mut index = 0; + b.iter(|| { + let result = RefCountTable::find_entry_base(&table, addresses[index], &chunk); + assert!(result.is_some()); + if let Some((_e, i)) = result { + assert_eq!(i, index); + } + index = (index + 1) % CHUNK_ENTRIES; + }); + } +} diff --git a/src/table.rs b/src/table.rs index dae909de..b493c71c 100644 --- a/src/table.rs +++ b/src/table.rs @@ -138,6 +138,11 @@ impl std::fmt::Display for TableId { } } +#[derive(Debug)] +struct FreeEntries { + stack: Vec, +} + #[derive(Debug)] pub struct ValueTable { pub id: TableId, @@ -147,6 +152,8 @@ pub struct ValueTable { written: AtomicU64, // Actual number of entries on disk. last_removed: AtomicU64, dirty_header: AtomicBool, + needs_free_entries: bool, + free_entries: Option>, multipart: bool, ref_counted: bool, db_version: u32, @@ -441,12 +448,46 @@ impl ValueTable { written: AtomicU64::new(filled), last_removed: AtomicU64::new(last_removed), dirty_header: AtomicBool::new(false), + needs_free_entries: options.multitree, + free_entries: None, multipart, ref_counted: options.ref_counted, db_version, }) } + pub fn init_table_data(&mut self) -> Result<()> { + let free_entries = if self.needs_free_entries { + let mut stack: Vec = Default::default(); + + let filled = self.filled.load(Ordering::Relaxed); + let last_removed = self.last_removed.load(Ordering::Relaxed); + + let mut next = last_removed; + while next != 0 { + if next >= filled { + return Err(crate::error::Error::Corruption(format!( + "Bad removed ref {} out of {}", + next, filled + ))) + } + + stack.insert(0, next); + + let mut buf = PartialEntry::new_uninit(); + self.file.read_at(buf.as_mut(), next * self.entry_size as u64)?; + buf.skip_size(); + next = buf.read_next(); + } + + Some(RwLock::new(FreeEntries { stack })) + } else { + None + }; + self.free_entries = free_entries; + Ok(()) + } + pub fn value_size(&self, key: &TableKey) -> Option { let base = self.entry_size - SIZE_SIZE as u16 - self.ref_size() as u16; let k_encoded = key.encoded_size() as u16; @@ -700,6 +741,12 @@ impl ValueTable { } pub fn next_free(&self, log: &mut LogWriter) -> Result { + let free_entries_guard = if let Some(free_entries) = &self.free_entries { + Some(free_entries.write()) + } else { + None + }; + let filled = self.filled.load(Ordering::Relaxed); let last_removed = self.last_removed.load(Ordering::Relaxed); let index = if last_removed != 0 { @@ -711,6 +758,10 @@ impl ValueTable { last_removed, ); self.last_removed.store(next_removed, Ordering::Relaxed); + if let Some(mut free_entries) = free_entries_guard { + let last = free_entries.stack.pop().unwrap(); + debug_assert_eq!(last, last_removed); + } last_removed } else { log::trace!( @@ -726,12 +777,48 @@ impl ValueTable { Ok(index) } + pub fn claim_entries(&self, num: usize) -> Result> { + match &self.free_entries { + Some(free_entries) => { + let mut free_entries = free_entries.write(); + + let mut entries: Vec = Default::default(); + + for _i in 0..num { + let filled = self.filled.load(Ordering::Relaxed); + let last_removed = self.last_removed.load(Ordering::Relaxed); + let index = if last_removed != 0 { + let last = free_entries.stack.pop().unwrap(); + debug_assert_eq!(last, last_removed); + + let next_removed = *free_entries.stack.last().unwrap_or(&0u64); + + self.last_removed.store(next_removed, Ordering::Relaxed); + last_removed + } else { + self.filled.store(filled + 1, Ordering::Relaxed); + filled + }; + entries.push(index); + } + self.dirty_header.store(true, Ordering::Relaxed); + + Ok(entries) + }, + None => + return Err(crate::error::Error::InvalidConfiguration(format!( + "claim_entries called without free_entries" + ))), + } + } + fn overwrite_chain( &self, key: &TableKey, value: &[u8], log: &mut LogWriter, at: Option, + claimed: bool, compressed: bool, ) -> Result { let mut remainder = value.len() + self.ref_size() + key.encoded_size(); @@ -739,7 +826,7 @@ impl ValueTable { let mut start = 0; assert!(self.multipart || value.len() <= self.value_size(key).unwrap() as usize); let (mut index, mut follow) = match at { - Some(index) => (index, true), + Some(index) => (index, !claimed), None => (self.next_free(log)?, false), }; loop { @@ -828,6 +915,12 @@ impl ValueTable { } fn clear_slot(&self, index: u64, log: &mut LogWriter) -> Result<()> { + let free_entries_guard = if let Some(free_entries) = &self.free_entries { + Some(free_entries.write()) + } else { + None + }; + let last_removed = self.last_removed.load(Ordering::Relaxed); log::trace!( target: "parity-db", @@ -843,6 +936,11 @@ impl ValueTable { log.insert_value(self.id, index, buf[0..buf.offset()].to_vec()); self.last_removed.store(index, Ordering::Relaxed); self.dirty_header.store(true, Ordering::Relaxed); + + if let Some(mut free_entries) = free_entries_guard { + free_entries.stack.push(index); + } + Ok(()) } @@ -853,7 +951,7 @@ impl ValueTable { log: &mut LogWriter, compressed: bool, ) -> Result { - self.overwrite_chain(key, value, log, None, compressed) + self.overwrite_chain(key, value, log, None, false, compressed) } pub fn write_replace_plan( @@ -864,7 +962,19 @@ impl ValueTable { log: &mut LogWriter, compressed: bool, ) -> Result<()> { - self.overwrite_chain(key, value, log, Some(index), compressed)?; + self.overwrite_chain(key, value, log, Some(index), false, compressed)?; + Ok(()) + } + + pub fn write_claimed_plan( + &self, + index: u64, + key: &TableKey, + value: &[u8], + log: &mut LogWriter, + compressed: bool, + ) -> Result<()> { + self.overwrite_chain(key, value, log, Some(index), true, compressed)?; Ok(()) } @@ -999,6 +1109,11 @@ impl ValueTable { if self.file.map.read().is_none() { return Ok(()) } + let _free_entries_guard = if let Some(free_entries) = &self.free_entries { + Some(free_entries.write()) + } else { + None + }; let mut header = Header::default(); self.file.read_at(&mut header.0, 0)?; let last_removed = header.last_removed(); @@ -1013,6 +1128,11 @@ impl ValueTable { } pub fn complete_plan(&self, log: &mut LogWriter) -> Result<()> { + let _free_entries_guard = if let Some(free_entries) = &self.free_entries { + Some(free_entries.read()) + } else { + None + }; if let Ok(true) = self.dirty_header .compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed) @@ -1088,7 +1208,7 @@ impl ValueTable { let empty_overlays = RwLock::new(LogOverlays::with_columns(0)); let mut log = LogWriter::new(&empty_overlays, 0); - let at = self.overwrite_chain(&TableKey::NoHash, entry, &mut log, None, false)?; + let at = self.overwrite_chain(&TableKey::NoHash, entry, &mut log, None, false, false)?; self.complete_plan(&mut log)?; assert_eq!(at, 1); let log = log.drain(); @@ -1101,6 +1221,11 @@ impl ValueTable { /// Validate free records sequence. pub fn check_free_refs(&self) -> Result { + let _free_entries_guard = if let Some(free_entries) = &self.free_entries { + Some(free_entries.read()) + } else { + None + }; let written = self.written.load(Ordering::Relaxed); let mut next = self.last_removed.load(Ordering::Relaxed); let mut len = 0; @@ -1119,6 +1244,25 @@ impl ValueTable { } Ok(len) } + + pub fn get_num_entries(&self) -> Result { + if let Some(free_entries) = &self.free_entries { + let free_entries = free_entries.read(); + let filled = self.filled.load(Ordering::Relaxed); + let num_free = free_entries.stack.len(); + let num = (filled - 1) - num_free as u64; + if num > 0 && self.multipart { + // TODO: Need to implement this. + return Err(crate::error::Error::InvalidConfiguration(format!( + "Unable to determine number of multipart entries" + ))) + } + return Ok(num) + } + Err(crate::error::Error::InvalidConfiguration(format!( + "Unable to determine number of entries" + ))) + } } pub mod key { @@ -1234,7 +1378,9 @@ mod test { match reader.next().unwrap() { LogAction::BeginRecord | LogAction::InsertIndex { .. } | - LogAction::DropTable { .. } => { + LogAction::InsertRefCount { .. } | + LogAction::DropTable { .. } | + LogAction::DropRefCountTable { .. } => { panic!("Unexpected log entry"); }, LogAction::EndRecord => {