mediadb (20260404+59) unstable; urgency=medium

  * Defer all cluster operations (replicate, lock acquire/release) outside
    db_.mutex_ to prevent import from blocking the entire database
  * Fine-grained locking in sync_from_cluster: hold cluster_op_mutex_ only
    during load, not during network fetch

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

mediadb (20260404+58) unstable; urgency=medium

  * Store all media data inline in per-store cluster blobs instead of
    separate per-media blobs (reduces cluster operations from N to 1 per store)
  * Remove replicate_media / fetch_media_from_cluster methods
  * read_media_data / read_media_data_range now delegate to local backend
  * Simplify import: no per-media begin_replicate callback needed

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

mediadb (20260404+57) unstable; urgency=medium

  * Hold cluster client lock per store instead of per media during import
    (eliminates hundreds of lock acquire/release cycles per store)
  * Add acquire_client_lock / replicate_unlocked / begin_replicate_unlocked
    to Cluster for caller-managed locking
  * Add store lifecycle callbacks (on_store_begin/on_store_end) to import
  * Add error_message() to ReplicateSession interface

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

mediadb (20260404+56) unstable; urgency=medium

  * Include underlying store_session error detail in cluster replication
    failure messages (stripe index, node failure count)
  * Delegate error_message() through LockedSession wrapper in cluster.cpp
  * Silence warn_unused_result warnings (freopen, chown, pwrite)

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

mediadb (20260404+55) unstable; urgency=medium

  * Fix use-after-move in load_store / load_store_from_buffer: album ID
    was read after std::move, causing phantom empty albums on restart/sync
  * Fix same use-after-move in MDS1/MDS2 legacy reader and add_media_metadata
  * Chown data directory to run_user before dropping privileges
  * Add error_message() to ImportSession; report write errors to client
  * Check store file open/write errors during import
  * Check cluster replication errors: begin_replicate, feed, finalize
    now abort import with error instead of silently losing media data
  * Defer media record visibility until all data is written (race fix)

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

mediadb (20260404+53) unstable; urgency=medium

  * Fix race: defer media record visibility until all data is written.
    Prevents concurrent readers from seeing media with incomplete data
    during streaming import (was masked by cerr logging acting as barrier).

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

mediadb (20260404+52) unstable; urgency=medium

  * Fix data race on import session done/ok flags: make atomic to ensure
    visibility across threads (H2/H3 handler reads without db mutex)
  * Remove diagnostic cerr logging from BinDbImportSession

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

mediadb (20260404+51) unstable; urgency=medium

  * Fix import status reporting: finish_import now stores ok/error result
    so /api/import/status returns correct success/failure instead of always
    reporting failure with empty error
  * Add diagnostic logging to BinDbImportSession for cluster debugging

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

mediadb (20260404+50) unstable; urgency=medium

  * Fix import data loss: vacuum store files after import to compact
    partial/duplicate records left by failed previous imports (ios::app)
  * Fix vacuum safety: skip raw data copy for media with data_offset==0
  * Fix spurious .mdb file: reject empty store_id in ensure_store_file
  * Fix client import: use PUT instead of POST for /api/import

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

mediadb (20260404+49) unstable; urgency=medium

  * Fix Alpine/musl fork: drop privileges before spawning threads so all
    threads inherit correct UID/GID (musl setuid is per-thread)
  * Fix empty DB after fork: defer ClusterMediaBackend sync_thread_ start
    to post-fork callback so sync runs in the child process after cluster start

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

mediadb (20260404+48) unstable; urgency=medium

  * Fix rwlock ownership violation: use per-call locking in BinDbImportSession
    instead of lifetime lock to avoid cross-thread unlock with H2 frame dispatch

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

mediadb (20260404+47) unstable; urgency=medium

  * Remove 'Cluster started' cerr to avoid race with paritypp server thread

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

mediadb (20260404+46) unstable; urgency=medium

  * Remove remaining std::cerr logging from cluster.cpp and backend.cpp
    to fully eliminate data races on _ZSt4cerr

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

