libparitypp (20260505+2) unstable; urgency=high

  * Rebuild against libnetplus 20260505+12 (ABI change: _closed_streams
    added to quic class; fixes crash in quic::~quic(), flow control
    double-counting, stream resurrection, silent data loss, uni-stream
    dispatch, FIN-only frame)

 -- Jan Koester <jan.koester@tuxist.de>  Mon, 05 May 2026 17:00:00 +0200

libparitypp (20260504+1) unstable; urgency=high

  * client/store_stripe Phase 2: pump ALL pending QUIC connections every
    loop iteration, not just sockets with incoming data — this ensures
    PTO (Probe Timeout) retransmissions fire even when the peer hasn't
    responded due to tail packet loss

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 04 May 2026 19:45:00 +0200

libparitypp (20260503+7) unstable; urgency=high

  * client/store_stripe: reset remote QUIC connections after response timeout
    so retries do not reuse poisoned half-open sessions
  * client: improves recovery from repeated "remote_sent=2" + no-response
    patterns seen during cluster import writes

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 03 May 2026 20:55:00 +0200

libparitypp (20260503+6) unstable; urgency=high

  * client: add opt-in deep diagnostics for store_stripe/send_recv timeout
    analysis via PARITYPP_DIAG=1 (header/body progress, timing, per-node
    response state) to isolate cross-node response timeout root causes

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 03 May 2026 19:45:00 +0200

libparitypp (20260503+5) unstable; urgency=high

  * client: reduce import stall time by failing fast on response-timeout
    dominated store() errors instead of running a full second global store
    attempt after store_stripe timeout failures
  * client: keep retry-once behavior for non-timeout transient errors

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 03 May 2026 19:35:00 +0200

libparitypp (20260503+4) unstable; urgency=high

  * client: fix logic bug in response parsing for send_recv() and
    store_stripe() when QUIC stream data arrives fragmented
  * client: handle partial response header/body reads statefully instead of
    discarding short reads; prevents false "response timeout" and
    "too many node failures" under import load

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 03 May 2026 19:05:00 +0200

libparitypp (20260503+3) unstable; urgency=medium

  * client: split store_stripe timeout into separate send and response
    deadlines; keep a much larger response window for remote block-store
    ACKs under import load to avoid false peer timeouts
  * client: apply the same longer type-specific timeout model to
    send_recv(STORE_BLOCK) so direct block writes do not still fail at 5s

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 03 May 2026 18:10:00 +0200

libparitypp (20260502+1) unstable; urgency=medium

  * Rebuild against libnetplus 20260502+1 (QUIC performance improvements)

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 02 May 2026 12:00:00 +0200

libparitypp (20260426+2) unstable; urgency=high

  * file_block_store: fix CRC32 PCLMULQDQ fold constants (k1k2, k3k4),
    poly constant byte-order, and add missing 96→64 fold step in
    Barrett reduction — the broken PCLMUL path caused all records to
    fail CRC verification on restart, leading to complete data loss
  * vacuum_impl: re-scan index from data file when index is empty but
    data file is non-empty; refuse to vacuum if re-scan finds nothing
  * crc32: promote to public API; add comprehensive unit test comparing
    PCLMUL vs table-driven across 24 sizes, 16 alignments, and 64 KB

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 26 Apr 2026 17:00:00 +0200

libparitypp (20260426+1) unstable; urgency=high

  * file_block_store: fix CRC32 PCLMULQDQ fold constants (k1k2, k3k4),
    poly constant byte-order, and add missing 96→64 fold step in
    Barrett reduction — the broken PCLMUL path caused all records to
    fail CRC verification on restart, leading to complete data loss
  * vacuum_impl: refuse to run when index is empty but data file is
    non-empty, preventing data wipe from future CRC/scan bugs
  * crc32: promote to public API; add comprehensive unit test comparing
    PCLMUL vs table-driven across 24 sizes, 16 alignments, and 64 KB

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 26 Apr 2026 16:00:00 +0200

libparitypp (20260425+4) unstable; urgency=medium

  * client::store_stripe: interleave remote QUIC sends via round-robin
    waitWrite/pump instead of sequential per-node blocking. All remote
    connections now grow their congestion windows concurrently, reducing
    per-stripe latency from sum(RTTs) to max(RTTs).

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 25 Apr 2026 22:00:00 +0200

