@cloudbitmaps/roaring 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PRIVACY.md +1 -1
- package/README.md +32 -4
- package/dist/bin/export-segments.js +1628 -211
- package/dist/bin/export-segments.js.map +4 -4
- package/dist/bitmap.d.ts +223 -0
- package/dist/index.d.ts +58 -6
- package/dist/index.js +1988 -198
- package/dist/index.js.map +4 -4
- package/package.json +2 -2
- package/dist/roaring-codec.d.ts +0 -49
package/PRIVACY.md
CHANGED
|
@@ -173,7 +173,7 @@ A call with a feed reads operands the library never stores, which no erasure can
|
|
|
173
173
|
Erasure and crypto-shred are **immediate in storage and immediate in the store whose verb performed them**, for
|
|
174
174
|
every read that starts after the verb returns. A read already in progress in that store can still yield an erased id
|
|
175
175
|
from a chunk it had requested before the verb ran: up to 32 chunks for `iterate` and `count`, and up to `concurrency` + 1
|
|
176
|
-
keys (33 by default) for a combine. That is the bound: the chunk or key a read is handing out and what it had already requested, which a `count` that reads chunks (on a source with no index of its own) reaches. A running `iterate` or combine on the library's own sources stops sooner: the verb invalidates the segment, so before the next key it takes the read lists its chunk keys again from the generation current then and drops what it had requested, and so yields the id only from the chunk or key it is handing out. A combine or `iterate` reads ranges of the object, and resolves the segment again before it serves each chunk, one held in its cache included, as a read of that chunk alone does, so the ranges it had already requested are dropped, not served. A pinned read in progress does not move to the rewritten generation: before its next chunk it opens its object again, and fails with `NotFoundError` once the erasure has deleted it, so it yields no more than that bound either. They are not immediate in any *other* store, in the same process or another, and this library ships nothing that could
|
|
176
|
+
keys (33 by default) for a combine or a count of a combine. That is the bound: the chunk or key a read is handing out and what it had already requested, which a `count` that reads chunks (on a source with no index of its own) reaches. A running `iterate` or combine on the library's own sources stops sooner: the verb invalidates the segment, so before the next key it takes the read lists its chunk keys again from the generation current then and drops what it had requested, and so yields the id only from the chunk or key it is handing out. A combine or `iterate` reads ranges of the object, and resolves the segment again before it serves each chunk, one held in its cache included, as a read of that chunk alone does, so the ranges it had already requested are dropped, not served. A pinned read in progress does not move to the rewritten generation: before its next chunk it opens its object again, and fails with `NotFoundError` once the erasure has deleted it, so it yields no more than that bound either. They are not immediate in any *other* store, in the same process or another, and this library ships nothing that could
|
|
177
177
|
make them so — there is no daemon, no bus, and no connection between two stores that happen to point at the same
|
|
178
178
|
bucket.
|
|
179
179
|
|
package/README.md
CHANGED
|
@@ -50,9 +50,37 @@ To persist, pass a different **backend** as `storage`. Nothing else changes:
|
|
|
50
50
|
| `GcsStorage({ bucket, prefix })` | `@cloudbitmaps/gcs` | Google Cloud Storage; outside the [validated envelope](https://github.com/cloudbitmaps/cloudbitmaps/blob/main/docs/ROADMAP.md#the-validated-envelope--whats-proven-and-what-isnt) |
|
|
51
51
|
| `AzureBlobStorage({ connectionString, container })` | `@cloudbitmaps/azure-blob` | Azure Blob Storage; outside the [validated envelope](https://github.com/cloudbitmaps/cloudbitmaps/blob/main/docs/ROADMAP.md#the-validated-envelope--whats-proven-and-what-isnt) |
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
`RoaringBitmap` is the codec's bitmap as a public class: a mutable set of unsigned 32-bit ids with the portable Roaring
|
|
54
|
+
bytes, in TypeScript with no native code. Import it from `@cloudbitmaps/roaring`, the same line as the store:
|
|
55
|
+
`import { CloudRoaring, MemoryStorage, RoaringBitmap } from '@cloudbitmaps/roaring'`. A store loads one as it is, and
|
|
56
|
+
`RoaringBitmap.deserialize(bytes)` is the one door for bytes you did not write.
|
|
57
|
+
|
|
58
|
+
Two calls are slower than the native `roaring` package by a ratio above 10 in the bench, and ship with their figures shown. The first `deserialize` in a fresh process has a measured ratio of about 14.6 (median 2.20 ms against 0.151 ms); it is a one-time cost of the first call (the expected reason is code not yet optimized plus compile time), and later decodes have measured ratios of 2.2 to 5.9 across the five data sets. The union of 64 dense bitmaps with `orMany` has a measured ratio of about 11. Every figure is in [the table](https://github.com/cloudbitmaps/cloudbitmaps/blob/main/docs/guide/roaring-codec.md#the-public-class-against-native-in-memory).
|
|
59
|
+
|
|
60
|
+
<!-- typecheck -->
|
|
61
|
+
```ts
|
|
62
|
+
import { CloudRoaring, MemoryStorage, RoaringBitmap } from '@cloudbitmaps/roaring';
|
|
63
|
+
|
|
64
|
+
const store = new CloudRoaring({ storage: new MemoryStorage() });
|
|
65
|
+
|
|
66
|
+
const vip = new RoaringBitmap([5, 99_999, 1_234_567_890]); // any iterable of ids
|
|
67
|
+
vip.add(7);
|
|
68
|
+
vip.removeMany([99_999]);
|
|
69
|
+
vip.addMany(new RoaringBitmap([8, 9])); // another bitmap, or a Uint32Array, works too
|
|
70
|
+
|
|
71
|
+
await store.load({ segment: 'vip' }, vip); // read, never changed or kept
|
|
72
|
+
|
|
73
|
+
// Bytes from another process go through the one safe door: capped, checked, one whole bitmap.
|
|
74
|
+
const received = RoaringBitmap.deserialize(vip.serialize());
|
|
75
|
+
console.log(received.size, received.minimum(), received.maximum()); // 5 5 1234567890
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
[The API reference](https://github.com/cloudbitmaps/cloudbitmaps/blob/main/docs/guide/api-reference.md#build-and-combine-bitmaps-by-themselves--roaringbitmap)
|
|
79
|
+
has every method and where it differs from the `roaring` package.
|
|
80
|
+
|
|
81
|
+
A stored segment has no `add` or `remove` (`RoaringBitmap` does, for a bitmap in memory): a segment changes only by loading a new generation. A load is a batch job, not a
|
|
54
82
|
request handler. `store.exists(ref)` says whether a segment has been loaded. A load takes ids, or a bitmap you already
|
|
55
|
-
hold: `store.load(ref,
|
|
83
|
+
hold: `store.load(ref, bitmap)` for a `RoaringBitmap` (or a `RoaringBitmap32`), or `{ serialized }` for portable Roaring bytes, checked
|
|
56
84
|
before anything is written and loaded with no per-id work, into a generation holding chunk for chunk what its ids would write (its footer carries its own write identity).
|
|
57
85
|
|
|
58
86
|
To write many results over the same stored operands, `store.materializeMany` reads each operand once for a whole batch of
|
|
@@ -77,8 +105,8 @@ name.
|
|
|
77
105
|
|
|
78
106
|
## What it costs
|
|
79
107
|
|
|
80
|
-
A cold `intersect` of two 500,000-id segments sharing 100 of their 1,999 chunks made 6 GETs and took
|
|
81
|
-
million** at list prices: measured on S3 in-region, in the run of 2026-10-
|
|
108
|
+
A cold `intersect` of two 500,000-id segments sharing 100 of their 1,999 chunks made 6 GETs and took 107.87 ms at the median, **$2.40 per
|
|
109
|
+
million** at list prices: measured on S3 in-region, in the run of 2026-10-30, whose client had 128 sockets. On a spread layout it reads more
|
|
82
110
|
bytes than it needs, which cross-region can cost more than the requests it saves. A segment's first single-part `store.load()` made
|
|
83
111
|
2 PUT + 3 GET, **$11.20 per million** at the default prices, pointer included: the requests are measured on S3 in-region, in the same run. A steady single-part `store.load()` at `keep: 12` that deletes a generation by name costs **$12.00 per million**, for 2 PUT + 5 GET and a free delete, the requests measured on S3 in-region, in the same run. A cold `count()` is one
|
|
84
112
|
pointer read: it reads no payload and no object.
|