pdftract/notes/pdftract-4ij2.md
jedarden 5881befa50 docs(pdftract-4ij2): add verification note for cycle detection + LRU cache
Implementation already complete. All 9 integration tests pass:
- Self-cycle detection returns PdfNull + STRUCT_CIRCULAR_REF
- 3-cycle (A->B->C->A) detection
- Legitimate objects cache after cycle
- 90%+ cache hit ratio
- LRU eviction at 4097 entries
- Random sequences terminate

Closes pdftract-4ij2.
2026-06-01 11:52:30 -04:00

3.4 KiB

pdftract-4ij2: Per-thread cycle detection + LRU object cache

Summary

This bead's implementation was already complete in the codebase. The per-thread cycle detection and LRU object cache features have been fully implemented with comprehensive tests.

Implementation Verification

Files Modified (already exist)

File Purpose
crates/pdftract-core/src/parser/object/cycle.rs Per-thread cycle detection with thread_local! RefCell<HashSet<ObjRef>>
crates/pdftract-core/src/parser/object/cache.rs LRU cache with Mutex<LruCache<ObjRef, Arc<PdfObject>>>, 4096 capacity
crates/pdftract-core/src/parser/object/types.rs ObjRef, PdfObject types
crates/pdftract-core/tests/test_cycle_detection.rs Integration tests

Acceptance Criteria Status

Criterion Status Test
Self-cycle returns PdfNull + STRUCT_CIRCULAR_REF, no stack overflow PASS test_self_cycle_returns_null_with_diagnostic
3-cycle (A->B->C->A) detection PASS test_three_cycle_abc_detected
Legitimate objects cached after cycle detection PASS test_legitimate_object_after_cycle
Cache hit ratio >= 90% (1000 accesses of 100 objects) PASS test_cache_hit_ratio_90_percent
LRU eviction at 4097 entries (4096 capacity) PASS test_lru_eviction_4097_entries
Random resolution sequences terminate PASS test_random_resolution_sequences_terminate

Implementation Details Verified

Per-thread Cycle Detection (cycle.rs)

  • thread_local! { static RESOLVING: RefCell<HashSet<ObjRef>> ... }
  • ResolutionGuard RAII guard for automatic cleanup
  • is_resolving(obj_ref) function for cycle checking
  • Thread-local isolation for rayon parallelism

LRU Object Cache (cache.rs)

  • lru = "0.12" crate in Cargo.toml
  • Mutex<LruCache<ObjRef, Arc<PdfObject>>> with 4096 capacity
  • CacheStats { hits: u64, misses: u64 } tracking
  • MAX_RESOLUTION_DEPTH: u16 = 256 depth limiting
  • Thread-local depth counter with RESOLUTION_DEPTH
  • PdfNull NOT cached (prevents poisoning)
  • CacheResolutionGuard combining cycle + depth tracking

Test Results

$ cargo test --package pdftract-core --test test_cycle_detection
running 9 tests
test test_self_cycle_returns_null_with_diagnostic ... ok
test test_three_cycle_abc_detected ... ok
test test_legitimate_object_after_cycle ... ok
test test_cache_hit_ratio_90_percent ... ok
test test_lru_eviction_4097_entries ... ok
test test_resolution_depth_limit_256 ... ok
test test_thread_local_cycle_detection ... ok
test test_null_not_cached ... ok
test test_random_resolution_sequences_terminate ... ok

test result: ok. 9 passed; 0 failed; 0 ignored

Unit Tests (cache.rs)

All 21 unit tests in cache.rs pass:

  • Cache hit/miss tracking
  • Hit ratio calculation
  • Null not cached
  • LRU eviction
  • Cycle detection
  • Depth limit enforcement
  • Thread-local independence
  • Guard cleanup on panic
  • peek_lru/is_lru helpers

Diagnostic Codes Verified

Code Emitted When Message Includes
STRUCT_CIRCULAR_REF Cycle detected ObjRef in msg
STRUCT_DEPTH_EXCEEDED Depth > 256 Limit value in msg

Conclusion

The implementation is complete and all acceptance criteria PASS. No code changes were required for this bead—the feature was already implemented.