pigeonhole-db 1.1.0 → 1.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6112428e9e5815a4ceab94e2ee520ef63d1ab237f87ffba0d1935183866b0daa
4
- data.tar.gz: 6acd6dfa278a29c0df775973b451686c1afbd3730832a6a493e87da7b4354d17
3
+ metadata.gz: 051ba1f3253f01d8bd59cf337efe6e202641359a46218ca9a4d9065bcc3174a9
4
+ data.tar.gz: 5928e6cc99b9ff647b075ae0cc27e5887513c199e55f0e758e565a98de3d0ba4
5
5
  SHA512:
6
- metadata.gz: 7381a5b7b08d209cfb4cd76b3fc0b9d3aba3b175811791b1abe1851bac9c47054196404c1d691b383272f2979a96984a9eda368b1c6846985517ac7d6eb459fa
7
- data.tar.gz: 6f7ca4131bae8d28edc5f858d8a2ef6d3a6eaf24f1f7113b80f51f19ab5d844e68a5d264b8bc15c37cfed3bdabc3c0219cd5e8700061cbfd7dbbb462ef56293b
6
+ metadata.gz: f98d422fbcb95b31b070ad293784b32cfdefefab8fca2e46b032d1b3058e382b903e783523738ed53a2401bfe27e82edce947e4061d623294b4fc93ed5901d30
7
+ data.tar.gz: 526bbec10351aaed21d260295f7460d57a63051a5bf738442aeb39f1d8ace6827496053dc81f40cba76c4dbd96ae6a8efd7b68c380d4cb75c621aad933329974
data/Cargo.lock CHANGED
@@ -367,7 +367,7 @@ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
367
367
 
368
368
  [[package]]
369
369
  name = "pigeonhole"