libparitypp (20260425+3) unstable; urgency=medium

  * Rebuild against libnetplus 20260425+5 (RSA Montgomery CIOS
    heap over-read fix)

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 25 Apr 2026 21:00:00 +0200

libparitypp (20260425+2) unstable; urgency=medium

  * file_block_store: add PCLMULQDQ-accelerated CRC32 path with
    runtime CPU dispatch via __builtin_cpu_supports("pclmul"),
    processing 64 bytes per fold iteration

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 25 Apr 2026 16:00:00 +0200

libparitypp (20260425+1) unstable; urgency=medium

  * file_block_store: replace bit-by-bit CRC32 with table-driven
    lookup, reducing per-byte cost from 8 branches to a single
    table fetch

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 25 Apr 2026 12:00:00 +0200

libparitypp (20260424+6) unstable; urgency=medium

  * memory_block_store: add optional byte-budget constructor with LRU
    eviction. Groups are evicted least-recently-used when used bytes
    exceed the configured maximum. Default constructor remains unbounded.

 -- Jan Koester <jan.koester@tuxist.de>  Thu, 24 Apr 2026 00:00:00 +0200

libparitypp (20260423+5) unstable; urgency=high

  * file_block_store: fix WAL commit ordering — wal_commit() is now called
    AFTER data is durably flushed, preventing data loss on crash between
    WAL commit and flush.
  * file_block_store: defer old-record tombstoning until replacement record
    is durably flushed. Crash between tombstone and flush can no longer
    destroy the only copy of a block.
  * file_block_store: handle duplicate LIVE records in scan_and_build_index
    (recovery after crash with deferred tombstoning).
  * file_block_store: clear pending_tombstones_ in vacuum_impl().
  * client::rebalance(): store data BEFORE removing old copies to prevent
    data loss when re-store fails after remove.

 -- Jan Koester <jan.koester@tuxist.de>  Wed, 23 Apr 2026 00:00:00 +0200

libparitypp (20260420+4) unstable; urgency=medium

  * store_stripe: replace std::async parallel sends with sequential sends.
    Eliminates thousands of short-lived OS threads during bulk imports that
    caused OOM kills and SEGV crashes on memory-constrained nodes.

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 20 Apr 2026 00:00:00 +0200

libparitypp (20260420+3) unstable; urgency=medium

  * store_stripe: log warning (stderr) when nodes fail but within parity
    tolerance — makes partial replication visible in Release builds.
  * connect_to_node: increase QUIC handshake timeout from 2s to 5s to
    improve reliability under load (e.g. during bulk imports).

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 20 Apr 2026 00:00:00 +0200

libparitypp (20260418+2) unstable; urgency=medium

  * Reduce mutex hold time in client::store(), retrieve(), retrieve_range()
    and remove() — release/reacquire between stripes/nodes for concurrency

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 18 Apr 2026 22:00:00 +0200

libparitypp (20260418+1) unstable; urgency=medium

  * Add scrub_running flag to status_info protocol (backward-compatible)
  * Add set_rebuilding() setter to server for external scrub signaling

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 18 Apr 2026 21:00:00 +0200

libparitypp (20260417+1) unstable; urgency=medium

  * Fix lock group inclusion in client::rebalance()

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 17 Apr 2026 12:00:00 +0200

libparitypp (20260412+43) unstable; urgency=medium

  * Add client::warmup() to pre-establish QUIC connections + auth
    on all nodes, eliminating first-request latency (2-3s per node)
  * Revert store_stripe deadline back to 5s (was 15s)

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 12 Apr 2026 23:00:00 +0200

libparitypp (20260412+42) unstable; urgency=medium

  * Add distributed scrub lock: try_scrub_lock() / release_scrub_lock()
    using a well-known parity group with timestamp-based TTL (5 min)
  * Prevents concurrent scrub/rebalance across cluster nodes

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 12 Apr 2026 18:00:00 +0200

libparitypp (20260412+41) unstable; urgency=medium

  * Increase store_stripe deadline from 5s to 15s
  * Optimize rebalance(): skip per-group list() calls, use
    list_groups_on_node() presence check only

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 12 Apr 2026 16:00:00 +0200