mediadb (20260404+45) unstable; urgency=medium

  * Fix data race on std::cerr: remove verbose hot-path debug logging
    from HTTP handler threads (send_response, RequestEvent, import start)

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

mediadb (20260404+44) unstable; urgency=medium

  * Fix deadlock: LockedSession::finalize() releases client_mutex_ immediately
    so finish_store() metadata replicate() can acquire it

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

mediadb (20260404+43) unstable; urgency=medium

  * Web GUI: stream File directly in fetch() instead of arrayBuffer() preload
  * Rebuild against libparitypp 20260404+11 (pipelined store_stripe)

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

mediadb (20260404+42) unstable; urgency=medium

  * Fix segfault: hold client_mutex_ for lifetime of streaming store_session
    (LockedSession wrapper prevents concurrent QUIC connection access)

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

mediadb (20260404+41) unstable; urgency=medium

  * H2/H3 streaming import via onH2StreamHeaders/onH3StreamHeaders callbacks
  * Body data feeds directly into ImportSession per DATA frame (no buffering)
  * Requires libhttppp >= 20260404+1

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

mediadb (20260404+40) unstable; urgency=medium

  * Fix H2/H3: pass QUIC and ALPN h2 connections to base class immediately
  * H1 import: parse() ourselves then intercept PUT /api/import
  * H2/H3 import: handle_import uses ImportSession with buffered body
  * Restore handle_import route for H2/H3 framing layer

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

mediadb (20260404+39) unstable; urgency=medium

  * Fix: call parse() before base class to intercept PUT /api/import body
  * Cluster import: stream media to paritypp via ReplicateSession (16KB stripes)
  * Eliminate cluster_media_buf_ — peak RAM ~16KB instead of 100MB per media
  * Remove old handle_import buffering path from router

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

mediadb (20260404+38) unstable; urgency=medium

  * Import: streaming ImportSession state machine, no temp file needed
  * Import: RequestEvent feeds PUT body chunks directly into ImportSession
  * Import: zero-copy MemBuf streambuf for buffer-based imports
  * Cluster import: replicate media data immediately, skip existing via seekg
  * Import: save index once after all stores instead of per-store
  * Import: open store file once per store for all appends

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

mediadb (20260404+37) unstable; urgency=medium

  * Import: spool PUT body to temp file via RequestEvent(con&) override
  * Import: peak RAM ~64KB instead of 1GB for large archives
  * Import: import_db(path) reads from file, not from memory buffer
  * Import: clean up temp file on disconnect (orphaned spool)
  * Delete store/album: remove media data from cluster nodes

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

mediadb (20260404+36) unstable; urgency=medium

  * Cluster import: read media directly into final buffer, no double-copy
  * Cluster import: skip existing media via seekg instead of read loop

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

mediadb (20260403+35) unstable; urgency=medium

  * Import: remove background thread, run synchronously in request handler
  * Import: skip body copy in convert_request for /api/import (skip_body)
  * Import: fast-path in server.cpp reads directly from RecvData
  * Remove import_thread_ member and async import machinery

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

mediadb (20260403+34) unstable; urgency=medium

  * Cluster import: replicate media individually during parsing, not after
  * Cluster import: store_buf contains metadata only (no raw media data)
  * Cluster import: don't keep pending_data in RAM after replication
  * Cluster import: eliminate redundant second media replication pass
  * Import: save_index_locked called once after all stores, not per-store

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

mediadb (20260403+33) unstable; urgency=medium

  * Import: remove per-media stderr logging (major CPU/IO savings)
  * Import: write metadata directly to store file, no ostringstream allocs
  * Import: reusable I/O buffer across all media (single allocation)
  * Import: skip O(n²) duplicate check on media_ids during import
  * Import: release request body and import buffer immediately after parsing

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

mediadb (20260403+32) unstable; urgency=medium

  * New mediadb-tools package with mds_convert CLI utility
  * mds_convert converts MDS1/MDS2 store files to MDS3 format
  * Import: zero-copy buffer (no double RAM), streaming media I/O
  * Import: single file handle per store instead of per-media open/close

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

