Skip to content

Key handling: rename() overwrites an existing destination, and generic readers reject keys that merely contain the base key #126

Open

Description

@bigsamich

RedisAdapter version or revision

main at ff2d5b8; unchanged through the #108 → #109 → #111 stack (0c3b0e6).

Redis version and deployment mode

Redis 7.4.11 standalone (TCP).

Observed behavior

1. rename() overwrites an existing destination.

rename() is documented as "rename a home stream key (dest key must not exist)" (RedisAdapter.hpp), the same wording as copy(). But RedisConnection::rename issues RENAME, which silently replaces the destination, and the call reports success. A caller relying on the documented contract loses the destination stream's data without any error.

A missing source (ERR no such key) also triggers a full adapter reconnect (#123).

2. split_key() matches the base key as a substring.

The guard in addGenericReader()/removeGenericReader() is meant to reject keys of this adapter's own schema ({base}:sub). It uses key.find(_base_key) anywhere in the key, so any generic key that merely contains the base-key text is refused. addGenericReader returns false with no log and registers nothing. Short or common base keys make this likely.

The same substring match also decides the base/sub reported for dispatched entries on non-schema keys.

Expected:

  • rename() fails, without reconnecting, when the destination exists (or the docs say it overwrites);
  • only keys that start with {<base>} are treated as schema keys.

Reproduction

  • addSingleValue(src, "SRC-DATA"); addSingleValue(dst, "DST-DATA"); rename(src, dst) returns 1, and dst now holds SRC-DATA. The previous value is gone.
  • With base key "BPM": addGenericReader("raw_frames") = 1, addGenericReader("BPM_raw_frames") = 0, addGenericReader("LINAC:BPMs:raw") = 0.

Build and runtime environment

  • Ubuntu 24.04, gcc 13.3
  • pinned redis-plus-plus 1.3.15 and hiredis 1.3.0
  • a private Redis 7.4.11 in a container

Suggested fix

  • Use RENAMENX (redis-plus-plus renamenx) and return false when the destination exists. Treat no such key as a plain false, without reconnect(). If overwriting is intended, correct the header comment and docs instead.
  • Test for the exact schema prefix, const auto prefix = "{" + _base_key + "}"; key.compare(0, prefix.size(), prefix) == 0, and derive base/sub in split_key from the delimiter rather than from a substring hit.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions