Compare commits

..

10 Commits

Author SHA1 Message Date
nym21 ec960bfefa release: v0.0.80 2025-07-13 21:20:40 +02:00
nym21 79f689dde1 mcp: remove claude results examples due to dead links 2025-07-13 21:20:02 +02:00
nym21 3b3654df56 vec: add local and shared stored_len to raw variant 2025-07-13 19:30:50 +02:00
nym21 c66f008f07 release: v0.0.79 2025-07-13 17:18:14 +02:00
nym21 37d9498d90 crates: upgrade 2025-07-13 17:18:02 +02:00
nym21 1ff67093db website: apply datasets changes to charts 2025-07-13 17:14:34 +02:00
nym21 daed37ccb8 stores: forgot some files 2025-07-13 16:52:19 +02:00
nym21 d41d807b4f stores: bloom filters back to default due to slow reads, v3 will bring down the needed RAM 2025-07-13 16:49:45 +02:00
nym21 d6fa5c8a55 vec: fix header reading of existing file 2025-07-13 16:31:22 +02:00
nym21 2dd608dfed vec: don't store mmap in struct anymore 2025-07-13 11:50:34 +02:00
22 changed files with 549 additions and 484 deletions
Generated
+35 -36
View File
@@ -170,9 +170,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "async-compression"
version = "0.4.25"
version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40f6024f3f856663b45fd0c9b6f2024034a702f453549449e0d84a305900dad4"
checksum = "937f41778d8baa0b8984a101f48ec5d2e5b0d23a3f9235b2066eef29c3472bb9"
dependencies = [
"brotli",
"flate2",
@@ -477,7 +477,7 @@ dependencies = [
[[package]]
name = "brk"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"brk_bundler",
"brk_cli",
@@ -497,7 +497,7 @@ dependencies = [
[[package]]
name = "brk_bundler"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"brk_rolldown",
"log",
@@ -508,7 +508,7 @@ dependencies = [
[[package]]
name = "brk_cli"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"bitcoincore-rpc",
"brk_computer",
@@ -531,7 +531,7 @@ dependencies = [
[[package]]
name = "brk_computer"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"bincode",
"bitcoin",
@@ -548,7 +548,6 @@ dependencies = [
"derive_deref",
"either",
"fjall",
"jiff",
"log",
"rayon",
"serde",
@@ -558,7 +557,7 @@ dependencies = [
[[package]]
name = "brk_core"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"bincode",
"bitcoin",
@@ -579,7 +578,7 @@ dependencies = [
[[package]]
name = "brk_exit"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"brk_logger",
"ctrlc",
@@ -588,7 +587,7 @@ dependencies = [
[[package]]
name = "brk_fetcher"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"brk_core",
"brk_logger",
@@ -600,7 +599,7 @@ dependencies = [
[[package]]
name = "brk_indexer"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"bitcoin",
"bitcoincore-rpc",
@@ -618,7 +617,7 @@ dependencies = [
[[package]]
name = "brk_interface"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"brk_computer",
"brk_core",
@@ -636,7 +635,7 @@ dependencies = [
[[package]]
name = "brk_logger"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"color-eyre",
"env_logger",
@@ -646,7 +645,7 @@ dependencies = [
[[package]]
name = "brk_mcp"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"axum",
"brk_interface",
@@ -656,7 +655,7 @@ dependencies = [
[[package]]
name = "brk_parser"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"bitcoin",
"bitcoincore-rpc",
@@ -1025,7 +1024,7 @@ dependencies = [
[[package]]
name = "brk_server"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"axum",
"bitcoincore-rpc",
@@ -1055,7 +1054,7 @@ dependencies = [
[[package]]
name = "brk_store"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"brk_core",
"byteview",
@@ -1077,7 +1076,7 @@ dependencies = [
[[package]]
name = "brk_vec"
version = "0.0.78"
version = "0.0.80"
dependencies = [
"arc-swap",
"brk_core",
@@ -1159,9 +1158,9 @@ dependencies = [
[[package]]
name = "castaway"
version = "0.2.3"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5"
checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
dependencies = [
"rustversion",
]
@@ -1371,9 +1370,9 @@ dependencies = [
[[package]]
name = "crc32fast"
version = "1.4.2"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
@@ -2431,9 +2430,9 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "memmap2"
version = "0.9.5"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
checksum = "483758ad303d734cec05e5c12b41d7e93e6a6390c5e9dae6bdeb7c1259012d28"
dependencies = [
"libc",
]
@@ -3553,9 +3552,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "regress"
version = "0.10.3"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ef7fa9ed0256d64a688a3747d0fef7a88851c18a5e1d57f115f38ec2e09366"
checksum = "145bb27393fe455dd64d6cbc8d059adfa392590a45eadf079c01b11857e7b010"
dependencies = [
"hashbrown 0.15.4",
"memchr",
@@ -4240,9 +4239,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.9.1"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0207d6ed1852c2a124c1fbec61621acb8330d2bf969a5d0643131e9affd985a5"
checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac"
dependencies = [
"indexmap 2.10.0",
"serde",
@@ -4264,18 +4263,18 @@ dependencies = [
[[package]]
name = "toml_parser"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5c1c469eda89749d2230d8156a5969a69ffe0d6d01200581cdc6110674d293e"
checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30"
dependencies = [
"winnow",
]
[[package]]
name = "toml_writer"
version = "1.0.0"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b679217f2848de74cabd3e8fc5e6d66f40b7da40f8e1954d92054d9010690fd5"
checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
[[package]]
name = "tower"
@@ -4574,9 +4573,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "vfs"
version = "0.12.1"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ec343ec20aa715908fd028a4b8e7c99a349d13143224222e4d61c316d1e7f0a"
checksum = "9e723b9e1c02a3cf9f9d0de6a4ddb8cdc1df859078902fe0ae0589d615711ae6"
dependencies = [
"filetime",
]
@@ -4929,9 +4928,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]]
name = "winnow"
version = "0.7.11"
version = "0.7.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
[[package]]
name = "wit-bindgen-rt"
+15 -15
View File
@@ -4,7 +4,7 @@ members = ["crates/*"]
package.description = "The Bitcoin Research Kit is a suite of tools designed to extract, compute and display data stored on a Bitcoin Core node"
package.license = "MIT"
package.edition = "2024"
package.version = "0.0.78"
package.version = "0.0.80"
package.homepage = "https://bitcoinresearchkit.org"
package.repository = "https://github.com/bitcoinresearchkit/brk"
@@ -26,22 +26,22 @@ axum = "0.8.4"
bincode = { version = "2.0.1", features = ["serde"] }
bitcoin = { version = "0.32.6", features = ["serde"] }
bitcoincore-rpc = "0.19.0"
brk_bundler = { version = "0.0.78", path = "crates/brk_bundler" }
brk_cli = { version = "0.0.78", path = "crates/brk_cli" }
brk_computer = { version = "0.0.78", path = "crates/brk_computer" }
brk_core = { version = "0.0.78", path = "crates/brk_core" }
brk_exit = { version = "0.0.78", path = "crates/brk_exit" }
brk_fetcher = { version = "0.0.78", path = "crates/brk_fetcher" }
brk_indexer = { version = "0.0.78", path = "crates/brk_indexer" }
brk_interface = { version = "0.0.78", path = "crates/brk_interface" }
brk_logger = { version = "0.0.78", path = "crates/brk_logger" }
brk_mcp = { version = "0.0.78", path = "crates/brk_mcp" }
brk_parser = { version = "0.0.78", path = "crates/brk_parser" }
brk_bundler = { version = "0.0.80", path = "crates/brk_bundler" }
brk_cli = { version = "0.0.80", path = "crates/brk_cli" }
brk_computer = { version = "0.0.80", path = "crates/brk_computer" }
brk_core = { version = "0.0.80", path = "crates/brk_core" }
brk_exit = { version = "0.0.80", path = "crates/brk_exit" }
brk_fetcher = { version = "0.0.80", path = "crates/brk_fetcher" }
brk_indexer = { version = "0.0.80", path = "crates/brk_indexer" }
brk_interface = { version = "0.0.80", path = "crates/brk_interface" }
brk_logger = { version = "0.0.80", path = "crates/brk_logger" }
brk_mcp = { version = "0.0.80", path = "crates/brk_mcp" }
brk_parser = { version = "0.0.80", path = "crates/brk_parser" }
brk_rmcp = { version = "0.2.1", features = ["transport-streamable-http-server", "transport-worker"]}
# brk_rmcp = { path = "../rust-sdk/crates/rmcp", features = ["transport-streamable-http-server", "transport-worker"]}
brk_server = { version = "0.0.78", path = "crates/brk_server" }
brk_store = { version = "0.0.78", path = "crates/brk_store" }
brk_vec = { version = "0.0.78", path = "crates/brk_vec" }
brk_server = { version = "0.0.80", path = "crates/brk_server" }
brk_store = { version = "0.0.80", path = "crates/brk_store" }
brk_vec = { version = "0.0.80", path = "crates/brk_vec" }
byteview = "=0.6.1"
clap = { version = "4.5.41", features = ["string"] }
clap_derive = "4.5.41"
+1 -2
View File
@@ -46,8 +46,7 @@ The toolkit can be used in various ways to accommodate as many needs as possible
Just like the website, it's entirely free, with no authentication or rate-limiting.
- **[AI](https://github.com/bitcoinresearchkit/brk/blob/main/crates/brk_mcp/README.md#brk-mcp)** \
LLMs have to possibility to connect to BRK's backend through a [MCP](https://modelcontextprotocol.io/introduction). \
It will give them access to the same tools as the API, with no restrictions, and allow you to have your very own data analysts. \
One-shot output examples: [Document](https://claude.ai/public/artifacts/71194d29-f965-417c-ba09-fdf0e4ecb1d5) // [Dashboard](https://claude.ai/public/artifacts/beef143f-399a-4ed4-b8bf-c986b776de42) // [Dashboard 2](https://claude.ai/public/artifacts/5430ae49-bb3d-4fc1-ab24-f1e33deb40dc)
It will give them access to the same tools as the API, with no restrictions, and allow you to have your very own data analysts.
- **[CLI](https://crates.io/crates/brk_cli)** \
Node runners are strongly encouraged to try out and self-host their own instance using BRK's command line interface. \
The CLI has multiple cogs available for users to tweak to adapt to all situations with even the possibility for web developers to create their own custom website which could later on be added as an alternative front-end.
+1 -1
View File
@@ -24,7 +24,7 @@ color-eyre = { workspace = true }
log = { workspace = true }
serde = { workspace = true }
tokio = { workspace = true }
toml = "0.9.1"
toml = "0.9.2"
[[bin]]
name = "brk"
-1
View File
@@ -23,7 +23,6 @@ color-eyre = { workspace = true }
derive_deref = { workspace = true }
either = "1.15.0"
fjall = { workspace = true }
jiff = { workspace = true }
log = { workspace = true }
rayon = { workspace = true }
serde = { workspace = true }
+21 -19
View File
@@ -10,6 +10,7 @@ use brk_fetcher::Fetcher;
use brk_indexer::Indexer;
use brk_vec::{
AnyCollectableVec, AnyIterableVec, AnyVec, Computation, EagerVec, Format, StoredIndex,
VecIterator,
};
use crate::vecs::grouped::Source;
@@ -456,33 +457,34 @@ impl Vecs {
exit,
)?;
let mut prev = None;
self.dateindex_to_ohlc_in_cents.compute_transform(
starting_indexes.dateindex,
&indexes.dateindex_to_date,
|(di, d, this)| {
let get_prev = || {
this.get_or_read(di, &this.mmap().load())
.unwrap()
.unwrap()
.into_owned()
};
if prev.is_none() {
let i = di.unwrap_to_usize();
prev.replace(if i > 0 {
this.into_iter().unwrap_get_inner_(i - 1)
} else {
OHLCCents::default()
});
}
let mut ohlc = if di.unwrap_to_usize() + 100 >= this.len() {
fetcher.get_date(d).unwrap_or_else(|_| get_prev())
} else {
get_prev()
};
if let Some(prev) = di.decremented() {
let prev_open = *this
.get_or_read(prev, &this.mmap().load())
.unwrap()
.unwrap()
.close;
let ohlc = if di.unwrap_to_usize() + 100 >= this.len()
&& let Ok(mut ohlc) = fetcher.get_date(d)
{
let prev_open = *prev.as_ref().unwrap().close;
*ohlc.open = prev_open;
*ohlc.high = (*ohlc.high).max(prev_open);
*ohlc.low = (*ohlc.low).min(prev_open);
}
ohlc
} else {
prev.clone().unwrap()
};
prev.replace(ohlc.clone());
(di, ohlc)
},
exit,
+3 -3
View File
@@ -498,9 +498,9 @@ impl Vecs {
let dateindex_to_first_height = &indexes.dateindex_to_first_height;
let dateindex_to_height_count = &indexes.dateindex_to_height_count;
let outputindex_to_value_mmap = outputindex_to_value.mmap().load();
let outputindex_to_outputtype_mmap = outputindex_to_outputtype.mmap().load();
let outputindex_to_typeindex_mmap = outputindex_to_typeindex.mmap().load();
let outputindex_to_value_mmap = outputindex_to_value.create_mmap()?;
let outputindex_to_outputtype_mmap = outputindex_to_outputtype.create_mmap()?;
let outputindex_to_typeindex_mmap = outputindex_to_typeindex.create_mmap()?;
let mut inputindex_to_outputindex_iter = inputindex_to_outputindex.into_iter();
let mut height_to_first_outputindex_iter = height_to_first_outputindex.into_iter();
+1 -1
View File
@@ -7,7 +7,7 @@ pub fn setrlimit() -> io::Result<()> {
rlimit::setrlimit(
Resource::NOFILE,
no_file_limit.0.max(250_000),
no_file_limit.0.max(10_000),
no_file_limit.1,
)?;
+103 -27
View File
@@ -15,7 +15,7 @@ use bitcoin::{Transaction, TxIn, TxOut};
use brk_exit::Exit;
use brk_parser::Parser;
use brk_store::AnyStore;
use brk_vec::{AnyVec, VecIterator};
use brk_vec::{AnyVec, Mmap, VecIterator};
use color_eyre::eyre::{ContextCompat, eyre};
use log::{error, info};
use rayon::prelude::*;
@@ -40,6 +40,7 @@ pub struct Indexer {
impl Indexer {
pub fn forced_import(outputs_dir: &Path) -> color_eyre::Result<Self> {
setrlimit()?;
Ok(Self {
vecs: Vecs::forced_import(&outputs_dir.join("vecs/indexed"), VERSION + Version::ZERO)?,
stores: Stores::forced_import(&outputs_dir.join("stores"), VERSION + Version::ZERO)?,
@@ -88,9 +89,9 @@ impl Indexer {
height: Height,
rem: bool,
exit: &Exit|
-> color_eyre::Result<()> {
-> color_eyre::Result<bool> {
if height == 0 || (height % SNAPSHOT_BLOCK_RANGE != 0) != rem || exit.triggered() {
return Ok(());
return Ok(false);
}
info!("Exporting...");
@@ -98,15 +99,88 @@ impl Indexer {
stores.commit(height)?;
vecs.flush(height)?;
exit.release();
Ok(())
Ok(true)
};
let mut txindex_to_first_outputindex_mmap_opt = None;
let mut p2pk65addressindex_to_p2pk65bytes_mmap_opt = None;
let mut p2pk33addressindex_to_p2pk33bytes_mmap_opt = None;
let mut p2pkhaddressindex_to_p2pkhbytes_mmap_opt = None;
let mut p2shaddressindex_to_p2shbytes_mmap_opt = None;
let mut p2wpkhaddressindex_to_p2wpkhbytes_mmap_opt = None;
let mut p2wshaddressindex_to_p2wshbytes_mmap_opt = None;
let mut p2traddressindex_to_p2trbytes_mmap_opt = None;
let mut p2aaddressindex_to_p2abytes_mmap_opt = None;
let reset_mmaps_options =
|vecs: &mut Vecs,
txindex_to_first_outputindex_mmap_opt: &mut Option<Mmap>,
p2pk65addressindex_to_p2pk65bytes_mmap_opt: &mut Option<Mmap>,
p2pk33addressindex_to_p2pk33bytes_mmap_opt: &mut Option<Mmap>,
p2pkhaddressindex_to_p2pkhbytes_mmap_opt: &mut Option<Mmap>,
p2shaddressindex_to_p2shbytes_mmap_opt: &mut Option<Mmap>,
p2wpkhaddressindex_to_p2wpkhbytes_mmap_opt: &mut Option<Mmap>,
p2wshaddressindex_to_p2wshbytes_mmap_opt: &mut Option<Mmap>,
p2traddressindex_to_p2trbytes_mmap_opt: &mut Option<Mmap>,
p2aaddressindex_to_p2abytes_mmap_opt: &mut Option<Mmap>| {
txindex_to_first_outputindex_mmap_opt
.replace(vecs.txindex_to_first_outputindex.create_mmap().unwrap());
p2pk65addressindex_to_p2pk65bytes_mmap_opt.replace(
vecs.p2pk65addressindex_to_p2pk65bytes
.create_mmap()
.unwrap(),
);
p2pk33addressindex_to_p2pk33bytes_mmap_opt.replace(
vecs.p2pk33addressindex_to_p2pk33bytes
.create_mmap()
.unwrap(),
);
p2pkhaddressindex_to_p2pkhbytes_mmap_opt
.replace(vecs.p2pkhaddressindex_to_p2pkhbytes.create_mmap().unwrap());
p2shaddressindex_to_p2shbytes_mmap_opt
.replace(vecs.p2shaddressindex_to_p2shbytes.create_mmap().unwrap());
p2wpkhaddressindex_to_p2wpkhbytes_mmap_opt.replace(
vecs.p2wpkhaddressindex_to_p2wpkhbytes
.create_mmap()
.unwrap(),
);
p2wshaddressindex_to_p2wshbytes_mmap_opt
.replace(vecs.p2wshaddressindex_to_p2wshbytes.create_mmap().unwrap());
p2traddressindex_to_p2trbytes_mmap_opt
.replace(vecs.p2traddressindex_to_p2trbytes.create_mmap().unwrap());
p2aaddressindex_to_p2abytes_mmap_opt
.replace(vecs.p2aaddressindex_to_p2abytes.create_mmap().unwrap());
};
reset_mmaps_options(
vecs,
&mut txindex_to_first_outputindex_mmap_opt,
&mut p2pk65addressindex_to_p2pk65bytes_mmap_opt,
&mut p2pk33addressindex_to_p2pk33bytes_mmap_opt,
&mut p2pkhaddressindex_to_p2pkhbytes_mmap_opt,
&mut p2shaddressindex_to_p2shbytes_mmap_opt,
&mut p2wpkhaddressindex_to_p2wpkhbytes_mmap_opt,
&mut p2wshaddressindex_to_p2wshbytes_mmap_opt,
&mut p2traddressindex_to_p2trbytes_mmap_opt,
&mut p2aaddressindex_to_p2abytes_mmap_opt,
);
parser.parse(start, end).iter().try_for_each(
|(height, block, blockhash)| -> color_eyre::Result<()> {
info!("Indexing block {height}...");
idxs.height = height;
let txindex_to_first_outputindex_mmap = txindex_to_first_outputindex_mmap_opt.as_ref().unwrap();
let p2pk65addressindex_to_p2pk65bytes_mmap = p2pk65addressindex_to_p2pk65bytes_mmap_opt.as_ref().unwrap();
let p2pk33addressindex_to_p2pk33bytes_mmap = p2pk33addressindex_to_p2pk33bytes_mmap_opt.as_ref().unwrap();
let p2pkhaddressindex_to_p2pkhbytes_mmap = p2pkhaddressindex_to_p2pkhbytes_mmap_opt.as_ref().unwrap();
let p2shaddressindex_to_p2shbytes_mmap = p2shaddressindex_to_p2shbytes_mmap_opt.as_ref().unwrap();
let p2wpkhaddressindex_to_p2wpkhbytes_mmap = p2wpkhaddressindex_to_p2wpkhbytes_mmap_opt.as_ref().unwrap();
let p2wshaddressindex_to_p2wshbytes_mmap = p2wshaddressindex_to_p2wshbytes_mmap_opt.as_ref().unwrap();
let p2traddressindex_to_p2trbytes_mmap = p2traddressindex_to_p2trbytes_mmap_opt.as_ref().unwrap();
let p2aaddressindex_to_p2abytes_mmap = p2aaddressindex_to_p2abytes_mmap_opt.as_ref().unwrap();
// Used to check rapidhash collisions
let check_collisions = check_collisions && height > Height::new(COLLISIONS_CHECKED_UP_TO);
@@ -166,9 +240,6 @@ impl Indexer {
});
let input_source_vec_handle = scope.spawn(|| {
let txindex_to_first_outputindex_mmap = vecs
.txindex_to_first_outputindex.mmap().load();
let inputs = block
.txdata
.iter()
@@ -211,7 +282,7 @@ impl Indexer {
let vout = Vout::from(outpoint.vout);
let outputindex = vecs.txindex_to_first_outputindex.get_or_read(prev_txindex, &txindex_to_first_outputindex_mmap)?
let outputindex = vecs.txindex_to_first_outputindex.get_or_read(prev_txindex, txindex_to_first_outputindex_mmap)?
.context("Expect outputindex to not be none")
.inspect_err(|_| {
dbg!(outpoint.txid, prev_txindex, vout);
@@ -240,16 +311,6 @@ impl Indexer {
})
});
let p2pk65addressindex_to_p2pk65bytes_mmap = vecs
.p2pk65addressindex_to_p2pk65bytes.mmap().load();
let p2pk33addressindex_to_p2pk33bytes_mmap = vecs.p2pk33addressindex_to_p2pk33bytes.mmap().load();
let p2pkhaddressindex_to_p2pkhbytes_mmap = vecs.p2pkhaddressindex_to_p2pkhbytes.mmap().load();
let p2shaddressindex_to_p2shbytes_mmap = vecs.p2shaddressindex_to_p2shbytes.mmap().load();
let p2wpkhaddressindex_to_p2wpkhbytes_mmap = vecs.p2wpkhaddressindex_to_p2wpkhbytes.mmap().load();
let p2wshaddressindex_to_p2wshbytes_mmap = vecs.p2wshaddressindex_to_p2wshbytes.mmap().load();
let p2traddressindex_to_p2trbytes_mmap = vecs.p2traddressindex_to_p2trbytes.mmap().load();
let p2aaddressindex_to_p2abytes_mmap = vecs.p2aaddressindex_to_p2abytes.mmap().load();
let outputs = block
.txdata
.iter()
@@ -307,35 +368,35 @@ impl Indexer {
let prev_addressbytes_opt = match outputtype {
OutputType::P2PK65 => vecs
.p2pk65addressindex_to_p2pk65bytes
.get_or_read(typeindex.into(), &p2pk65addressindex_to_p2pk65bytes_mmap)?
.get_or_read(typeindex.into(), p2pk65addressindex_to_p2pk65bytes_mmap)?
.map(|v| AddressBytes::from(v.into_owned())),
OutputType::P2PK33 => vecs
.p2pk33addressindex_to_p2pk33bytes
.get_or_read(typeindex.into(), &p2pk33addressindex_to_p2pk33bytes_mmap)?
.get_or_read(typeindex.into(), p2pk33addressindex_to_p2pk33bytes_mmap)?
.map(|v| AddressBytes::from(v.into_owned())),
OutputType::P2PKH => vecs
.p2pkhaddressindex_to_p2pkhbytes
.get_or_read(typeindex.into(), &p2pkhaddressindex_to_p2pkhbytes_mmap)?
.get_or_read(typeindex.into(), p2pkhaddressindex_to_p2pkhbytes_mmap)?
.map(|v| AddressBytes::from(v.into_owned())),
OutputType::P2SH => vecs
.p2shaddressindex_to_p2shbytes
.get_or_read(typeindex.into(), &p2shaddressindex_to_p2shbytes_mmap)?
.get_or_read(typeindex.into(), p2shaddressindex_to_p2shbytes_mmap)?
.map(|v| AddressBytes::from(v.into_owned())),
OutputType::P2WPKH => vecs
.p2wpkhaddressindex_to_p2wpkhbytes
.get_or_read(typeindex.into(), &p2wpkhaddressindex_to_p2wpkhbytes_mmap)?
.get_or_read(typeindex.into(), p2wpkhaddressindex_to_p2wpkhbytes_mmap)?
.map(|v| AddressBytes::from(v.into_owned())),
OutputType::P2WSH => vecs
.p2wshaddressindex_to_p2wshbytes
.get_or_read(typeindex.into(), &p2wshaddressindex_to_p2wshbytes_mmap)?
.get_or_read(typeindex.into(), p2wshaddressindex_to_p2wshbytes_mmap)?
.map(|v| AddressBytes::from(v.into_owned())),
OutputType::P2TR => vecs
.p2traddressindex_to_p2trbytes
.get_or_read(typeindex.into(), &p2traddressindex_to_p2trbytes_mmap)?
.get_or_read(typeindex.into(), p2traddressindex_to_p2trbytes_mmap)?
.map(|v| AddressBytes::from(v.into_owned())),
OutputType::P2A => vecs
.p2aaddressindex_to_p2abytes
.get_or_read(typeindex.into(), &p2aaddressindex_to_p2abytes_mmap)?
.get_or_read(typeindex.into(), p2aaddressindex_to_p2abytes_mmap)?
.map(|v| AddressBytes::from(v.into_owned())),
OutputType::Empty | OutputType::OpReturn | OutputType::P2MS | OutputType::Unknown => {
unreachable!()
@@ -677,7 +738,22 @@ impl Indexer {
idxs.inputindex += InputIndex::from(inputs_len);
idxs.outputindex += OutputIndex::from(outputs_len);
export_if_needed(stores, vecs, height, false, exit)?;
let exported = export_if_needed(stores, vecs, height, false, exit)?;
if exported {
reset_mmaps_options(
vecs,
&mut txindex_to_first_outputindex_mmap_opt,
&mut p2pk65addressindex_to_p2pk65bytes_mmap_opt,
&mut p2pk33addressindex_to_p2pk33bytes_mmap_opt,
&mut p2pkhaddressindex_to_p2pkhbytes_mmap_opt,
&mut p2shaddressindex_to_p2shbytes_mmap_opt,
&mut p2wpkhaddressindex_to_p2wpkhbytes_mmap_opt,
&mut p2wshaddressindex_to_p2wshbytes_mmap_opt,
&mut p2traddressindex_to_p2trbytes_mmap_opt,
&mut p2aaddressindex_to_p2abytes_mmap_opt,
);
}
Ok(())
},
+8 -8
View File
@@ -72,7 +72,7 @@ impl Stores {
path,
"p2aaddressindex_with_outputindex",
version + VERSION + Version::ZERO,
Some(None),
Some(false),
)
});
let p2pk33addressindex_with_outputindex = scope.spawn(|| {
@@ -81,7 +81,7 @@ impl Stores {
path,
"p2pk33addressindex_with_outputindex",
version + VERSION + Version::ZERO,
Some(None),
Some(false),
)
});
let p2pk65addressindex_with_outputindex = scope.spawn(|| {
@@ -90,7 +90,7 @@ impl Stores {
path,
"p2pk65addressindex_with_outputindex",
version + VERSION + Version::ZERO,
Some(None),
Some(false),
)
});
let p2pkhaddressindex_with_outputindex = scope.spawn(|| {
@@ -99,7 +99,7 @@ impl Stores {
path,
"p2pkhaddressindex_with_outputindex",
version + VERSION + Version::ZERO,
Some(None),
Some(false),
)
});
let p2shaddressindex_with_outputindex = scope.spawn(|| {
@@ -108,7 +108,7 @@ impl Stores {
path,
"p2shaddressindex_with_outputindex",
version + VERSION + Version::ZERO,
Some(None),
Some(false),
)
});
let p2traddressindex_with_outputindex = scope.spawn(|| {
@@ -117,7 +117,7 @@ impl Stores {
path,
"p2traddressindex_with_outputindex",
version + VERSION + Version::ZERO,
Some(None),
Some(false),
)
});
let p2wpkhaddressindex_with_outputindex = scope.spawn(|| {
@@ -126,7 +126,7 @@ impl Stores {
path,
"p2wpkhaddressindex_with_outputindex",
version + VERSION + Version::ZERO,
Some(None),
Some(false),
)
});
let p2wshaddressindex_with_outputindex = scope.spawn(|| {
@@ -135,7 +135,7 @@ impl Stores {
path,
"p2wshaddressindex_with_outputindex",
version + VERSION + Version::ZERO,
Some(None),
Some(false),
)
});
-8
View File
@@ -47,11 +47,3 @@ Verify that it has access to BRK's tools.
Optionally and highly recommended, giving it unsupervised access gives a more fluid experience and prevents possible issues and errors.
![Image of edit integration meny on Claude Desktop](https://github.com/bitcoinresearchkit/brk/blob/main/assets/claude-step4.png)
#### Results
Some examples of dashboard and documents generated by Claude using BRK's tools:
- [Document](https://claude.ai/public/artifacts/71194d29-f965-417c-ba09-fdf0e4ecb1d5)
- [Dashboard](https://claude.ai/public/artifacts/beef143f-399a-4ed4-b8bf-c986b776de42)
- [Dashboard2](https://claude.ai/public/artifacts/5430ae49-bb3d-4fc1-ab24-f1e33deb40dc)
+16 -19
View File
@@ -34,11 +34,9 @@ pub struct Store<Key, Value> {
rtx: ReadTransaction,
puts: BTreeMap<Key, Value>,
dels: BTreeSet<Key>,
bloom_filter_bits: Option<Option<u8>>,
bloom_filters: Option<bool>,
}
/// Use default if will read
const DEFAULT_BLOOM_FILTER_BITS: Option<u8> = Some(5);
// const CHECK_COLLISIONS: bool = true;
const MAJOR_FJALL_VERSION: Version = Version::TWO;
@@ -59,7 +57,7 @@ where
path: &Path,
name: &str,
version: Version,
bloom_filter_bits: Option<Option<u8>>,
bloom_filters: Option<bool>,
) -> Result<Self> {
fs::create_dir_all(path)?;
@@ -68,7 +66,7 @@ where
&path.join(format!("meta/{name}")),
MAJOR_FJALL_VERSION + version,
|| {
Self::open_partition_handle(keyspace, name, bloom_filter_bits).inspect_err(|e| {
Self::open_partition_handle(keyspace, name, bloom_filters).inspect_err(|e| {
eprintln!("{e}");
eprintln!("Delete {path:?} and try again");
})
@@ -85,7 +83,7 @@ where
rtx,
puts: BTreeMap::new(),
dels: BTreeSet::new(),
bloom_filter_bits,
bloom_filters,
})
}
@@ -180,17 +178,17 @@ where
fn open_partition_handle(
keyspace: &TransactionalKeyspace,
name: &str,
bloom_filter_bits: Option<Option<u8>>,
bloom_filters: Option<bool>,
) -> Result<TransactionalPartitionHandle> {
keyspace
.open_partition(
name,
PartitionCreateOptions::default()
.bloom_filter_bits(bloom_filter_bits.unwrap_or(DEFAULT_BLOOM_FILTER_BITS))
.max_memtable_size(8 * 1024 * 1024)
.manual_journal_persist(true),
)
.map_err(|e| e.into())
let mut options = PartitionCreateOptions::default()
.max_memtable_size(8 * 1024 * 1024)
.manual_journal_persist(true);
if bloom_filters.is_some_and(|b| !b) {
options = options.bloom_filter_bits(None);
}
keyspace.open_partition(name, options).map_err(|e| e.into())
}
pub fn commit_(
@@ -272,8 +270,7 @@ where
self.meta.reset();
let partition =
Self::open_partition_handle(&self.keyspace, self.name, self.bloom_filter_bits)?;
let partition = Self::open_partition_handle(&self.keyspace, self.name, self.bloom_filters)?;
self.partition.replace(partition);
@@ -314,7 +311,7 @@ where
rtx: self.keyspace.read_tx(),
puts: self.puts.clone(),
dels: self.dels.clone(),
bloom_filter_bits: self.bloom_filter_bits,
bloom_filters: self.bloom_filters,
}
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ brk_exit = { workspace = true }
clap = { workspace = true }
clap_derive = { workspace = true }
log = { workspace = true }
memmap2 = "0.9.5"
memmap2 = "0.9.7"
rayon = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
+10 -3
View File
@@ -1,16 +1,18 @@
use std::{fs, path::Path};
use brk_core::{DateIndex, Height, Version};
use brk_core::{DateIndex, Height, Printable, Version};
use brk_vec::{AnyVec, CollectableVec, Format, GenericStoredVec, StoredVec, VecIterator};
type I = DateIndex;
#[allow(clippy::upper_case_acronyms)]
type VEC = StoredVec<DateIndex, u32>;
type VEC = StoredVec<I, u32>;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _ = fs::remove_dir_all("./vec");
let _ = fs::remove_file("./vec");
let version = Version::TWO;
let format = Format::Compressed;
let format = Format::Raw;
{
let mut vec: VEC = StoredVec::forced_import(Path::new("."), "vec", version, format)?;
@@ -21,6 +23,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut iter = vec.into_iter();
dbg!(iter.get(0.into()));
dbg!(iter.get(1.into()));
dbg!(iter.get(2.into()));
dbg!(iter.get(20.into()));
dbg!(iter.get(21.into()));
@@ -38,6 +42,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
dbg!(iter.get(0.into()));
dbg!(iter.get(1.into()));
dbg!(iter.get(2.into()));
dbg!(iter.get(3.into()));
dbg!(iter.get(4.into()));
dbg!(iter.get(5.into()));
dbg!(iter.get(20.into()));
dbg!(iter.get(20.into()));
dbg!(iter.get(0.into()));
+21 -9
View File
@@ -7,7 +7,6 @@ use std::{
use arc_swap::ArcSwap;
use brk_core::{Error, Height, Result, Version};
use memmap2::Mmap;
use zerocopy::{FromBytes, IntoBytes};
use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout};
@@ -31,8 +30,12 @@ impl Header {
})
}
pub fn import_and_verify(mmap: &Mmap, vec_version: Version, format: Format) -> Result<Self> {
let inner = HeaderInner::import_and_verify(mmap, vec_version, format)?;
pub fn import_and_verify(
file: &mut File,
vec_version: Version,
format: Format,
) -> Result<Self> {
let inner = HeaderInner::import_and_verify(file, vec_version, format)?;
Ok(Self {
inner: Arc::new(ArcSwap::from_pointee(inner)),
modified: false,
@@ -100,7 +103,6 @@ impl HeaderInner {
compressed: ZeroCopyBool::from(format),
};
header.write(file)?;
// dbg!(file.bytes().map(|b| b.unwrap()).collect::<Vec<_>>());
file.seek(SeekFrom::End(0))?;
Ok(header)
}
@@ -109,13 +111,22 @@ impl HeaderInner {
file.write_all_at(self.as_bytes(), 0)
}
pub fn import_and_verify(mmap: &Mmap, vec_version: Version, format: Format) -> Result<Self> {
if mmap.len() < HEADER_OFFSET {
pub fn import_and_verify(
file: &mut File,
vec_version: Version,
format: Format,
) -> Result<Self> {
let len = file.metadata()?.len();
if len < HEADER_OFFSET as u64 {
return Err(Error::WrongLength);
}
// dbg!(mmap.len());
let header = HeaderInner::read_from_bytes(&mmap[..HEADER_OFFSET])?;
// dbg!(&header);
let mut buf = [0; HEADER_OFFSET];
file.read_exact_at(&mut buf, 0)?;
let header = HeaderInner::read_from_bytes(&buf)?;
if header.header_version != HEADER_VERSION {
return Err(Error::DifferentVersion {
found: header.header_version,
@@ -136,6 +147,7 @@ impl HeaderInner {
{
return Err(Error::DifferentCompressionMode);
}
Ok(header)
}
}
+7 -16
View File
@@ -3,10 +3,8 @@ use std::{
fs::{File, OpenOptions},
io::{self, Seek, SeekFrom, Write},
path::{Path, PathBuf},
sync::Arc,
};
use arc_swap::ArcSwap;
use brk_core::Result;
use memmap2::Mmap;
@@ -38,7 +36,7 @@ where
}
#[inline]
fn get_or_read_(&self, index: usize, mmap: &Mmap) -> Result<Option<Cow<T>>> {
let stored_len = self.stored_len_(mmap);
let stored_len = self.stored_len();
if index >= stored_len {
let pushed = self.pushed();
@@ -61,10 +59,7 @@ where
format!("{}_to_{}", I::to_string(), self.name())
}
fn mmap(&self) -> &ArcSwap<Mmap>;
fn stored_len(&self) -> usize;
fn stored_len_(&self, mmap: &Mmap) -> usize;
fn pushed(&self) -> &[T];
#[inline]
@@ -116,7 +111,7 @@ where
fn file_set_len(&mut self, file: &mut File, len: u64) -> Result<()> {
Self::file_set_len_(file, len)?;
self.update_mmap(file)
Ok(())
}
fn file_set_len_(file: &mut File, len: u64) -> Result<()> {
file.set_len(len)?;
@@ -127,7 +122,7 @@ where
fn file_write_all(&mut self, file: &mut File, buf: &[u8]) -> Result<()> {
file.write_all(buf)?;
file.flush()?;
self.update_mmap(file)
Ok(())
}
fn file_truncate_and_write_all(&mut self, file: &mut File, len: u64, buf: &[u8]) -> Result<()> {
@@ -143,14 +138,10 @@ where
self.file_truncate_and_write_all(&mut file, HEADER_OFFSET as u64, &[])
}
fn new_mmap(file: &File) -> Result<Arc<Mmap>> {
Ok(Arc::new(unsafe { Mmap::map(file)? }))
}
fn update_mmap(&mut self, file: &File) -> Result<()> {
let mmap = Self::new_mmap(file)?;
self.mmap().store(mmap);
Ok(())
#[inline]
fn create_mmap(&self) -> Result<Mmap> {
let file = self.open_file()?;
unsafe { Mmap::map(&file).map_err(|e| e.into()) }
}
#[inline]
+33 -43
View File
@@ -57,7 +57,7 @@ where
}
pub fn import(parent: &Path, name: &str, version: Version) -> Result<Self> {
let inner = RawVec::import(parent, name, version)?;
let mut inner = RawVec::import(parent, name, version)?;
let pages_meta = {
let path = inner
@@ -66,12 +66,19 @@ where
if inner.is_empty() {
let _ = fs::remove_file(&path);
}
Arc::new(ArcSwap::new(Arc::new(CompressedPagesMetadata::read(
&path,
)?)))
CompressedPagesMetadata::read(&path)?
};
Ok(Self { inner, pages_meta })
inner.set_stored_len(if let Some(last) = pages_meta.last() {
(pages_meta.len() - 1) * Self::PER_PAGE + last.values_len as usize
} else {
0
});
Ok(Self {
inner,
pages_meta: Arc::new(ArcSwap::new(Arc::new(pages_meta))),
})
}
fn decode_page(&self, page_index: usize, mmap: &Mmap) -> Result<Vec<T>> {
@@ -130,14 +137,6 @@ where
page_index * Self::PER_PAGE
}
fn stored_len__(pages_meta: &Guard<Arc<CompressedPagesMetadata>>) -> usize {
if let Some(last) = pages_meta.last() {
(pages_meta.len() - 1) * Self::PER_PAGE + last.values_len as usize
} else {
0
}
}
#[inline]
pub fn iter(&self) -> CompressedVecIterator<'_, I, T> {
self.into_iter()
@@ -180,22 +179,13 @@ where
self.inner.mut_header()
}
#[inline]
fn mmap(&self) -> &ArcSwap<Mmap> {
self.inner.mmap()
}
fn parent(&self) -> &Path {
self.inner.parent()
}
#[inline]
fn stored_len(&self) -> usize {
Self::stored_len__(&self.pages_meta.load())
}
#[inline]
fn stored_len_(&self, _: &Mmap) -> usize {
self.stored_len()
self.inner.stored_len()
}
#[inline]
@@ -223,6 +213,8 @@ where
let stored_len = self.stored_len();
let mut file = file_opt.unwrap_or(self.open_file()?);
let mut pages_meta = (**self.pages_meta.load()).clone();
let mut starting_page_index = pages_meta.len();
@@ -236,16 +228,13 @@ where
let last_page_index = pages_meta.len() - 1;
values = Self::decode_page_(
stored_len,
last_page_index,
&self.mmap().load(),
&pages_meta,
)
.inspect_err(|_| {
dbg!(last_page_index, &pages_meta);
})
.unwrap();
let mmap = unsafe { Mmap::map(&file)? };
values = Self::decode_page_(stored_len, last_page_index, &mmap, &pages_meta)
.inspect_err(|_| {
dbg!(last_page_index, &pages_meta);
})
.unwrap();
truncate_at.replace(pages_meta.pop().unwrap().start);
starting_page_index = last_page_index;
@@ -287,8 +276,6 @@ where
pages_meta.write()?;
let mut file = file_opt.unwrap_or(self.open_file()?);
if let Some(truncate_at) = truncate_at {
self.file_set_len(&mut file, truncate_at)?;
}
@@ -324,7 +311,11 @@ where
let page_index = Self::index_to_page_index(index);
let values = self.decode_page(page_index, &self.mmap().load())?;
let mut file = self.open_file()?;
let mmap = unsafe { Mmap::map(&file)? };
let values = self.decode_page(page_index, &mmap)?;
let mut buf = vec![];
let mut page = pages_meta.truncate(page_index).unwrap();
@@ -348,8 +339,6 @@ where
self.pages_meta.store(Arc::new(pages_meta));
let mut file = self.open_file()?;
self.file_truncate_and_write_all(&mut file, len, &buf)?;
Ok(())
@@ -399,7 +388,7 @@ impl<I, T> Clone for CompressedVec<I, T> {
#[derive(Debug)]
pub struct CompressedVecIterator<'a, I, T> {
vec: &'a CompressedVec<I, T>,
guard: Guard<Arc<Mmap>>,
mmap: Mmap,
decoded_page: Option<(usize, Vec<T>)>,
// second_decoded_page?: Option<(usize, Vec<T>)>,
pages_meta: Guard<Arc<CompressedPagesMetadata>>,
@@ -445,7 +434,7 @@ where
type Item = (I, Cow<'a, T>);
fn next(&mut self) -> Option<Self::Item> {
let mmap = &self.guard;
let mmap = &self.mmap;
let i = self.index;
let stored_len = self.stored_len;
@@ -496,14 +485,15 @@ where
fn into_iter(self) -> Self::IntoIter {
let pages_meta = self.pages_meta.load();
let stored_len = CompressedVec::<I, T>::stored_len__(&pages_meta);
let stored_len = self.stored_len();
CompressedVecIterator {
vec: self,
guard: self.mmap().load(),
mmap: self.create_mmap().unwrap(),
decoded_page: None,
pages_meta,
stored_len,
index: 0,
stored_len,
}
}
}
-5
View File
@@ -8,7 +8,6 @@ use std::{
path::{Path, PathBuf},
};
use arc_swap::ArcSwap;
use brk_core::{
Bitcoin, CheckedSub, Close, Date, DateIndex, Dollars, Error, Result, Sats, StoredF32,
StoredUsize, Version,
@@ -108,10 +107,6 @@ where
self.0.get_or_read(index, mmap)
}
pub fn mmap(&self) -> &ArcSwap<Mmap> {
self.0.mmap()
}
pub fn inner_version(&self) -> Version {
self.0.version()
}
+2 -3
View File
@@ -1,6 +1,5 @@
use std::{borrow::Cow, cmp::Ordering, fmt::Debug, path::Path};
use arc_swap::ArcSwap;
use brk_core::{Error, Height, Result, Version};
use crate::{
@@ -78,8 +77,8 @@ where
self.0.header()
}
pub fn mmap(&self) -> &ArcSwap<Mmap> {
self.0.mmap()
pub fn create_mmap(&self) -> Result<Mmap> {
self.0.create_mmap()
}
#[inline]
+47 -32
View File
@@ -5,10 +5,12 @@ use std::{
marker::PhantomData,
mem,
path::{Path, PathBuf},
sync::Arc,
sync::{
Arc,
atomic::{AtomicUsize, Ordering},
},
};
use arc_swap::{ArcSwap, Guard};
use brk_core::{Error, Result, Version};
use memmap2::Mmap;
use rayon::prelude::*;
@@ -25,9 +27,9 @@ pub struct RawVec<I, T> {
header: Header,
parent: PathBuf,
name: &'static str,
// Consider Arc<ArcSwap<Option<Mmap>>> for dataraces when reorg ?
mmap: Arc<ArcSwap<Mmap>>,
pushed: Vec<T>,
local_stored_len: Option<usize>,
shared_stored_len: Arc<AtomicUsize>,
phantom: PhantomData<I>,
}
@@ -55,16 +57,18 @@ where
pub fn import(parent: &Path, name: &str, version: Version) -> Result<Self> {
let path = Self::path_(parent, name);
let (mmap, header) = match Self::open_file_(&path) {
let (header, file) = match Self::open_file_(&path) {
Ok(mut file) => {
if file.metadata()?.len() == 0 {
let header = Header::create_and_write(&mut file, version, Format::Raw)?;
let mmap = Self::new_mmap(&file)?;
(mmap, header)
(
Header::create_and_write(&mut file, version, Format::Raw)?,
Some(file),
)
} else {
let mmap = Self::new_mmap(&file)?;
let header = Header::import_and_verify(&mmap, version, Format::Raw)?;
(mmap, header)
(
Header::import_and_verify(&mut file, version, Format::Raw)?,
Some(file),
)
}
}
Err(e) => match e.kind() {
@@ -72,25 +76,36 @@ where
fs::create_dir_all(Self::folder_(parent, name))?;
let mut file = Self::open_file_(&path)?;
let header = Header::create_and_write(&mut file, version, Format::Raw)?;
let mmap = Self::new_mmap(&file)?;
(mmap, header)
(header, None)
}
_ => {
return Err(e.into());
}
_ => return Err(e.into()),
},
};
let mmap = Arc::new(ArcSwap::new(mmap));
let stored_len = if let Some(file) = file {
(file.metadata()?.len() as usize - HEADER_OFFSET) / Self::SIZE_OF_T
} else {
0
};
Ok(Self {
mmap,
header,
name: Box::leak(Box::new(name.to_string())),
parent: parent.to_owned(),
pushed: vec![],
local_stored_len: Some(stored_len),
shared_stored_len: Arc::new(AtomicUsize::new(stored_len)),
phantom: PhantomData,
})
}
pub fn set_stored_len(&mut self, len: usize) {
self.local_stored_len.replace(len);
self.shared_stored_len.store(len, Ordering::Relaxed);
}
#[inline]
pub fn iter(&self) -> RawVecIterator<'_, I, T> {
self.into_iter()
@@ -141,18 +156,10 @@ where
&mut self.header
}
#[inline]
fn mmap(&self) -> &ArcSwap<Mmap> {
&self.mmap
}
#[inline]
fn stored_len(&self) -> usize {
self.stored_len_(&self.mmap.load())
}
#[inline]
fn stored_len_(&self, mmap: &Mmap) -> usize {
(mmap.len() - HEADER_OFFSET) / Self::SIZE_OF_T
self.local_stored_len
.unwrap_or_else(|| self.shared_stored_len.load(Ordering::Relaxed))
}
#[inline]
@@ -194,9 +201,14 @@ where
};
let mut file = file_opt.unwrap_or(self.open_file()?);
self.file_write_all(&mut file, &bytes)?;
if let Some(local_stored_len) = self.local_stored_len.as_mut() {
*local_stored_len += pushed_len;
}
self.shared_stored_len
.fetch_add(pushed_len, Ordering::Relaxed);
Ok(())
}
@@ -212,6 +224,8 @@ where
return Ok(());
}
self.set_stored_len(index);
let len = index * Self::SIZE_OF_T + HEADER_OFFSET;
let mut file = self.open_file()?;
@@ -221,6 +235,7 @@ where
}
fn reset(&mut self) -> Result<()> {
self.set_stored_len(0);
self.reset_()
}
}
@@ -262,9 +277,10 @@ impl<I, T> Clone for RawVec<I, T> {
header: self.header.clone(),
parent: self.parent.clone(),
name: self.name,
mmap: self.mmap.clone(),
pushed: vec![],
phantom: PhantomData,
local_stored_len: None,
shared_stored_len: self.shared_stored_len.clone(),
}
}
}
@@ -272,7 +288,7 @@ impl<I, T> Clone for RawVec<I, T> {
#[derive(Debug)]
pub struct RawVecIterator<'a, I, T> {
vec: &'a RawVec<I, T>,
guard: Guard<Arc<Mmap>>,
mmap: Mmap,
index: usize,
}
@@ -305,12 +321,11 @@ where
type Item = (I, Cow<'a, T>);
fn next(&mut self) -> Option<Self::Item> {
let mmap = &self.guard;
let index = self.index;
let opt = self
.vec
.get_or_read_(index, mmap)
.get_or_read_(index, &self.mmap)
.unwrap()
.map(|v| (I::from(index), v));
@@ -333,7 +348,7 @@ where
fn into_iter(self) -> Self::IntoIter {
RawVecIterator {
vec: self,
guard: self.mmap.load(),
mmap: self.create_mmap().unwrap(),
index: 0,
}
}
-16
View File
@@ -3,7 +3,6 @@ use std::{
path::{Path, PathBuf},
};
use arc_swap::ArcSwap;
use brk_core::{Result, Version};
use memmap2::Mmap;
@@ -75,14 +74,6 @@ where
}
}
#[inline]
fn mmap(&self) -> &ArcSwap<Mmap> {
match self {
StoredVec::Raw(v) => v.mmap(),
StoredVec::Compressed(v) => v.mmap(),
}
}
#[inline]
fn parent(&self) -> &Path {
match self {
@@ -98,13 +89,6 @@ where
StoredVec::Compressed(v) => v.stored_len(),
}
}
#[inline]
fn stored_len_(&self, mmap: &Mmap) -> usize {
match self {
StoredVec::Raw(v) => v.stored_len_(mmap),
StoredVec::Compressed(v) => v.stored_len_(mmap),
}
}
#[inline]
fn pushed(&self) -> &[T] {
+224 -216
View File
@@ -1227,78 +1227,82 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
name: legend,
color,
}),
createBaseSeries({
key: `${key}_ratio_p1sd_as_price`,
name: "+1σ",
color: colors.orange,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p2sd_as_price`,
name: "+2σ",
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p3sd_as_price`,
name: "+3σ",
color: colors.pink,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_m1sd_as_price`,
name: "1σ",
color: colors.cyan,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_m2sd_as_price`,
name: "2σ",
color: colors.blue,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_m3sd_as_price`,
name: "3σ",
color: colors.violet,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p99_as_price`,
name: "p99",
color: colors.orange,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p99_5_as_price`,
name: "p99.5",
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p99_9_as_price`,
name: "p99.9",
color: colors.pink,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p1_as_price`,
name: "p1",
color: colors.cyan,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p0_5_as_price`,
name: "p0.5",
color: colors.blue,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p0_1_as_price`,
name: "p0.1",
color: colors.violet,
defaultActive: false,
}),
...(`${key}_ratio_p1sd_as_price` in vecIdToIndexes
? [
createBaseSeries({
key: `${key}_ratio_p1sd_as_price`,
name: "+1σ",
color: colors.orange,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p2sd_as_price`,
name: "+2σ",
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p3sd_as_price`,
name: "+3σ",
color: colors.pink,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_m1sd_as_price`,
name: "1σ",
color: colors.cyan,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_m2sd_as_price`,
name: "2σ",
color: colors.blue,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_m3sd_as_price`,
name: "3σ",
color: colors.violet,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p99_as_price`,
name: "p99",
color: colors.orange,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p99_5_as_price`,
name: "p99.5",
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p99_9_as_price`,
name: "p99.9",
color: colors.pink,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p1_as_price`,
name: "p1",
color: colors.cyan,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p0_5_as_price`,
name: "p0.5",
color: colors.blue,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p0_1_as_price`,
name: "p0.1",
color: colors.violet,
defaultActive: false,
}),
]
: []),
],
bottom: [
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
@@ -1312,150 +1316,154 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
},
},
}),
createBaseSeries({
key: `${key}_ratio_p1sd`,
name: "+1σ",
color: colors.orange,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p2sd`,
name: "+2σ",
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p3sd`,
name: "+3σ",
color: colors.pink,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_m1sd`,
name: "1σ",
color: colors.cyan,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_m2sd`,
name: "2σ",
color: colors.blue,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_m3sd`,
name: "3σ",
color: colors.violet,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p99`,
name: "p99",
color: colors.orange,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p99_5`,
name: "p99.5",
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p99_9`,
name: "p99.9",
color: colors.pink,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p1`,
name: "p1",
color: colors.cyan,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p0_5`,
name: "p0.5",
color: colors.blue,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p0_1`,
name: "p0.1",
color: colors.violet,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_1w_sma`,
name: "1w sma",
color: colors.fuchsia,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_1m_sma`,
name: "1m sma",
color: colors.pink,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_1y_sma`,
name: "1y sma",
color: colors.rose,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_4y_sma`,
name: "4y_sma",
color: colors.purple,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_sma`,
name: "sma",
color: colors.yellow,
defaultActive: false,
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
key: `${key}_ratio_1y_sma_momentum_oscillator`,
title: "1Y Momentum",
type: "Baseline",
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
key: `${key}_ratio_zscore`,
title: "All time",
type: "Baseline",
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
key: `${key}_ratio_4y_zscore`,
title: "4y",
type: "Baseline",
colors: [colors.yellow, colors.pink],
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
key: `${key}_ratio_1y_zscore`,
title: "1y",
type: "Baseline",
colors: [colors.orange, colors.purple],
options: {
createPriceLine: {
value: 0,
},
},
}),
...(`${key}_ratio_p1sd` in vecIdToIndexes
? [
createBaseSeries({
key: `${key}_ratio_p1sd`,
name: "+1σ",
color: colors.orange,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p2sd`,
name: "+2σ",
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p3sd`,
name: "+3σ",
color: colors.pink,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_m1sd`,
name: "1σ",
color: colors.cyan,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_m2sd`,
name: "2σ",
color: colors.blue,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_m3sd`,
name: "3σ",
color: colors.violet,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p99`,
name: "p99",
color: colors.orange,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p99_5`,
name: "p99.5",
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p99_9`,
name: "p99.9",
color: colors.pink,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p1`,
name: "p1",
color: colors.cyan,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p0_5`,
name: "p0.5",
color: colors.blue,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_p0_1`,
name: "p0.1",
color: colors.violet,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_1w_sma`,
name: "1w sma",
color: colors.fuchsia,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_1m_sma`,
name: "1m sma",
color: colors.pink,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_1y_sma`,
name: "1y sma",
color: colors.rose,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_4y_sma`,
name: "4y_sma",
color: colors.purple,
defaultActive: false,
}),
createBaseSeries({
key: `${key}_ratio_sma`,
name: "sma",
color: colors.yellow,
defaultActive: false,
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
key: `${key}_ratio_1y_sma_momentum_oscillator`,
title: "1Y Momentum",
type: "Baseline",
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
key: `${key}_ratio_zscore`,
title: "All time",
type: "Baseline",
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
key: `${key}_ratio_4y_zscore`,
title: "4y",
type: "Baseline",
colors: [colors.yellow, colors.pink],
options: {
createPriceLine: {
value: 0,
},
},
}),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
key: `${key}_ratio_1y_zscore`,
title: "1y",
type: "Baseline",
colors: [colors.orange, colors.purple],
options: {
createPriceLine: {
value: 0,
},
},
}),
]
: []),
],
};
}