mediadb (20260403+31) unstable; urgency=medium

  * New MDS3 append-only store format: O(1) writes, O(1) deletes
  * Add media appends to end of store file instead of full rewrite
  * Delete marks record as empty (1 byte pwrite) instead of rewriting
  * Album edits (set_album_public) append new record + mark old as deleted
  * Import streams records directly to disk per-record (no full store rewrite)
  * Add vacuum: POST /api/vacuum reclaims space from deleted records
  * Backward-compatible: MDS1/MDS2 files still readable, new files use MDS3

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

mediadb (20260403+30) unstable; urgency=medium

  * Cluster: no local data storage, direct replication per media
  * Upload replicates only the new media data (media:{id} key), not the
    entire store
  * Store replication is metadata-only (no raw bytes), drastically smaller
  * Reads fetch media data on-demand from cluster
  * Export reconstructs full archive by fetching each media from cluster
  * Import replicates each media individually to cluster
  * Repair checks individual media shard health

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

mediadb (20260403+29) unstable; urgency=medium

  * Make PUT /api/import synchronous: blocks until replication is confirmed
  * Natural backpressure via HTTP connection, no background thread

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

mediadb (20260403+28) unstable; urgency=medium

  * Increase cluster client_mutex timeouts: 120s replicate, 60s fetch, 30s misc
  * Import no longer aborts on first store failure; continues and retries only
    the failed keys
  * Import returns success even if some replicas fail (local data preserved)

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

mediadb (20260403+27) unstable; urgency=medium

  * Fix streaming import: keep media in pending_data for local access while
    also writing to cluster buffer, fixing broken pictures after import

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

mediadb (20260403+26) unstable; urgency=medium

  * Stream import directly to cluster: build store buffer on-the-fly without
    loading all media into memory, drastically reducing memory usage
  * Fix NetException not caught in Cluster (replicate, fetch, server_loop)
  * Fix double save_store_to_buffer call in import retry logic

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

mediadb (20260403+25) unstable; urgency=medium

  * Import replication: retry up to 3 times on failure, discard on final failure
  * Fix Node Health showing duplicate self node after set_local_node change
  * Switch cluster from RAID1 mirroring to erasure coding (k+m shards)
  * Remove local in-memory block store, rely on distributed erasure-coded storage
  * repair_replication checks shard count (k+m) instead of total peers

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

mediadb (20260403+22) unstable; urgency=medium

  * Cluster::replicate checks peer count, fails if 0 peers reached

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

mediadb (20260403+21) unstable; urgency=medium

  * Reject import when cluster is not writable instead of storing locally
  * Cluster::replicate returns bool, stores locally only on peer success

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

mediadb (20260403+20) unstable; urgency=medium

  * Rebuild against libparitypp 20260403+4 (periodic resync)

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

mediadb (20260403+19) unstable; urgency=medium

  * Fix fork-kills-thread bug: move cluster.start() to post-fork callback
    so QUIC server thread survives daemonization (matches authdb pattern)

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

mediadb (20260403+18) unstable; urgency=medium

  * Rebuild against libnetplus 20260403+2 / libparitypp 20260403+3
    (QUIC client handshake debug logging)

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

mediadb (20260403+17) unstable; urgency=medium

  * Rebuild against libnetplus 20260403+1 / libparitypp 20260403+2
    (udp::sendTo, clean quic::sendPacket)

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

mediadb (20260403+16) unstable; urgency=medium

  * Rebuild against libnetplus 20260403 / libparitypp 20260403+1
    (QUIC Initial packet and ServerHello debug logging)

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

mediadb (20260403+15) unstable; urgency=medium

  * Rebuild against libparitypp 20260403 (cert load debug logging)

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

mediadb (20260403+14) unstable; urgency=medium

  * Generate DER format certificates and keys instead of PEM in postinst
  * Fix node health display: map pclient indices to config peer indices
    (self node no longer duplicates index 0)

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

mediadb (20260403+13) unstable; urgency=medium

  * Add self node to cluster status endpoint (correct nodes_total/nodes_online)
  * Add debug logging to import: stores, albums, media counts and stream state

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