libparitypp (20260412+40) unstable; urgency=medium

  * Optimize rebalance(): skip expensive per-group list() calls by using
    list_groups_on_node() presence check — groups on all n nodes are
    assumed OK, only under-replicated groups get retrieve/remove/re-store

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 12 Apr 2026 14:00:00 +0200

libparitypp (20260412+39) unstable; urgency=medium

  * Increase store_stripe deadline from 5s to 15s — the shared deadline
    covers Phase 1 (send), Phase 1b (retry), and Phase 2 (collect),
    leaving too little time for response collection after QUIC handshakes

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 12 Apr 2026 12:00:00 +0200

libparitypp (20260411+38) unstable; urgency=medium

  * Add client::rebalance() method: detects misplaced blocks
    (block_index % n != node_index), re-stores groups with correct
    placement, then vacuums stale blocks

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 11 Apr 2026 20:00:00 +0200

libparitypp (20260411+37) unstable; urgency=medium

  * Fix client global mutex blocking: release mutex during retrieve_stripe
    retry backoff sleep so other operations are not serialized behind retries
  * Change retrieve/retrieve_range from lock_guard to unique_lock to allow
    unlock/relock around retry sleeps

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 11 Apr 2026 18:00:00 +0200

libparitypp (20260411+36) unstable; urgency=medium

  * Add per-record CRC32 checksums to file_block_store (record header 17→21 bytes)
  * Add WAL journal (blocks.wal) with STORE/TOMBSTONE/COMMIT for crash safety
  * Add fdatasync after flush and fsync directory after vacuum rename
  * Add WAL recovery on startup in scan_and_build_index
  * Add CRC32 validation on load, truncate trailing corrupt records
  * Add client retrieve_stripe retry with exponential backoff (up to 6 retries)
  * Add server peer-forwarding on FETCH_BLOCK when block not local
  * Add configurable startup_peer_wait_secs for cluster full-restart resilience
  * Add degraded mode flag with GET_STATUS reporting and auto-clear on rebuild
  * Add file_block_store test suite

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 11 Apr 2026 00:00:00 +0200

libparitypp (20260410+35) unstable; urgency=medium

  * No library changes — version bump for dependent package rebuilds
    (authdb, mediadb cluster scrub and health monitor improvements)

 -- Jan Koester <jan.koester@tuxist.de>  Thu, 10 Apr 2026 00:00:00 +0200

libparitypp (20260409+34) unstable; urgency=medium

  * Make file_block_store write buffer threshold configurable via
    constructor parameter (default 256KB, 0 = immediate flush)

 -- Jan Koester <jan.koester@tuxist.de>  Wed, 09 Apr 2026 20:00:00 +0200

libparitypp (20260409+33) unstable; urgency=medium

  * Add batch API to client: store_batch(), retrieve_batch(),
    retrieve_batch_item(), encode_batch(), decode_batch() for packing
    multiple keyed items into a single parity group
  * Add write coalescing to file_block_store: buffer small writes in
    memory (up to 256KB) and flush as a single pwrite(), reducing
    syscall overhead for many small block stores
  * file_block_store::fetch() reads from write buffer for unflushed data
  * file_block_store::remove_group() tombstones in write buffer when
    applicable, avoiding premature disk I/O
  * Flush write buffer before vacuum to ensure data consistency
  * Add public flush() method to file_block_store

 -- Jan Koester <jan.koester@tuxist.de>  Wed, 09 Apr 2026 18:00:00 +0200

libparitypp (20260409+32) unstable; urgency=medium

  * Rebuild against libnetplus 20260409+14 (BLOCKSIZE 65536)

 -- Jan Koester <jan.koester@tuxist.de>  Wed, 09 Apr 2026 00:00:00 +0200

libparitypp (20260407+31) unstable; urgency=medium

  * New release

 -- Jan Koester <jan.koester@tuxist.de>  Tue, 07 Apr 2026 00:00:00 +0200

libparitypp (20260406+30) unstable; urgency=medium

  * Add mark_node_dead() public method: allows external callers to propagate
    dead-node info between client instances (e.g. session_client_ syncs from
    pclient_ health monitor), avoiding redundant connect timeouts on dead nodes

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 06 Apr 2026 00:00:00 +0000