370
- version = "1.1.0"
370
+ version = "1.1.1"
371
371
  dependencies = [
372
372
  "arc-swap",
373
373
  "futures-core",
@@ -380,14 +380,14 @@ dependencies = [
380
380
 
381
381
  [[package]]
382
382
  name = "pigeonhole-cache"
383
- version = "2.0.0"
383
+ version = "2.0.1"
384
384
  dependencies = [
385
385
  "pigeonhole-io",
386
386
  ]
387
387
 
388
388
  [[package]]
389
389
  name = "pigeonhole-compaction"
390
- version = "2.0.0"
390
+ version = "2.0.1"
391
391
  dependencies = [
392
392
  "pigeonhole-cache",
393
393
  "pigeonhole-format",
@@ -398,7 +398,7 @@ dependencies = [
398
398
 
399
399
  [[package]]
400
400
  name = "pigeonhole-engine"
401
- version = "2.0.0"
401
+ version = "2.0.1"
402
402
  dependencies = [
403
403
  "arc-swap",
404
404
  "loom",
@@ -417,7 +417,7 @@ dependencies = [
417
417
 
418
418
  [[package]]
419
419
  name = "pigeonhole-format"
420
- version = "2.0.0"
420
+ version = "2.0.1"
421
421
  dependencies = [
422
422
  "crc-fast",
423
423
  "foldhash",
@@ -429,7 +429,7 @@ dependencies = [
429
429
 
430
430
  [[package]]
431
431
  name = "pigeonhole-io"
432
- version = "2.0.0"
432
+ version = "2.0.1"
433
433
  dependencies = [
434
434
  "io-uring",
435
435
  "libc",
@@ -440,7 +440,7 @@ dependencies = [
440
440
 
441
441
  [[package]]
442
442
  name = "pigeonhole-memory"
443
- version = "1.1.0"
443
+ version = "1.1.1"
444
444
  dependencies = [
445
445
  "getrandom 0.3.4",
446
446
  "pigeonhole",
@@ -451,7 +451,7 @@ dependencies = [
451
451
 
452
452
  [[package]]
453
453
  name = "pigeonhole-memtable"
454
- version = "2.0.0"
454
+ version = "2.0.1"
455
455
  dependencies = [
456
456
  "pigeonhole-format",
457
457
  "pigeonhole-io",
@@ -459,7 +459,7 @@ dependencies = [
459
459
 
460
460
  [[package]]
461
461
  name = "pigeonhole-pager"
462
- version = "2.0.0"
462
+ version = "2.0.1"
463
463
  dependencies = [
464
464
  "pigeonhole-format",
465
465
  "pigeonhole-io",
@@ -467,7 +467,7 @@ dependencies = [
467
467
 
468
468
  [[package]]
469
469
  name = "pigeonhole-ruby"
470
- version = "1.1.0"
470
+ version = "1.1.1"
471
471
  dependencies = [
472
472
  "magnus",
473
473
  "pigeonhole",
@@ -479,14 +479,14 @@ dependencies = [
479
479
 
480
480
  [[package]]
481
481
  name = "pigeonhole-runtime"
482
- version = "2.0.0"
482
+ version = "2.0.1"
483
483
  dependencies = [
484
484
  "pigeonhole-io",
485
485
  ]
486
486
 
487
487
  [[package]]
488
488
  name = "pigeonhole-shm"
489
- version = "2.0.0"
489
+ version = "2.0.1"
490
490
  dependencies = [
491
491
  "pigeonhole-format",
492
492
  "pigeonhole-io",
@@ -494,7 +494,7 @@ dependencies = [
494
494
 
495
495
  [[package]]
496
496
  name = "pigeonhole-sst"
497
- version = "2.0.0"
497
+ version = "2.0.1"
498
498
  dependencies = [
499
499
  "pigeonhole-cache",
500
500
  "pigeonhole-format",
@@ -503,7 +503,7 @@ dependencies = [
503
503
 
504
504
  [[package]]
505
505
  name = "pigeonhole-text"
506
- version = "1.1.0"
506
+ version = "1.1.1"
507
507
  dependencies = [
508
508
  "levenshtein_automata",
509
509
  "pigeonhole",
@@ -513,7 +513,7 @@ dependencies = [
513
513
 
514
514
  [[package]]
515
515
  name = "pigeonhole-vector"
516
- version = "1.1.0"
516
+ version = "1.1.1"
517
517
  dependencies = [
518
518
  "futures-core",
519
519
  "pigeonhole",
@@ -521,7 +521,7 @@ dependencies = [
521
521
 
522
522
  [[package]]
523
523
  name = "pigeonhole-wal"
524
- version = "2.0.0"
524
+ version = "2.0.1"
525
525
  dependencies = [
526
526
  "pigeonhole-format",
527
527
  "pigeonhole-io",
data/Cargo.toml CHANGED
@@ -5,16 +5,16 @@ features = ["bytes"]
5
5
  version = "0.9"
6
6
  [dependencies.pigeonhole]
7
7
  path = "vendor/pigeonhole"
8
- version = "1.1.0"
8
+ version = "1.1.1"
9
9
  [dependencies.pigeonhole-memory]
10
10
  path = "vendor/memory"
11
- version = "1.1.0"
11
+ version = "1.1.1"
12
12
  [dependencies.pigeonhole-text]
13
13
  path = "vendor/text"
14
- version = "1.1.0"
14
+ version = "1.1.1"
15
15
  [dependencies.pigeonhole-vector]
16
16
  path = "vendor/vector"
17
- version = "1.1.0"
17
+ version = "1.1.1"
18
18
  [dependencies.rb-sys]
19
19
  version = "0.9"
20
20
  [lib]
@@ -37,7 +37,7 @@ name = "pigeonhole-ruby"
37
37
  publish = false
38
38
  repository = "https://github.com/CodingAnarchy/pigeonhole"
39
39
  rust-version = "1.96"
40
- version = "1.1.0"
40
+ version = "1.1.1"
41
41
  [profile.release]
42
42
  codegen-units = 1
43
43
  lto = "thin"
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Pigeonhole
4
4
  # The gem's version: the `pigeonhole` crate's.
5
- VERSION = "1.1.0"
5
+ VERSION = "1.1.1"
6
6
  end
@@ -6,12 +6,12 @@ checking for whether -fvisibility=hidden is accepted as CFLAGS... yes
6
6
  creating Makefile
7
7
 
8
8
  current directory: /home/runner/work/pigeonhole/pigeonhole/crates/ruby/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/ext/prism
9
- make DESTDIR\= sitearchdir\=./.gem.20261104-2345-sni2nw sitelibdir\=./.gem.20261104-2345-sni2nw clean
9
+ make DESTDIR\= sitearchdir\=./.gem.20261105-2189-n76o6p sitelibdir\=./.gem.20261105-2189-n76o6p clean
10
10
 
11
11
  current directory: /home/runner/work/pigeonhole/pigeonhole/crates/ruby/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/ext/prism
12
- make DESTDIR\= sitearchdir\=./.gem.20261104-2345-sni2nw sitelibdir\=./.gem.20261104-2345-sni2nw
13
- compiling api_pack.c
12
+ make DESTDIR\= sitearchdir\=./.gem.20261105-2189-n76o6p sitelibdir\=./.gem.20261105-2189-n76o6p
14
13
  compiling api_node.c
14
+ compiling api_pack.c
15
15
  compiling extension.c
16
16
  compiling ./../../src/diagnostic.c
17
17
  compiling ./../../src/encoding.c
@@ -37,8 +37,8 @@ compiling ./../../src/util/pm_strpbrk.c
37
37
  linking shared-object prism/prism.so
38
38
 
39
39
  current directory: /home/runner/work/pigeonhole/pigeonhole/crates/ruby/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/ext/prism
40
- make DESTDIR\= sitearchdir\=./.gem.20261104-2345-sni2nw sitelibdir\=./.gem.20261104-2345-sni2nw install
41
- /usr/bin/install -c -m 0755 prism.so ./.gem.20261104-2345-sni2nw/prism
40
+ make DESTDIR\= sitearchdir\=./.gem.20261105-2189-n76o6p sitelibdir\=./.gem.20261105-2189-n76o6p install
41
+ /usr/bin/install -c -m 0755 prism.so ./.gem.20261105-2189-n76o6p/prism
42
42
 
43
43
  current directory: /home/runner/work/pigeonhole/pigeonhole/crates/ruby/vendor/bundle/ruby/3.4.0/gems/prism-1.9.0/ext/prism
44
- make DESTDIR\= sitearchdir\=./.gem.20261104-2345-sni2nw sitelibdir\=./.gem.20261104-2345-sni2nw clean
44
+ make DESTDIR\= sitearchdir\=./.gem.20261105-2189-n76o6p sitelibdir\=./.gem.20261105-2189-n76o6p clean
@@ -9,10 +9,10 @@ checking for whether -DNDEBUG is accepted as CFLAGS... yes
9
9
  creating Makefile
10
10
 
11
11
  current directory: /home/runner/work/pigeonhole/pigeonhole/crates/ruby/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension
12
- make DESTDIR\= sitearchdir\=./.gem.20261104-2345-3suy1i sitelibdir\=./.gem.20261104-2345-3suy1i clean
12
+ make DESTDIR\= sitearchdir\=./.gem.20261105-2189-ggqkev sitelibdir\=./.gem.20261105-2189-ggqkev clean
13
13
 
14
14
  current directory: /home/runner/work/pigeonhole/pigeonhole/crates/ruby/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension
15
- make DESTDIR\= sitearchdir\=./.gem.20261104-2345-3suy1i sitelibdir\=./.gem.20261104-2345-3suy1i
15
+ make DESTDIR\= sitearchdir\=./.gem.20261105-2189-ggqkev sitelibdir\=./.gem.20261105-2189-ggqkev
16
16
  compiling ./../../src/ast.c
17
17
  compiling ./../../src/lexer.c
18
18
  compiling ./../../src/lexstate.c
@@ -34,8 +34,8 @@ compiling rbs_string_bridging.c
34
34
  linking shared-object rbs_extension.so
35
35
 
36
36
  current directory: /home/runner/work/pigeonhole/pigeonhole/crates/ruby/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension
37
- make DESTDIR\= sitearchdir\=./.gem.20261104-2345-3suy1i sitelibdir\=./.gem.20261104-2345-3suy1i install
38
- /usr/bin/install -c -m 0755 rbs_extension.so ./.gem.20261104-2345-3suy1i
37
+ make DESTDIR\= sitearchdir\=./.gem.20261105-2189-ggqkev sitelibdir\=./.gem.20261105-2189-ggqkev install
38
+ /usr/bin/install -c -m 0755 rbs_extension.so ./.gem.20261105-2189-ggqkev
39
39
 
40
40
  current directory: /home/runner/work/pigeonhole/pigeonhole/crates/ruby/vendor/bundle/ruby/3.4.0/gems/rbs-4.2.0/ext/rbs_extension
41
- make DESTDIR\= sitearchdir\=./.gem.20261104-2345-3suy1i sitelibdir\=./.gem.20261104-2345-3suy1i clean
41
+ make DESTDIR\= sitearchdir\=./.gem.20261105-2189-ggqkev sitelibdir\=./.gem.20261105-2189-ggqkev clean
@@ -2,7 +2,7 @@
2
2
 
3
3
  [dependencies.pigeonhole-io]
4
4
  path = "../io"
5
- version = "=2.0.0"
5
+ version = "=2.0.1"
6
6
  [lints.rust.unexpected_cfgs]
7
7
  check-cfg = ["cfg(loom)", "cfg(engine_loom)", "cfg(io_loom)", "cfg(pigeonhole_sim)"]
8
8
  level = "warn"
@@ -17,5 +17,5 @@ name = "pigeonhole-cache"
17
17
  readme = "README.md"
18
18
  repository = "https://github.com/CodingAnarchy/pigeonhole"
19
19
  rust-version = "1.96"
20
- version = "2.0.0"
20
+ version = "2.0.1"
21
21
  [target."cfg(loom)"]
@@ -2,19 +2,19 @@
2
2
 
3
3
  [dependencies.pigeonhole-cache]
4
4
  path = "../cache"
5
- version = "=2.0.0"
5
+ version = "=2.0.1"
6
6
  [dependencies.pigeonhole-format]
7
7
  path = "../format"
8
- version = "=2.0.0"
8
+ version = "=2.0.1"
9
9
  [dependencies.pigeonhole-io]
10
10
  path = "../io"
11
- version = "=2.0.0"
11
+ version = "=2.0.1"
12
12
  [dependencies.pigeonhole-pager]
13
13
  path = "../pager"
14
- version = "=2.0.0"
14
+ version = "=2.0.1"
15
15
  [dependencies.pigeonhole-sst]
16
16
  path = "../sst"
17
- version = "=2.0.0"
17
+ version = "=2.0.1"
18
18
  [lints.rust.unexpected_cfgs]
19
19
  check-cfg = ["cfg(loom)", "cfg(engine_loom)", "cfg(io_loom)", "cfg(pigeonhole_sim)"]
20
20
  level = "warn"
@@ -29,4 +29,4 @@ name = "pigeonhole-compaction"
29
29
  readme = "README.md"
30
30
  repository = "https://github.com/CodingAnarchy/pigeonhole"
31
31
  rust-version = "1.96"
32
- version = "2.0.0"
32
+ version = "2.0.1"
@@ -4,34 +4,34 @@
4
4
  version = "1"
5
5
  [dependencies.pigeonhole-cache]
6
6
  path = "../cache"
7
- version = "=2.0.0"
7
+ version = "=2.0.1"
8
8
  [dependencies.pigeonhole-compaction]
9
9
  path = "../compaction"
10
- version = "=2.0.0"
10
+ version = "=2.0.1"
11
11
  [dependencies.pigeonhole-format]
12
12
  path = "../format"
13
- version = "=2.0.0"
13
+ version = "=2.0.1"
14
14
  [dependencies.pigeonhole-io]
15
15
  path = "../io"
16
- version = "=2.0.0"
16
+ version = "=2.0.1"
17
17
  [dependencies.pigeonhole-memtable]
18
18
  path = "../memtable"
19
- version = "=2.0.0"
19
+ version = "=2.0.1"
20
20
  [dependencies.pigeonhole-pager]
21
21
  path = "../pager"
22
- version = "=2.0.0"
22
+ version = "=2.0.1"
23
23
  [dependencies.pigeonhole-runtime]
24
24
  path = "../runtime"
25
- version = "=2.0.0"
25
+ version = "=2.0.1"
26
26
  [dependencies.pigeonhole-shm]
27
27
  path = "../shm"
28
- version = "=2.0.0"
28
+ version = "=2.0.1"
29
29
  [dependencies.pigeonhole-sst]
30
30
  path = "../sst"
31
- version = "=2.0.0"
31
+ version = "=2.0.1"
32
32
  [dependencies.pigeonhole-wal]
33
33
  path = "../wal"
34
- version = "=2.0.0"
34
+ version = "=2.0.1"
35
35
  [dependencies.smallvec]
36
36
  version = "1"
37
37
  [features]
@@ -50,7 +50,7 @@ name = "pigeonhole-engine"
50
50
  readme = "README.md"
51
51
  repository = "https://github.com/CodingAnarchy/pigeonhole"
52
52
  rust-version = "1.96"
53
- version = "2.0.0"
53
+ version = "2.0.1"
54
54
  [target."cfg(engine_loom)".dependencies.loom]
55
55
  version = "0.7"
56
56
  [target."cfg(unix)"]
@@ -2693,6 +2693,15 @@ impl Engine {
2693
2693
  .value
2694
2694
  .take()
2695
2695
  .map(|p| (p, Arc::clone(&snapshot.view.ssts)));
2696
+ // The read's column limit counts only the columns that pass the predicate (the
2697
+ // resolver counts a column when its newest version passes), so it leaves the read
2698
+ // with the predicate, and the search counts the passing columns itself (simp724's A1
2699
+ // on #1286).
2700
+ let column_limit = if filter.is_some() {
2701
+ std::mem::take(&mut read.columns_per_row)
2702
+ } else {
2703
+ 0
2704
+ };
2696
2705
  Ok(match &spec.input {
2697
2706
  crate::ReadInput::Ranges(ranges) => {
2698
2707
  let [(lo, hi)] = ranges.as_slice() else {
@@ -2703,7 +2712,7 @@ impl Engine {
2703
2712
  let mut scan = ScanSpec::new(lo.clone(), hi.clone());
2704
2713
  scan.read = read;
2705
2714
  let cursor = self.scan_async(snapshot, table, scan)?;
2706
- read::knn::PendingNearest::scan(cursor, query, k, filter)
2715
+ read::knn::PendingNearest::scan(cursor, query, k, filter, column_limit)
2707
2716
  }
2708
2717
  crate::ReadInput::Keys(keys) => {
2709
2718
  let cursor = crate::KeyCursor::over(
@@ -2715,7 +2724,14 @@ impl Engine {
2715
2724
  Arc::clone(keys),
2716
2725
  Arc::clone(&self.inner.shared),
2717
2726
  )?;
2718
- read::knn::PendingNearest::keys(cursor, Arc::clone(keys), query, k, filter)
2727
+ read::knn::PendingNearest::keys(
2728
+ cursor,
2729
+ Arc::clone(keys),
2730
+ query,
2731
+ k,
2732
+ filter,
2733
+ column_limit,
2734
+ )
2719
2735
  }
2720
2736
  })
2721
2737
  }
@@ -240,6 +240,11 @@ pub struct PendingNearest {
240
240
  /// so the cells it drops count toward a poll's budget (#1237's rule), with the SSTs to
241
241
  /// read a separated value from.
242
242
  filter: Option<Filter>,
243
+ /// The read's column limit when `filter` left the read (0: none), and the columns that
244
+ /// passed it in the current row: the resolver counts only passing columns, so the search
245
+ /// does too (simp724's A1 on #1286).
246
+ column_limit: u32,
247
+ columns: u32,
243
248
  /// The row being read (its key in a buffer reused from row to row), if one is.
244
249
  row: Vec<u8>,
245
250
  in_row: bool,
@@ -263,8 +268,9 @@ impl PendingNearest {
263
268
  query: Prepared,
264
269
  k: usize,
265
270
  filter: Option<Filter>,
271
+ column_limit: u32,
266
272
  ) -> Self {
267
- Self::with(Source::Scan(cursor), query, k, filter)
273
+ Self::with(Source::Scan(cursor), query, k, filter, column_limit)
268
274
  }
269
275
 
270
276
  pub(crate) fn keys(
@@ -273,16 +279,31 @@ impl PendingNearest {
273
279
  query: Prepared,
274
280
  k: usize,
275
281
  filter: Option<Filter>,
282
+ column_limit: u32,
276
283
  ) -> Self {
277
- Self::with(Source::Keys { cursor, keys }, query, k, filter)
284
+ Self::with(
285
+ Source::Keys { cursor, keys },
286
+ query,
287
+ k,
288
+ filter,
289
+ column_limit,
290
+ )
278
291
  }
279
292
 
280
- fn with(source: Source, query: Prepared, k: usize, filter: Option<Filter>) -> Self {
293
+ fn with(
294
+ source: Source,
295
+ query: Prepared,
296
+ k: usize,
297
+ filter: Option<Filter>,
298
+ column_limit: u32,
299
+ ) -> Self {
281
300
  Self {
282
301
  source,
283
302
  visitor: KnnVisitor::typed(query, Arc::new(KnnSkips::default())),
284
303
  top: TopK::new(k),
285
304
  filter,
305
+ column_limit,
306
+ columns: 0,
286
307
  row: Vec::new(),
287
308
  in_row: false,
288
309
  done: false,
@@ -315,18 +336,29 @@ impl PendingNearest {
315
336
  return Poll::Ready(Ok(()));
316
337
  }
317
338
  self.in_row = true;
339
+ self.columns = 0;
318
340
  }
319
341
  let row = self.row.as_slice();
320
- let (visitor, top, filter) = (&mut self.visitor, &mut self.top, self.filter.as_ref());
321
- let ended = match &mut self.source {
322
- Source::Scan(c) => {
323
- c.counted(|c| read_row(c, row, &mut budget, visitor, top, filter))
324
- }
325
- Source::Keys { cursor, .. } => {
326
- cursor.counted(|c| read_row(c, row, &mut budget, visitor, top, filter))
327
- }
342
+ let mut r = RowRead {
343
+ row,
344
+ budget: &mut budget,
345
+ visitor: &mut self.visitor,
346
+ top: &mut self.top,
347
+ filter: self.filter.as_ref(),
348
+ column_limit: self.column_limit,
349
+ columns: &mut self.columns,
350
+ };
351
+ let end = match &mut self.source {
352
+ Source::Scan(c) => c.counted(|c| r.read(c)),
353
+ Source::Keys { cursor, .. } => cursor.counted(|c| r.read(c)),
328
354
  }?;
329
- if ended {
355
+ if end == RowEnd::Limit
356
+ && let Source::Keys { cursor, .. } = &mut self.source
357
+ {
358
+ // The rest of the key goes unread; a scan's next row drops it itself.
359
+ cursor.skip_rest_of_key();
360
+ }
361
+ if end != RowEnd::Budget {
330
362
  self.in_row = false;
331
363
  } else {
332
364
  // The budget ran out mid-row: yield, keeping the row's place.
@@ -354,43 +386,71 @@ impl RowCells for super::keys::KeyCursor {
354
386
  }
355
387
  }
356
388
 
357
- /// Scores the current row's cells into `top` within `budget` cells: whether the row ended.
358
- /// Cells `filter` drops count toward the budget too, and never reach the visitor.
359
- fn read_row(
360
- cells: &mut impl RowCells,
361
- row: &[u8],
362
- budget: &mut u32,
363
- visitor: &mut KnnVisitor,
364
- top: &mut TopK<Score>,
365
- filter: Option<&Filter>,
366
- ) -> crate::Result<bool> {
367
- use super::reduce::{CellRef, Reducer};
368
- loop {
369
- if *budget == 0 {
370
- return Ok(false);
371
- }
372
- let Some(c) = cells.next_cell()? else {
373
- return Ok(true);
374
- };
375
- *budget -= 1;
376
- if let Some((p, ssts)) = filter {
377
- let kept = match pigeonhole_compaction::blob_pointer(c.stored) {
378
- Some(ptr) => p.matches(&ssts.read_pointer(&ptr)?),
379
- None => p.matches(c.stored),
380
- };
381
- if !kept {
382
- continue;
389
+ /// Where a row's read stopped.
390
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
391
+ enum RowEnd {
392
+ /// The poll's cell budget ran out: the row goes on next poll.
393
+ Budget,
394
+ /// The row's cells ran out.
395
+ Ended,
396
+ /// The column limit is reached: the rest of the row is skipped.
397
+ Limit,
398
+ }
399
+
400
+ /// One row's read into `top`, within the poll's `budget` cells.
401
+ struct RowRead<'a> {
402
+ row: &'a [u8],
403
+ budget: &'a mut u32,
404
+ visitor: &'a mut KnnVisitor,
405
+ top: &'a mut TopK<Score>,
406
+ filter: Option<&'a Filter>,
407
+ column_limit: u32,
408
+ columns: &'a mut u32,
409
+ }
410
+
411
+ impl RowRead<'_> {
412
+ /// Scores the current row's cells. Cells `filter` drops count toward the budget too,
413
+ /// and never reach the visitor; with a column limit, only the cells it keeps count
414
+ /// toward the limit (one version per column).
415
+ fn read(&mut self, cells: &mut impl RowCells) -> crate::Result<RowEnd> {
416
+ use super::reduce::{CellRef, Reducer};
417
+ let row = self.row;
418
+ loop {
419
+ if *self.budget == 0 {
420
+ return Ok(RowEnd::Budget);
383
421
  }
384
- }
385
- if let Visit::Emit(score) = visitor.visit(row, c.family, c.qualifier, c.ts, c.stored) {
386
- let cell = CellRef {
387
- row,
388
- family_rank: 0,
389
- family: c.family,
390
- qualifier: c.qualifier,
391
- ts: c.ts,
422
+ let Some(c) = cells.next_cell()? else {
423
+ return Ok(RowEnd::Ended);
392
424
  };
393
- let _ = top.push(cell, score);
425
+ *self.budget -= 1;
426
+ if let Some((p, ssts)) = self.filter {
427
+ let kept = match pigeonhole_compaction::blob_pointer(c.stored) {
428
+ Some(ptr) => p.matches(&ssts.read_pointer(&ptr)?),
429
+ None => p.matches(c.stored),
430
+ };
431
+ if !kept {
432
+ continue;
433
+ }
434
+ if self.column_limit != 0 {
435
+ if *self.columns == self.column_limit {
436
+ return Ok(RowEnd::Limit);
437
+ }
438
+ *self.columns += 1;
439
+ }
440
+ }
441
+ let visited = self
442
+ .visitor
443
+ .visit(row, c.family, c.qualifier, c.ts, c.stored);
444
+ if let Visit::Emit(score) = visited {
445
+ let cell = CellRef {
446
+ row,
447
+ family_rank: 0,
448
+ family: c.family,
449
+ qualifier: c.qualifier,
450
+ ts: c.ts,
451
+ };
452
+ let _ = self.top.push(cell, score);
453
+ }
394
454
  }
395
455
  }
396
456
  }
@@ -1121,11 +1121,12 @@ impl ScanCursor {
1121
1121
  self.recycle_lanes();
1122
1122
  return Ok(Some(false));
1123
1123
  }
1124
- // Drop whatever is left of the current row.
1124
+ // Drop whatever is left of the current row. A lane whose cell was handed out last
1125
+ // still holds it (pending, in this row) with the rest of the row behind it unread:
1126
+ // it is skipped with the others, never left to hand that rest out as a next row
1127
+ // (a reader that stops a row early: an async search at its column limit, #1286).
1125
1128
  if self.in_row {
1126
- if let Some(i) = self.last_lane.take() {
1127
- self.lanes[i].pending = false;
1128
- }
1129
+ self.last_lane = None;
1129
1130
  self.skip_current_row()?;
1130
1131
  self.in_row = false;
1131
1132
  }
@@ -37,4 +37,4 @@ name = "pigeonhole-format"
37
37
  readme = "README.md"
38
38
  repository = "https://github.com/CodingAnarchy/pigeonhole"
39
39
  rust-version = "1.96"
40
- version = "2.0.0"
40
+ version = "2.0.1"
data/vendor/io/Cargo.toml CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [dependencies.pigeonhole-format]
4
4
  path = "../format"
5
- version = "=2.0.0"
5
+ version = "=2.0.1"
6
6
  [lints.rust.unexpected_cfgs]
7
7
  check-cfg = ["cfg(loom)", "cfg(engine_loom)", "cfg(io_loom)", "cfg(pigeonhole_sim)"]
8
8
  level = "warn"
@@ -17,7 +17,7 @@ name = "pigeonhole-io"
17
17
  readme = "README.md"
18
18
  repository = "https://github.com/CodingAnarchy/pigeonhole"
19
19
  rust-version = "1.96"
20
- version = "2.0.0"
20
+ version = "2.0.1"
21
21
  [target."cfg(io_loom)".dependencies.loom]
22
22
  version = "0.7"
23
23
  [target."cfg(target_os = \"linux\")".dependencies.io-uring]
@@ -4,13 +4,13 @@
4
4
  version = "0.3"
5
5
  [dependencies.pigeonhole]
6
6
  path = "../pigeonhole"
7
- version = "1.1.0"
7
+ version = "1.1.1"
8
8
  [dependencies.pigeonhole-text]
9
9
  path = "../text"
10
- version = "1.1.0"
10
+ version = "1.1.1"
11
11
  [dependencies.pigeonhole-vector]
12
12
  path = "../vector"
13
- version = "1.1.0"
13
+ version = "1.1.1"
14
14
  [dependencies.twox-hash]
15
15
  default-features = false
16
16
  features = ["std", "xxhash3_64", "xxhash3_128"]
@@ -31,4 +31,4 @@ name = "pigeonhole-memory"
31
31
  readme = "README.md"
32
32
  repository = "https://github.com/CodingAnarchy/pigeonhole"
33
33
  rust-version = "1.96"
34
- version = "1.1.0"
34
+ version = "1.1.1"
@@ -2,10 +2,10 @@
2
2
 
3
3
  [dependencies.pigeonhole-format]
4
4
  path = "../format"
5
- version = "=2.0.0"
5
+ version = "=2.0.1"
6
6
  [dependencies.pigeonhole-io]
7
7
  path = "../io"
8
- version = "=2.0.0"
8
+ version = "=2.0.1"
9
9
  [lints.rust.unexpected_cfgs]
10
10
  check-cfg = ["cfg(loom)", "cfg(engine_loom)", "cfg(io_loom)", "cfg(pigeonhole_sim)"]
11
11
  level = "warn"
@@ -20,5 +20,5 @@ name = "pigeonhole-memtable"
20
20
  readme = "README.md"
21
21
  repository = "https://github.com/CodingAnarchy/pigeonhole"
22
22
  rust-version = "1.96"
23
- version = "2.0.0"
23
+ version = "2.0.1"
24
24
  [target."cfg(loom)"]
@@ -2,10 +2,10 @@
2
2
 
3
3
  [dependencies.pigeonhole-format]
4
4
  path = "../format"
5
- version = "=2.0.0"
5
+ version = "=2.0.1"
6
6
  [dependencies.pigeonhole-io]
7
7
  path = "../io"
8
- version = "=2.0.0"
8
+ version = "=2.0.1"
9
9
  [lints.rust.unexpected_cfgs]
10
10
  check-cfg = ["cfg(loom)", "cfg(engine_loom)", "cfg(io_loom)", "cfg(pigeonhole_sim)"]
11
11
  level = "warn"
@@ -20,4 +20,4 @@ name = "pigeonhole-pager"
20
20
  readme = "README.md"
21
21
  repository = "https://github.com/CodingAnarchy/pigeonhole"
22
22
  rust-version = "1.96"
23
- version = "2.0.0"
23
+ version = "2.0.1"
@@ -8,16 +8,16 @@ optional = true
8
8
  version = "0.3"
9
9
  [dependencies.pigeonhole-engine]
10
10
  path = "../engine"
11
- version = "=2.0.0"
11
+ version = "=2.0.1"
12
12
  [dependencies.pigeonhole-format]
13
13
  path = "../format"
14
- version = "=2.0.0"
14
+ version = "=2.0.1"
15
15
  [dependencies.pigeonhole-io]
16
16
  path = "../io"
17
- version = "=2.0.0"
17
+ version = "=2.0.1"
18
18
  [dependencies.pigeonhole-shm]
19
19
  path = "../shm"
20
- version = "=2.0.0"
20
+ version = "=2.0.1"
21
21
  [dependencies.smallvec]
22
22
  version = "1"
23
23
  [features]
@@ -39,4 +39,4 @@ name = "pigeonhole"
39
39
  readme = "README.md"
40
40
  repository = "https://github.com/CodingAnarchy/pigeonhole"
41
41
  rust-version = "1.96"
42
- version = "1.1.0"
42
+ version = "1.1.1"
@@ -39,7 +39,7 @@ cargo add pigeonhole
39
39
  or `pigeonhole = "1"` in `Cargo.toml`. Requires Rust 1.96 (2024 edition). API docs are on
40
40
  [docs.rs](https://docs.rs/pigeonhole). See the
41
41
  [changelog](https://github.com/CodingAnarchy/pigeonhole/blob/main/CHANGELOG.md) and the
42
- [1.1.0 release](https://github.com/CodingAnarchy/pigeonhole/releases/tag/v1.1.0).
42
+ [1.1.1 release](https://github.com/CodingAnarchy/pigeonhole/releases/tag/v1.1.1).
43
43
 
44
44
  ## Quickstart
45
45
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  [dependencies.pigeonhole-io]
4
4
  path = "../io"
5
- version = "=2.0.0"
5
+ version = "=2.0.1"
6
6
  [lints.rust.unexpected_cfgs]
7
7
  check-cfg = ["cfg(loom)", "cfg(engine_loom)", "cfg(io_loom)", "cfg(pigeonhole_sim)"]
8
8
  level = "warn"
@@ -17,5 +17,5 @@ name = "pigeonhole-runtime"
17
17
  readme = "README.md"
18
18
  repository = "https://github.com/CodingAnarchy/pigeonhole"
19
19
  rust-version = "1.96"
20
- version = "2.0.0"
20
+ version = "2.0.1"
21
21
  [target."cfg(loom)"]
@@ -2,10 +2,10 @@
2
2
 
3
3
  [dependencies.pigeonhole-format]
4
4
  path = "../format"
5
- version = "=2.0.0"
5
+ version = "=2.0.1"
6
6
  [dependencies.pigeonhole-io]
7
7
  path = "../io"
8
- version = "=2.0.0"
8
+ version = "=2.0.1"
9
9
  [lints.rust.unexpected_cfgs]
10
10
  check-cfg = ["cfg(loom)", "cfg(engine_loom)", "cfg(io_loom)", "cfg(pigeonhole_sim)"]
11
11
  level = "warn"
@@ -20,5 +20,5 @@ name = "pigeonhole-shm"
20
20
  readme = "README.md"
21
21
  repository = "https://github.com/CodingAnarchy/pigeonhole"
22
22
  rust-version = "1.96"
23
- version = "2.0.0"
23
+ version = "2.0.1"
24
24
  [target."cfg(unix)"]
@@ -2,13 +2,13 @@
2
2
 
3
3
  [dependencies.pigeonhole-cache]
4
4
  path = "../cache"
5
- version = "=2.0.0"
5
+ version = "=2.0.1"
6
6
  [dependencies.pigeonhole-format]
7
7
  path = "../format"
8
- version = "=2.0.0"
8
+ version = "=2.0.1"
9
9
  [dependencies.pigeonhole-io]
10
10
  path = "../io"
11
- version = "=2.0.0"
11
+ version = "=2.0.1"
12
12
  [lints.rust.unexpected_cfgs]
13
13
  check-cfg = ["cfg(loom)", "cfg(engine_loom)", "cfg(io_loom)", "cfg(pigeonhole_sim)"]
14
14
  level = "warn"
@@ -23,4 +23,4 @@ name = "pigeonhole-sst"
23
23
  readme = "README.md"
24
24
  repository = "https://github.com/CodingAnarchy/pigeonhole"
25
25
  rust-version = "1.96"
26
- version = "2.0.0"
26
+ version = "2.0.1"
@@ -4,7 +4,7 @@
4
4
  version = "0.2.1"
5
5
  [dependencies.pigeonhole]
6
6
  path = "../pigeonhole"
7
- version = "1.1.0"
7
+ version = "1.1.1"
8
8
  [dependencies.unicode-normalization]
9
9
  version = "0.1"
10
10
  [dependencies.unicode-segmentation]
@@ -23,4 +23,4 @@ name = "pigeonhole-text"
23
23
  readme = "README.md"
24
24
  repository = "https://github.com/CodingAnarchy/pigeonhole"
25
25
  rust-version = "1.96"
26
- version = "1.1.0"
26
+ version = "1.1.1"
@@ -6,7 +6,7 @@ optional = true
6
6
  version = "0.3"
7
7
  [dependencies.pigeonhole]
8
8
  path = "../pigeonhole"
9
- version = "1.1.0"
9
+ version = "1.1.1"
10
10
  [features]
11
11
  __unstable-hooks = []
12
12
  async = ["pigeonhole/async", "dep:futures-core"]
@@ -25,4 +25,4 @@ name = "pigeonhole-vector"
25
25
  readme = "README.md"
26
26
  repository = "https://github.com/CodingAnarchy/pigeonhole"
27
27
  rust-version = "1.96"
28
- version = "1.1.0"
28
+ version = "1.1.1"
@@ -2,10 +2,10 @@
2
2
 
3
3
  [dependencies.pigeonhole-format]
4
4
  path = "../format"
5
- version = "=2.0.0"
5
+ version = "=2.0.1"
6
6
  [dependencies.pigeonhole-io]
7
7
  path = "../io"
8
- version = "=2.0.0"
8
+ version = "=2.0.1"
9
9
  [features]
10
10
  sim-hooks = []
11
11
  [lints.rust.unexpected_cfgs]
@@ -22,4 +22,4 @@ name = "pigeonhole-wal"
22
22
  readme = "README.md"
23
23
  repository = "https://github.com/CodingAnarchy/pigeonhole"
24
24
  rust-version = "1.96"
25
- version = "2.0.0"
25
+ version = "2.0.1"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pigeonhole-db
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Tanous