mediadb (20260403+12) unstable; urgency=medium

  * Exclude local node from pclient QUIC connections — avoid auth/handshake errors
  * Query local store directly for list_peer_groups on self node
  * Map peer config indices to pclient node indices for correct remote queries

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

mediadb (20260403+11) unstable; urgency=medium

  * Import replicates each store directly to cluster during parsing
  * No more two-step import-then-replicate — stores go to peers immediately

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

mediadb (20260403+10) unstable; urgency=medium

  * Store locally before replicate_to_peers (match authdb pattern)
  * Remove Local column from cluster status HTML

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

mediadb (20260403+9) unstable; urgency=medium

  * Remove Local column from cluster status — local node is now a regular peer
  * Fix total_nodes count: no more +1 double-counting

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

mediadb (20260403+8) unstable; urgency=medium

  * Include local node in peer list — replicate directly to all nodes with parity
  * Remove is_self skip so local paritypp server participates as a regular peer

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

mediadb (20260403+7) unstable; urgency=medium

  * Fix cluster status: check availability via cluster fetch instead of empty local store
  * local_ok was always false because store_ has no data (no local cache)

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

mediadb (20260403+6) unstable; urgency=medium

  * Add debug logging to cluster replicate_store, replicate_index, import_db_from_buffer

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

mediadb (20260403+5) unstable; urgency=medium

  * Cluster: write directly to nodes, no local store — replicate and remove via pclient only
  * Fix import: link new media to existing albums (not only new albums)
  * sync_from_cluster always fetches from peers for fresh data

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

mediadb (20260403+4) unstable; urgency=medium

  * Remove all local paritypp store operations from Cluster (fetch, fetch_from_peers, remove)
  * All data goes exclusively through peers — no local cache reads or writes
  * Simplify sync_from_cluster: single fetch() call (now peers-only)
  * Remove local_ok status from cluster stores API endpoint

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

mediadb (20260403+3) unstable; urgency=medium

  * Remove local paritypp cache write on replicate — data goes directly to peers only

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

mediadb (20260403+2) unstable; urgency=medium

  * Fix intermittent store visibility: use fetch_from_peers in sync (like authdb)
  * Cluster::fetch() returns stale local cache, never checking peers for updates
  * Merge-only index sync: do not delete locally-present stores missing from synced index

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

mediadb (20260403+1) unstable; urgency=medium

  * Fix store sync ordering: replicate store data before index to prevent stale reads
  * Upgrade cluster_op_mutex_ to shared_mutex for concurrent read access
  * Add shared_lock to all ClusterMediaBackend read methods to prevent reads during sync

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

mediadb (20260402+5) unstable; urgency=medium

  * Fix race condition: sync_from_cluster could overwrite freshly written data
  * Add cluster_op_mutex_ to serialize all write+replicate operations vs sync

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

mediadb (20260402+4) unstable; urgency=medium

  * Fix import_db_from_buffer in cluster (memory-only) mode
  * Refactor import to stream-based import_from_stream, no temp file needed

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

mediadb (20260402+3) unstable; urgency=medium

  * Cluster mode: use paritypp block_store exclusively, no local files
  * Add memory-only BinDb mode for cluster backend
  * Buffer-based serialize/deserialize for index and store data

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

mediadb (20260402+2) unstable; urgency=medium

  * Fix cluster sync: fetch from peers instead of local store
  * Add comparison check to avoid unnecessary reloads

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

mediadb (20260402+1) unstable; urgency=medium

  * Fix cluster store replication: sync all store files, not just missing ones

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

mediadb (20260402) unstable; urgency=medium

  * Split monolithic main.cpp into modular source files
  * service file updated

 -- Jan Koester <jan.koester@tuxist.de>  Thu, 02 Apr 2026 18:11:50 +0200

mediadb (20260401+nmu1) UNRELEASED; urgency=medium

  * service file updated

 -- Jan Koester <jan.koester@tuxist.de>  Thu, 02 Apr 2026 18:11:50 +0200

mediadb (20260401) unstable; urgency=medium

  * Initial Debian packaging with multiarch support.

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