libparitypp (20260406+29) unstable; urgency=medium

  * Make client thread-safe: add internal mutex_ to all public methods
    (store, retrieve, remove, list, replicate_to_peers, fetch_from_peers,
    get_node_status, get_cluster_status, list_groups_on_node,
    vacuum_all_nodes, set_local_node, begin_store/flush_stripe)
  * External callers no longer need their own mutex around client calls

 -- Jan Koester <jan.koester@tuxist.de>  Mon, 06 Apr 2026 00:00:00 +0000

libparitypp (20260406+28) unstable; urgency=medium

  * rebuild

 -- Jan Koester <jan.koester@tuxist.de>  Mon, 06 Apr 2026 00:00:00 +0000

libparitypp (20260405+27) unstable; urgency=medium

  * Parallelize store_stripe and retrieve_stripe Phase 1: send to all
    remote nodes concurrently via std::async instead of sequentially
  * Parallelize store_stripe Phase 1b retry with fresh connections

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 05 Apr 2026 00:00:00 +0000

libparitypp (20260405+26) unstable; urgency=medium

  * retrieve(): return empty vector instead of throwing when no stripes
    exist for a group_id (fixes spam on fresh/empty clusters)

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 05 Apr 2026 00:00:00 +0000

libparitypp (20260405+25) unstable; urgency=medium

  * Add retrieve_range(group_id, offset, length): fetch only the stripes
    needed for a byte range, accounting for 8-byte framing header

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 05 Apr 2026 00:00:00 +0000

libparitypp (20260405+24) unstable; urgency=medium

  * Pipeline retrieve_stripe: send FETCH_BLOCK to all nodes simultaneously,
    collect responses with waitReadMulti (parallelize block fetches per stripe)
  * Auto-retry in client::store on stale QUIC connections: reset all
    connections and retry once on first stripe failure
  * Gate all debug logging behind NDEBUG macro (no output in Release builds)

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 05 Apr 2026 00:00:00 +0000

libparitypp (20260405+23) unstable; urgency=medium

  * Increase STRIPE_SIZE from 16KB to 4MB to reduce roundtrips per store
    (e.g. 188MB: 11490 stripes -> 46 stripes)

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 05 Apr 2026 00:00:00 +0000

libparitypp (20260405+22) unstable; urgency=medium

  * Add diagnostic stderr logging to client::store and store_stripe for
    debugging import hangs (stripe progress, failure diagnostics)

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 05 Apr 2026 00:00:00 +0000

libparitypp (20260405+21) unstable; urgency=medium

  * Replace per-socket waitRead polling loop in store_stripe Phase 2 with
    waitReadMulti: single epoll/kqueue/poll call waits on all pending nodes
    at once, eliminating CPU-burning spin when nodes are slow to respond

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 05 Apr 2026 00:00:00 +0000

libparitypp (20260405+20) unstable; urgency=medium

  * Add VACUUM protocol command (0x07) for remote block store compaction
  * Move vacuum() to block_store base class (default no-op, file_block_store
    overrides)
  * Add client::vacuum_all_nodes() to broadcast VACUUM to all cluster peers

 -- Jan Koester <jan.koester@tuxist.de>  Sun, 05 Apr 2026 00:00:00 +0000

libparitypp (20260404+19) unstable; urgency=medium

  * Replace busy-spin accept loop with poll-based waitRead (fixes 100% CPU
    usage on one core when idle)

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 04 Apr 2026 00:00:00 +0000

libparitypp (20260404+18) unstable; urgency=medium

  * Replace per-file block storage with append-only binary file
    (single blocks.bin per node instead of thousands of .blk files)
  * Add vacuum() method to compact file by dropping deleted records
  * In-memory index rebuilt on startup by scanning the data file

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 04 Apr 2026 00:00:00 +0000

libparitypp (20260404+17) unstable; urgency=medium

  * Catch netplus::NetException explicitly in store_stripe Phase 1 and
    Phase 2 (does not inherit std::exception, was falling through to
    catch(...) losing the error message)

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 04 Apr 2026 00:00:00 +0000

