← Back to ChaosTree

The Dragon Feed

"Every rev (factor) of the dragon is a warning. Every gearshift bears the load (memory). The dragon unleashes its might at 1.0f, packing your data into the map like it never even felt it."

The Dragon Feed is the internal bulk-loading engine of ChaosTree's B-Tree and B+Tree architectures. Instead of utilizing standard iterative insertions—which suffer from pointer chasing, tree rebalancing, and heavy GC allocation rates—the Dragon Feed directly ingests raw sorted matrices and compiles them into contiguous memory pages.

The Gears (Packing Factor)

The Dragon Feed exposes a factor parameter, acting as the transmission for the engine. It dictates exactly how tightly the internal arrays should be packed during bulk ingestion.

- 0.5f (First Gear): 50% capacity. Leaves room for future random insertions without triggering node splits. Highest initial memory footprint.
- 1.0f (Top Gear): 100% capacity. Zero wasted bytes. Maximum CPU cache line saturation. Pure throughput.

JMH Benchmarks (degree = 64)

Benchmark performed on: Intel Core i5-13450HX (16 cores), G1GC, default heap (5803 MB).

Two ingestion paths were measured. importFlatMatrix bulk-copies a pre-built sorted matrix directly into node arrays via System.arraycopy; buildFromSorted walks a sorted iterator (the same style of construction TreeMap uses) and builds nodes incrementally. All 30-fork averages, times in microseconds per operation.

Reproduce with:

java -jar ct-benchmark/target/benchmarks.jar WriteHeavyMap.bulkLoadBPlusTree \
    -p size=10000,100000,1000000,10000000 \
    -p factor=0.5f,0.75f,1.0f \
    -f 3 -wi 10 -w 1 -r 1 -i 10 -tu us -rf text -rff bulkLoad.txt

java -jar ct-benchmark/target/benchmarks.jar WriteHeavyMap.importFlatMatrixBPlusTree \
    -p size=10000,100000,1000000,10000000 \
    -p factor=0.5f,0.75f,1.0f \
    -f 3 -wi 10 -w 1 -r 1 -i 10 -tu us -rf text -rff dragonFeed.txt

importFlatMatrix — arraycopy-based bulk import

Factor 10,000 100,000 1,000,000 10,000,000
0.5f 11.545 ± 0.166 145.733 ± 0.895 1466.230 ± 7.196 16729.324 ± 511.749
0.75f 9.700 ± 0.121 98.792 ± 0.499 1015.293 ± 4.962 13006.075 ± 629.287
1.0f 7.319 ± 0.032 75.207 ± 0.288 791.220 ± 16.122 9726.478 ± 109.668

All values in microseconds per operation, rows are factor, columns are size — read down a column to compare factors at fixed size, or across a row to see how a single factor scales with size.

Packing factor directly sizes the underlying flat array and resize threshold here, so it's a first-order effect: 1.0f beats 0.5f by roughly 35–42% across every size.

Factor vs. Memory — importFlatMatrix, size = 1,000,000

Same path, finer-grained factor sweep, with JMH's gc.alloc.rate.norm profiler enabled to see bytes allocated per op directly. Allocation drops almost linearly as factor rises — less slack per node means fewer nodes, which means less array overhead per element — and time tracks it closely.

java -jar ct-benchmark/target/benchmarks.jar WriteHeavyMap.importFlatMatrixBPlusTree \
    -p size=1000000 \
    -p factor=0.5f,0.6f,0.7f,0.8f,0.9f,1.0f \
    -f 3 -wi 10 -w 1 -r 1 -i 10 -tu ms -prof gc -rf text -rff dragonFeedMemory.txt
Factor Time (ms/op) Alloc Rate (MB/sec) Alloc/op (B/op) Tree Size (MB) GC Count GC Time (ms)
0.5f 1.483 ± 0.009 11273.263 ± 69.080 17538210.268 16.73 248 384
0.6f 1.241 ± 0.005 11213.114 ± 46.660 14592160.594 13.91 258 384
0.7f 1.097 ± 0.007 10976.941 ± 70.795 12628127.598 12.04 259 329
0.8f 0.954 ± 0.006 10950.163 ± 69.089 10952094.603 10.44 258 354
0.9f 0.845 ± 0.004 10901.292 ± 46.037 9664125.850 9.22 282 337
1.0f 0.777 ± 0.008 10682.879 ± 114.768 8701725.380 8.30 279 343

Tree Size (MB) is Alloc/op converted to MB — for a bulk import benchmark this is effectively the resident size of the built tree, since each op constructs one fresh tree from scratch. 0.5f → 1.0f shrinks it from 16.73 MB to 8.30 MB, roughly halving memory footprint for 1,000,000 entries, while time drops ~48% in step.

buildFromSorted — iterator-driven build

Factor 10,000 100,000 1,000,000 10,000,000
0.5f 74.251 ± 0.847 700.342 ± 15.937 7640.535 ± 68.402 82775.216 ± 4449.711
0.75f 72.601 ± 0.235 705.388 ± 14.247 7597.012 ± 35.819 83992.645 ± 4933.130
1.0f 73.762 ± 1.303 689.406 ± 6.192 7619.628 ± 46.503 84430.291 ± 5037.158

All values in microseconds per operation, same layout as above — down a column compares factors at fixed size, across a row shows one factor's scaling.

Here the three factors sit within each other's error bars at every size — packing density only controls node occupancy, and it's a second-order effect compared to the per-entry comparator/iterator/split cost that dominates this path.

Usage

1. By Constructor

// Use the Dragon at top gear (1.0f)
// It is advised to leave a space for future operation.
// 1. Prepare your sorted data matrix
Integer[] sortedKeys = {1, 2, 3, 4, 5};
String[] values = {"A", "B", "C", "D", "E"};
Object[][] matrix = new Object[][]{sortedKeys, values};

// 2. Feed the Dragon
BPlusTreeMap fastMap = new BPlusTreeMap<>(
    BPlusTreeMap.Builder.degree(64)
        .factor(0.8f) // 80% packing density, leaves room for runtime inserts
        .importFlatMatrix(matrix)
        .build()
);
    

2. By Public API through array

WARNING: THE TRUE DRAGON OF CHAOSTREE. This is a high-performance, Data-Oriented, cache-aware array ingestion engine. It is hungry for raw array throughput, but it is extremely unforgiving. Use with absolute precision. THE FLAT MATRIX RULES: Method: abstract void importFlatMatrix(Object[][] blast, float factor); Parameters: blast A 2D array where blast[0] is the sorted keys and blast[1] is the mapped values. factor The node fill factor, restricted to the range [0.5, 1.0].
    // Awaken the Dragon at top gear (1.0f)
    Object[][] blast = new Object[][]{sortedKeys, values};
    float factor = 1.0f;

    BPlusTreeMap<Integer, String> map = new BPlusTreeMap<>();
    //this creates a default degree of 64 and comparator null!
    map.importFlatMatrix(blast, factor);
    

3. By Public API through Sorted Map.Entry

Streams strictly sorted data directly into the tree in O(N) time.

WARNING: The provided iterator MUST yield elements in strict ascending order according to this tree's comparator. If the data is unsorted, the tree structure will be corrupted.

FILL FACTOR:

Parameters:

public void buildFromSorted(Iterator> it, float factor) The factor provide the node density [0.5f, 1f] more you pack the less it's take memory. Internally used in Serialization at a factor of 0.75f.
    // Use the Dragon at top gear (1.0f)
    BPlusTreeMap<Integer, String> map = new BPlusTreeMap<>();
    //this creates a default degree of 64 and comparator null!
    map.buildFromSorted(iterator, factor);