Git Commit History

This page provides a detailed history of all changes to the RedisAllocator project, automatically generated from Git commit messages.

Quick Summary

  • docs: clarify docker deployment scope by Qingrui Hu at 2026-06-30 05:36:52

  • bump: version 0.6.1 → 0.7.0 by Qingrui Hu at 2026-06-29 18:55:07

  • docs: add repository guidance and diagnostics plan by Qingrui Hu at 2026-06-29 18:54:56

  • docs: clarify orphan lock recovery by Qingrui Hu at 2026-06-29 18:49:12

  • test: stabilize assign performance benchmark by Qingrui Hu at 2026-06-29 18:12:47

Full History

  • docs: clarify docker deployment scope by Qingrui Hu at 2026-06-30 05:36:52

  • bump: version 0.6.1 → 0.7.0 by Qingrui Hu at 2026-06-29 18:55:07

  • docs: add repository guidance and diagnostics plan by Qingrui Hu at 2026-06-29 18:54:56

  • docs: clarify orphan lock recovery by Qingrui Hu at 2026-06-29 18:49:12

  • test: stabilize assign performance benchmark by Qingrui Hu at 2026-06-29 18:12:47

  • test: expand allocator performance contracts by Qingrui Hu at 2026-06-29 18:06:39

  • style: satisfy diagnostics lint by Qingrui Hu at 2026-06-29 17:42:30

  • docs: document allocator diagnostics by Qingrui Hu at 2026-06-29 17:40:50

  • feat: add live diagnostics dashboard UI by Qingrui Hu at 2026-06-29 17:38:10

  • feat: serve allocator diagnostics dashboard by Qingrui Hu at 2026-06-29 17:35:58

  • feat: add allocator diagnostics CLI by Qingrui Hu at 2026-06-29 17:34:19

  • feat: collect allocator diagnostics snapshots by Qingrui Hu at 2026-06-29 17:33:00

  • feat: add allocator diagnostics invariants by Qingrui Hu at 2026-06-29 17:29:19

  • feat: add diagnostics snapshot models by Qingrui Hu at 2026-06-29 17:27:48

  • docs: design allocator diagnostics dashboard by Qingrui Hu at 2026-06-29 16:59:15

  • feat: improve allocator cleanup and task timeouts by Qingrui Hu at 2026-06-29 16:06:06

  • bump: version 0.6.0 → 0.6.1 by Qingrui Hu at 2026-04-28 11:30:21

  • refactor: extract sentinels, derive prefixes from helpers, trim narrative comments by Qingrui Hu at 2026-04-28 10:35:42

    Code-review pass over the recent allocator hardening + test infrastructure
    work. Changes are zero-behavior — just simplification:
    
      - Extract ``ALLOCATED_SENTINEL`` and ``POOL_VALUE_SEP`` as module-level
        constants in redis_allocator/allocator.py and inject them into the
        Lua scripts via the existing f-string template. Both the Python
        ``_validate_keys`` path and ``tests/_bughunt_helpers.py`` now import
        the constants instead of re-hardcoding ``"#ALLOCATED"`` and ``"||"``.
    
      - In ``tests/_bughunt_helpers.py`` derive the lock-key and soft-bind
        prefixes from ``allocator._key_str("")`` and
        ``allocator._soft_bind_name("")`` rather than reformatting the
        ``prefix|suffix:`` shape inline (would silently drift if the producer
        changed its key layout). Switch ``_SNAPSHOT_SCRIPT_CACHE`` to a
        ``WeakKeyDictionary`` so cached Script entries are released with
        their Redis client instead of pinning by ``id()``.
    
      - ``tests/test_allocator_forensics.py``: bound the trace via
        ``collections.deque(maxlen=TRACE_TAIL + 200)`` so long runs cannot
        grow it without limit. Trim the file/test docstrings to drop the
        historical narrative.
    
      - Trim retrospective / "this fixes the user-reported X" comments out
        of allocator.py and the test files. The bug-history belongs in
        BUGHUNT_REPORT.md and the commit log, not in production source.
        The cleanup checklist in tests/conftest.py is reduced to one
        sentence pointing at the upstream PR.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    
  • docs: surface behavior contracts, testing layout, and recent hardening in README by Qingrui Hu at 2026-04-28 10:09:29

    Three additions to README.md:
    
      - "Behavior Contracts (Important for API Users)" section right after
        Core Features. Spells out the four intentional surprises a caller
        needs to know (timeout<=0 permanent locks, cache_timeout=0 permanent
        soft bindings, assign() not deleting evicted lock keys, extend/assign
        rejecting malformed pool keys with ValueError).
    
      - "Concurrency Safety" subsection after the architecture description,
        explaining the Lua-EVAL atomicity + lock-TTL + GC self-heal model
        so users understand what survives process crashes.
    
      - "Testing" top-level section before Roadmap, with the default unit
        suite, opt-in markers (concurrency / fuzz / benchmark), Docker
        stress driver, and a note about the temporary fakeredis monkey-patch
        bridging upstream PR #473.
    
    Roadmap "Recently Completed" gains three bullets covering the pool
    hardening work, the test infrastructure additions, and the validated
    O(1) performance contract — pointing to BUGHUNT_REPORT.md for detail.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    
  • build: relax fakeredis dep + restore HSET-O(1) monkey-patch as upstream-release bridge by Qingrui Hu at 2026-04-28 09:32:16

    Previous commit ab5b8ac dropped the conftest monkey-patch and bumped the
    fakeredis dep to >= 2.36.0 on the assumption that the upstream fix would
    be released. The fix has been merged
    (https://github.com/cunla/fakeredis-py/pull/473, commit 1e1173b on master)
    but no release tag yet contains it — the latest fakeredis on PyPI is
    still 2.35.1, so `pip install` against >= 2.36.0 cannot resolve.
    
    This commit restores the bridge:
      - setup.py: fakeredis[lua] dep relaxed back to >= 2.35.1 (PyPI-resolvable)
      - tests/conftest.py: re-add the idempotent _install_fakeredis_hset_o1_patch
        with a CLEANUP CHECKLIST comment that pinpoints the exact follow-up
        work (delete the block + bump dep + update CLAUDE.md) so it can be done
        in one clean commit when fakeredis releases the fix
      - CLAUDE.md: mention the temporary monkey-patch and link to PR #473
    
    The patch is no-op-equivalent on a future fakeredis where the upstream
    fix is already in place — re-installing the same len(h) logic is
    harmless.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    
  • build: bump fakeredis to >=2.36 and drop in-tree HSET monkey-patch by Qingrui Hu at 2026-04-26 16:53:53

    Switch the test dependency from fakeredis 2.20.1 to 2.36.0+. The local
    HSET-O(1) monkey-patch in tests/conftest.py was a workaround for a
    fakeredis upstream bug; the equivalent fix has been prepared as a PR
    against cunla/fakeredis-py and once merged + released will land
    naturally via this version bump.
    
    CLAUDE.md is updated to note that the benchmark suite needs the
    upstream fix to pass; for fresh installs from PyPI today the benchmark
    will report ~12x scaling instead of flat O(1) until the fakeredis PR
    ships. Local development against `pip install -e` of the patched fork
    (or any fakeredis ≥ next-release) keeps benchmark green.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    
  • docs: add bug-hunt report summarizing the three investigation rounds by Qingrui Hu at 2026-04-26 07:04:56

    Summarises every bug found, every fix applied, and every behavior
    classified as by-design (with an asserting test pinning the contract).
    
    Round 1 hunted single-process / static bugs: input validation,
    shrink-of-unknown-key, and the three by-design timeout/binding/lock
    contracts.
    
    Round 2 added concurrency tests and revealed that the original
    non-atomic watcher was producing false-positive INV violations under
    load. Replacing it with an atomic Lua-EVAL snapshot eliminated the
    noise and let the real bugs surface as Lua asserts.
    
    Round 3 chased the remaining real concurrency bugs to root cause:
    pop_from_head not maintaining headNext.prev across head removal,
    soft-binding lock-set ordered before chain mutation, and
    extend/assign re-adding keys without clearing residual lock state.
    After these fixes, real-Redis stress (60s/90s/16-worker/0.4s-kill)
    sustains zero invariant violations.
    
    Includes the marker policy, test categories, and a "what was not a
    bug" section so future maintainers don't re-investigate the same
    false positives.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    
  • test: add comprehensive bug-hunt, concurrency, fuzz, benchmark, and stress suites by Qingrui Hu at 2026-04-26 07:04:42

    Test infrastructure built up alongside the allocator hardening work:
    
    - tests/_bughunt_helpers.py: PoolSnapshot helpers and check_invariants
      for INV-1..5 (linked-list integrity, pointer well-formedness,
      half-allocated detection, free/locked overlap, soft-binding refs).
      snapshot() uses a single Lua EVAL so head/tail/entries/locks are
      read atomically — eliminates the false-positive violations the
      original non-atomic watcher produced under concurrent load.
    
    - tests/test_allocator_bughunt.py: per-bug regression + by-design
      contract tests (~30 cases). Covers input validation rejections,
      shrink/free no-op, zombie resurrection, and the by-design contracts
      for timeout<=0 permanent locks, cache_timeout=0 permanent bindings,
      and assign() preserving evicted lock keys.
    
    - tests/test_allocator_fuzz.py: random operation sequences across
      parametrized seeds. Exercises serialized EVAL ordering edge cases.
    
    - tests/test_allocator_concurrency.py: multi-thread fakeredis stress
      asserting invariants are preserved under interleaved EVALs.
    
    - tests/test_allocator_forensics.py: same as concurrency but with
      per-method-call tracing so any future violation dumps the offending
      EVAL sequence.
    
    - tests/test_allocator_benchmark.py: O(1) contract for malloc/free
      and per-key extend cost; threshold MAX_SCALE_FACTOR=3.
    
    - tests/stress_pool_corruption.py: standalone Docker-driven stress
      driver (workers + abandoners + atomic watcher + murderer). Not a
      pytest test; run directly when validating against real Redis.
    
    - tests/_perf_real_redis.py: cross-checks the benchmark against a
      real Redis container, demonstrating the allocator's true O(1) and
      the fakeredis non-linearity that the conftest patch addresses.
    
    - tests/_profile_fakeredis.py: localised the upstream fakeredis
      HSET-is-O(n) issue (worth filing upstream).
    
    - tests/conftest.py: monkey-patches fakeredis HashCommandsMixin._hset
      to use len(h) instead of len(h.keys()) — Hash.keys() builds a
      fresh list each call (O(n)), so each HSET was O(n) on the hash
      size, masking the allocator's true O(1) cost on the benchmark.
      The patched _hset is semantically identical (same _expire_keys()
      and same returned count).
    
    - pyproject.toml: registers concurrency / fuzz / benchmark / stress
      pytest markers and sets default addopts to exclude all four.
      Default `pytest` runs only the fast unit suite (~7s); explicit
      `pytest -m <marker>` opts into each category.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    
  • fix(allocator): pool key validation, race-driven structural corruption, zombie key resurrection by Qingrui Hu at 2026-04-26 07:04:18

    Eight related fixes that together eliminate the user-reported "pool
    completely corrupted under multi-process load with mid-sequence kills":
    
    1. _validate_keys: reject keys equal to "", "#ALLOCATED", containing
       "||" (the on-disk separator), NUL bytes, or non-str types from
       extend()/assign(). Each pattern previously caused silent linked-list
       corruption (greedy regex mis-parse, sentinel collision, ambiguous
       empty-pointer).
    
    2. pop_from_head: locked-skip and expired branches now run a new
       _advance_head_after_removal() helper that updates headNext.prev = ""
       before recursing. The old code left headNext referencing a key that
       was either HDEL'd (expired branch) or now in #ALLOCATED state
       (locked-skip branch). A later set_item_allocated on the neighbor
       then wrote half-allocated "#ALLOCATED || real_key || ..." entries,
       tripping cascading Lua asserts ("prev value should not be nil",
       "next item should also be allocated", "head value should not be
       nil") that crashed every subsequent malloc — the headline corruption
       symptom in production.
    
    3. _free_script: HEXISTS guard before push_to_tail prevents free() from
       resurrecting a key that assign() already evicted from the pool.
    
    4. _shrink_script: HEXISTS guard before set_item_allocated makes
       shrink([unknown_key]) a silent no-op instead of a Lua assert.
    
    5. _malloc_script soft-binding: reorder set_item_allocated before SET
       lock. If set_item_allocated raised on a stale chain reference, the
       prior order left the lock in place while the entry stayed in free
       state — INV-4 (free + locked). New order aborts the EVAL cleanly
       with no orphan lock.
    
    6/7. _extend_script and _assign_script: DEL the lock key before
       push_to_tail when adding a fresh free node. Without this, a key
       re-extended after a previous incarnation was allocated-then-evicted
       would surface as free + locked (INV-4), since by-design #4 keeps
       locks alive across pool eviction.
    
    8. check_item_health: enable the previously commented-out
       "if locked then set_item_allocated(...)" branch so any future race
       producing INV-4 self-heals on the next gc() pass.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    
  • docs: add CLAUDE.md project guide for future Claude Code sessions by Qingrui Hu at 2026-04-26 07:03:54

    Captures the load-bearing architectural facts that take time to
    re-derive each session: the doubly-linked-list-in-a-hash pool layout,
    the _lua_required_string shared helper contract, shared-vs-exclusive
    allocation modes, the parametrized fixture convention in conftest, the
    minimal-change coding rule from .cursor/rules, the _version.py vs
    __init__.py version drift, and several "looks-like-a-bug-is-design"
    contracts (timeout<=0 permanent locks, cache_timeout=0 permanent
    bindings, assign() preserving lock keys).
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    
  • test: add comprehensive Redis allocator test suite with thread health and allocation scenarios by Qingrui Hu at 2025-05-19 07:39:42

  • bump: version 0.5.2 → 0.6.0 by Qingrui Hu at 2025-05-19 07:32:24

  • feat: implement Redis-based distributed memory allocator with health checks and soft binding by Qingrui Hu at 2025-05-18 16:43:44

  • bump: version 0.5.1 → 0.5.2 by Qingrui Hu at 2025-04-22 16:34:27

  • fix: update refresh_pool_all to use length of updater parameters by Qingrui Hu at 2025-04-22 16:34:23

    - Changed the loop in `refresh_pool_all` method to iterate based on the length of `updater.params` instead of the parameter itself, ensuring correct iteration count.
    
  • bump: version 0.5.0 → 0.5.1 by Qingrui Hu at 2025-04-22 16:30:08

  • fix: implement clear method in RedisAllocator and update refresh_pool_all by Qingrui Hu at 2025-04-22 16:30:01

    - Added a `clear` method in `RedisAllocator` to clear resources from the allocation pool and cache using a Lua script.
    - Updated the `refresh_pool_all` method in `DefaultRedisAllocatorPolicy` to call the new `clear` method on the allocator.
    
  • bump: version 0.4.6 → 0.5.0 by Qingrui Hu at 2025-04-22 16:22:47

  • feat: add refresh_pool_all method to RedisAllocatorPolicy and DefaultRedisAllocatorPolicy by Qingrui Hu at 2025-04-22 16:22:42

    - Introduced an abstract method `refresh_pool_all` in `RedisAllocatorPolicy` to define a contract for refreshing the allocation pool.
    - Implemented the `refresh_pool_all` method in `DefaultRedisAllocatorPolicy` to iterate and refresh the pool based on the updater parameters.
    
  • bump: version 0.4.5 → 0.4.6 by Qingrui Hu at 2025-04-22 16:04:31

  • fix: adjust timeout calculation in RedisAllocatorPolicy health check by Qingrui Hu at 2025-04-22 16:03:53

    - Modified the timeout parameter in the executor.map call to use only lock_duration, simplifying the logic and ensuring consistent health check behavior.
    
  • bump: version 0.4.4 → 0.4.5 by Qingrui Hu at 2025-04-21 21:17:25

  • fix: comment out assertion in RedisAllocator to prevent runtime errors by Qingrui Hu at 2025-04-21 21:17:20

    - Commented out the assertion that checks if both head and tail are empty, allowing for smoother operation when the free list is empty.
    - This change aims to prevent potential runtime errors during allocation processes.
    
  • bump: version 0.4.3 → 0.4.4 by Qingrui Hu at 2025-04-20 11:59:53

  • fix: refactor pointer management in RedisAllocator by Qingrui Hu at 2025-04-20 11:59:45

    - Introduced helper functions to streamline head and tail pointer retrieval and updates, improving code readability and maintainability.
    - Enhanced the push_to_tail and pop_from_head functions to ensure correct handling of the free list and item states.
    - Added a new get_free_list function to return the order of items in the free list without modifying the list structure.
    
  • fix: remove redundant head pointer update in RedisAllocator by Qingrui Hu at 2025-04-19 17:39:49

    - Eliminated unnecessary logic that updated the head pointer when the current head was removed, streamlining the allocation process.
    
  • bump: version 0.4.2 → 0.4.3 by Qingrui Hu at 2025-04-19 17:16:02

  • fix: enhance head and tail management in RedisAllocator by Qingrui Hu at 2025-04-19 17:15:56

    - Added logic to ensure the head and tail pointers are correctly updated when items are allocated or removed from the free list.
    - Implemented checks to handle corrupted pointers and maintain the integrity of the linked list structure.
    - Improved the handling of the current head's previous pointer to ensure it is always set to an empty string.
    
  • fix: update tail assertion in RedisAllocator to allow for allocated items by Qingrui Hu at 2025-04-19 10:00:00

    - Modified the assertion in the RedisAllocator class to check if the next item is either an empty string or marked as '#ALLOCATED', ensuring correct handling of the free list.
    
  • test: remove test for __del__ method in TestRedisAllocatorObject by Qingrui Hu at 2025-04-19 09:49:41

    - Removed the test_del method that tested the __del__ method of RedisAllocatorObject.
    - This change is part of the ongoing refactoring to improve test clarity and focus.
    
  • bump: version 0.4.1 → 0.4.2 by Qingrui Hu at 2025-04-18 14:27:48

  • fix: improve error logging and comment out __del__ method in RedisAllocatorObject by Qingrui Hu at 2025-04-18 14:26:45

    - Added error logging for failed object refresh attempts.
    - Commented out the __del__ method to prevent automatic closing of objects.
    
  • bump: version 0.4.0 → 0.4.1 by Qingrui Hu at 2025-04-17 13:44:02

  • refactor: enhance RedisAllocatorPolicy and DefaultRedisAllocatorPolicy with generic type support by Qingrui Hu at 2025-04-17 13:43:58

    - Updated RedisAllocatorPolicy to accept a generic type parameter.
    - Modified methods in RedisAllocatorPolicy and DefaultRedisAllocatorPolicy to utilize the generic type for improved type safety.
    - Adjusted the allocator initialization and method signatures accordingly.
    
  • bump: version 0.3.3 → 0.4.0 by Qingrui Hu at 2025-04-17 05:31:31

  • docs: update README files to clarify soft binding unbinding and correct PoolHash content representation by Qingrui Hu at 2025-04-17 05:31:15

  • feat: enhance RedisAllocator with health management and automatic closing features by Qingrui Hu at 2025-04-17 05:22:13

    - Added set_healthy method to mark objects as healthy.
    - Introduced refresh_until_healthy method to refresh objects until they are healthy.
    - Updated refresh method to include cache_timeout parameter.
    - Modified DefaultRedisAllocatorPolicy to support auto_close functionality for non-unique objects.
    
  • bump: version 0.3.2 → 0.3.3 by Qingrui Hu at 2025-04-16 13:36:45

  • fix: update open method to return self in RedisAllocatableClass and RedisAllocatorObject for improved chaining by Qingrui Hu at 2025-04-16 13:33:44

  • bump: version 0.3.1 → 0.3.2 by Qingrui Hu at 2025-04-16 13:11:13

  • fix: replace os.time with custom time function in RedisAllocator for improved accuracy in Lua scripts by Qingrui Hu at 2025-04-16 13:11:08

  • bump: version 0.3.0 → 0.3.1 by Qingrui Hu at 2025-04-16 08:56:06

  • refactor: move versioning to a dedicated _version.py file and update setup.py to read version dynamically by Qingrui Hu at 2025-04-16 08:56:01

  • feat: add health check methods to RedisAllocator for improved object management and reliability by Qingrui Hu at 2025-04-16 07:57:25

  • feat: add cachetools dependency and enhance RedisAllocator with new methods for object management and soft binding retrieval by Qingrui Hu at 2025-04-15 16:37:51

  • docs: update README and Chinese documentation to clarify RedisAllocator’s features, including resource pooling, atomic operations, and enhanced roadmap details; add example for managing a proxy pool with automatic updates by Qingrui Hu at 2025-04-14 20:01:06

  • docs: enhance README and Chinese documentation with simplified flow diagrams for RedisLock and RedisAllocator, improving clarity and understanding by Qingrui Hu at 2025-04-14 19:20:39

  • feat: enhance RedisAllocator with custom cache timeout for soft binding and improve documentation clarity by Qingrui Hu at 2025-04-14 18:49:46

  • feat: add unique ID handling and object lifecycle management in RedisAllocator by Qingrui Hu at 2025-04-14 15:42:18

  • refactor: simplify allocation logic in RedisAllocator and enhance Lua script handling for improved performance and clarity by Qingrui Hu at 2025-04-14 15:20:05

  • refactor: update tox configuration to use python instead of python3 and modify cursor rules to always apply; enhance RedisLock and RedisLockPool docstrings for clarity by Qingrui Hu at 2025-04-14 03:12:13

  • docs: introduce shared and soft binding modes in RedisAllocator, enhancing resource allocation flexibility and documentation by Qingrui Hu at 2025-04-13 05:07:51

  • docs: enhance README and documentation with RedisLock usage examples and key concepts for better clarity by Qingrui Hu at 2025-04-12 18:35:37

  • refactor: update tox configuration and improve test commands for flake8 and pytest by Qingrui Hu at 2025-04-12 17:26:00

  • feat: enhance RedisAllocator with a new allocation policy and refactor RedisAllocatableClass for improved configurability by Qingrui Hu at 2025-04-12 14:03:28

  • feat: implement timeout management in RedisAllocator tests with extend, assign, and free methods by Qingrui Hu at 2025-04-11 15:07:48

  • refactor: replace LUA script properties with cached properties in RedisAllocator for improved performance by Qingrui Hu at 2025-04-11 15:00:02

  • feat: add cursor rules for coding standards and enhance RedisAllocator with timeout management by Qingrui Hu at 2025-04-11 14:54:28

  • docs: add contributing guidelines and code of conduct to CONTRIBUTING.md by Qingrui Hu at 2025-04-11 10:37:18

  • style: fix whitespace inconsistencies in docstrings across allocator and task queue modules by Qingrui Hu at 2025-04-11 10:35:30

  • docs: update setup for redis-allocator and add documentation structure with Sphinx by Qingrui Hu at 2025-04-11 10:31:47

  • chore: add initial project structure with configuration files, README, and core modules for Redis-based resource allocation system by Qingrui Hu at 2025-04-11 10:03:31