libparitypp (20260404+16) unstable; urgency=medium

  * Flush UDP datagrams immediately after sendStreamData (pumpNetwork)
  * Verify connection state after ensure_connected before using socket
  * Per-node diagnostic in store_stripe error: address, port, failure reason
    (connect failed, send timeout, response timeout, server non-OK, exception)

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 04 Apr 2026 00:00:00 +0000

libparitypp (20260404+15) unstable; urgency=medium

  * Add error_message() virtual method to store_session interface
  * Capture stripe failure details in client_store_session instead of
    logging to cerr (lost when daemonized)
  * Retry failed remote nodes once with a fresh connection in store_stripe
    (fixes stale QUIC connections between streaming sessions)

 -- Jan Koester <jan.koester@tuxist.de>  Sat, 04 Apr 2026 00:00:00 +0000

libparitypp (20260404+14) unstable; urgency=medium

  * Remove all std::cerr debug logging to eliminate data races
  * Replace ostringstream with snprintf in file_block_store to fix
    std::ctype<char>::_M_widen_init() BSS race

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 04 Apr 2026 00:00:00 +0000

libparitypp (20260404+13) unstable; urgency=medium

  * Fix store_stripe Phase 2: check hasStreamData before waitRead (buffered responses)
  * Close leaked streams when Phase 1 send fails

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 04 Apr 2026 23:00:00 +0200

libparitypp (20260404+12) unstable; urgency=medium

  * Fix pipelined response collection: use waitRead() instead of busy-poll
  * Increase timeout to 15s, handle null sockets gracefully

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 04 Apr 2026 23:00:00 +0200

libparitypp (20260404+11) unstable; urgency=medium

  * Pipeline store_stripe: send all blocks in parallel, then collect responses
  * Reduces per-stripe latency from O(n*RTT) to O(RTT)

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 04 Apr 2026 21:30:00 +0200

libparitypp (20260404+10) unstable; urgency=medium

  * Rebuild against libnetplus 20260404+6

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 04 Apr 2026 21:00:00 +0200

libparitypp (20260404+9) unstable; urgency=medium

  * Stripe-based store/retrieve: fixed 16KB stripes with independent parity
  * Add store_session for incremental streaming store (feed chunks, finalize)
  * Add begin_store(group_id, total_size) to client
  * Peak RAM reduced from full payload to ~16KB per stripe

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 04 Apr 2026 18:00:00 +0200

libparitypp (20260403+8) unstable; urgency=medium

  * Add retry logic (3 attempts) to store(gid) for transient connection failures
  * Add set_local_node() to bypass QUIC for self-node via direct block_store
  * Add erasure-coded store/retrieve with deterministic group_id
  * store(group_id, data) prepends 8-byte length header for padding removal
  * retrieve(group_id) reconstructs data with automatic size detection

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 04 Apr 2026 09:00:00 +0200

libparitypp (20260403+5) unstable; urgency=medium

  * replicate_to_peers now returns success count instead of void

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 04 Apr 2026 08:00:00 +0200

libparitypp (20260403+4) unstable; urgency=medium

  * Add periodic resync every 60s in server accept loop

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 04 Apr 2026 06:00:00 +0200

libparitypp (20260403+3) unstable; urgency=medium

  * Rebuild against libnetplus 20260403+2 (client handshake debug logging)

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 04 Apr 2026 02:00:00 +0200

libparitypp (20260403+2) unstable; urgency=medium

  * Rebuild against libnetplus 20260403+1 (udp::sendTo, clean sendPacket)

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 04 Apr 2026 01:00:00 +0200

libparitypp (20260403+1) unstable; urgency=medium

  * Rebuild against libnetplus 20260403 (QUIC debug logging)

 -- Jan Koester <jan.koester@tuxist.de>  Fri, 04 Apr 2026 00:10:00 +0200

libparitypp (20260403) unstable; urgency=medium

  * Add debug logging to load_certs: warn on cert/key load failure,
    log loaded certificate CN and key size

 -- Jan Koester <jan.koester@tuxist.de>  Thu, 03 Apr 2026 23:55:00 +0200

libparitypp (20260401) unstable; urgency=medium

  * Initial Debian packaging with multiarch support.

 -- Jan Koester <jan.koester@tuxist.de>  Wed, 01 Apr 2026 00:00:00 +0200
