Full Code of redis/go-redis for AI

master 7c6b09e2975f cached
402 files
3.8 MB
1.0M tokens
4857 symbols
1 requests
Download .txt
Showing preview only (4,091K chars total). Download the full file or copy to clipboard to get everything.
Repository: redis/go-redis
Branch: master
Commit: 7c6b09e2975f
Files: 402
Total size: 3.8 MB

Directory structure:
gitextract_z25o6z9o/

├── .github/
│   ├── CODEOWNERS
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── config.yml
│   ├── RELEASE_NOTES_TEMPLATE.md
│   ├── actions/
│   │   └── run-tests/
│   │       └── action.yml
│   ├── dependabot.yml
│   ├── release-drafter-config.yml
│   ├── spellcheck-settings.yml
│   ├── wordlist.txt
│   └── workflows/
│       ├── build.yml
│       ├── codeql-analysis.yml
│       ├── doctests.yaml
│       ├── golangci-lint.yml
│       ├── release-drafter.yml
│       ├── spellcheck.yml
│       ├── stale-issues.yml
│       ├── test-e2e.yml
│       └── test-redis-enterprise.yml
├── .gitignore
├── .golangci.yml
├── .prettierrc.yml
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── RELEASE-NOTES.md
├── RELEASING.md
├── acl_commands.go
├── acl_commands_test.go
├── adapters.go
├── async_handoff_integration_test.go
├── auth/
│   ├── auth.go
│   ├── auth_test.go
│   └── reauth_credentials_listener.go
├── bench_test.go
├── bitmap_commands.go
├── bitmap_commands_test.go
├── cluster_commands.go
├── command.go
├── command_digest_test.go
├── command_policy_resolver.go
├── command_recorder_test.go
├── command_test.go
├── commands.go
├── commands_test.go
├── dial_retry_backoff.go
├── digest_test.go
├── doc.go
├── docker-compose.yml
├── dockers/
│   ├── .gitignore
│   └── sentinel.conf
├── doctests/
│   ├── Makefile
│   ├── README.md
│   ├── bf_tutorial_test.go
│   ├── bitfield_tutorial_test.go
│   ├── bitmap_tutorial_test.go
│   ├── cmds_generic_test.go
│   ├── cmds_hash_test.go
│   ├── cmds_list_test.go
│   ├── cmds_servermgmt_test.go
│   ├── cmds_set_test.go
│   ├── cmds_sorted_set_test.go
│   ├── cmds_string_test.go
│   ├── cms_tutorial_test.go
│   ├── cuckoo_tutorial_test.go
│   ├── geo_index_test.go
│   ├── geo_tutorial_test.go
│   ├── hash_tutorial_test.go
│   ├── hll_tutorial_test.go
│   ├── home_json_example_test.go
│   ├── home_prob_dts_test.go
│   ├── json_tutorial_test.go
│   ├── list_tutorial_test.go
│   ├── lpush_lrange_test.go
│   ├── main_test.go
│   ├── pipe_trans_example_test.go
│   ├── query_agg_test.go
│   ├── query_em_test.go
│   ├── query_ft_test.go
│   ├── query_geo_test.go
│   ├── query_range_test.go
│   ├── search_quickstart_test.go
│   ├── set_get_test.go
│   ├── sets_example_test.go
│   ├── ss_tutorial_test.go
│   ├── stream_tutorial_test.go
│   ├── string_example_test.go
│   ├── tdigest_tutorial_test.go
│   ├── timeseries_tut_test.go
│   ├── topk_tutorial_test.go
│   └── vec_set_test.go
├── error.go
├── error_test.go
├── error_wrapping_test.go
├── example/
│   ├── cluster-mget/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── del-keys-without-ttl/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── digest-optimistic-locking/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── disable-maintnotifications/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── hll/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── hset-struct/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── lua-scripting/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── maintnotifiations-pubsub/
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── otel/
│   │   ├── README.md
│   │   ├── client.go
│   │   ├── config/
│   │   │   ├── otel-collector.yaml
│   │   │   └── vector.toml
│   │   ├── docker-compose.yml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── uptrace.yml
│   ├── otel-metrics/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── redis-bloom/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── scan-struct/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── tls-cert-auth/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   └── tls-connection/
│       ├── README.md
│       ├── go.mod
│       ├── go.sum
│       └── main.go
├── example_instrumentation_test.go
├── example_test.go
├── export_test.go
├── extra/
│   ├── rediscensus/
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── rediscensus.go
│   ├── rediscmd/
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── rediscmd.go
│   │   ├── rediscmd_test.go
│   │   ├── safe.go
│   │   └── unsafe.go
│   ├── redisotel/
│   │   ├── README.md
│   │   ├── config.go
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── metrics.go
│   │   ├── metrics_test.go
│   │   ├── tracing.go
│   │   └── tracing_test.go
│   ├── redisotel-native/
│   │   ├── attributes.go
│   │   ├── config.go
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── metrics.go
│   │   ├── metrics_definitions_test.go
│   │   ├── metrics_stress_test.go
│   │   └── redisotel.go
│   └── redisprometheus/
│       ├── README.md
│       ├── collector.go
│       ├── go.mod
│       └── go.sum
├── fuzz/
│   └── fuzz.go
├── generic_commands.go
├── geo_commands.go
├── go.mod
├── go.sum
├── hash_commands.go
├── helper/
│   ├── helper.go
│   └── helper_test.go
├── hotkeys_commands.go
├── hotkeys_commands_test.go
├── hset_benchmark_test.go
├── hyperloglog_commands.go
├── internal/
│   ├── arg.go
│   ├── auth/
│   │   └── streaming/
│   │       ├── conn_reauth_credentials_listener.go
│   │       ├── cred_listeners.go
│   │       ├── manager.go
│   │       ├── manager_test.go
│   │       ├── pool_hook.go
│   │       └── pool_hook_state_test.go
│   ├── customvet/
│   │   ├── .gitignore
│   │   ├── checks/
│   │   │   └── setval/
│   │   │       ├── setval.go
│   │   │       ├── setval_test.go
│   │   │       └── testdata/
│   │   │           └── src/
│   │   │               └── a/
│   │   │                   └── a.go
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── hashtag/
│   │   ├── hashtag.go
│   │   └── hashtag_test.go
│   ├── hscan/
│   │   ├── hscan.go
│   │   ├── hscan_test.go
│   │   └── structmap.go
│   ├── interfaces/
│   │   └── interfaces.go
│   ├── internal.go
│   ├── internal_test.go
│   ├── log.go
│   ├── maintnotifications/
│   │   └── logs/
│   │       └── log_messages.go
│   ├── once.go
│   ├── otel/
│   │   └── metrics.go
│   ├── pool/
│   │   ├── bench_test.go
│   │   ├── buffer_size_test.go
│   │   ├── conn.go
│   │   ├── conn_check.go
│   │   ├── conn_check_dummy.go
│   │   ├── conn_check_test.go
│   │   ├── conn_relaxed_timeout_test.go
│   │   ├── conn_state.go
│   │   ├── conn_state_alloc_test.go
│   │   ├── conn_state_test.go
│   │   ├── conn_used_at_test.go
│   │   ├── dial_conn_retry_test.go
│   │   ├── dial_context_timeout_test.go
│   │   ├── dial_retry_backoff_test.go
│   │   ├── double_freeturn_simple_test.go
│   │   ├── double_freeturn_test.go
│   │   ├── export_test.go
│   │   ├── hooks.go
│   │   ├── hooks_test.go
│   │   ├── main_test.go
│   │   ├── pool.go
│   │   ├── pool_single.go
│   │   ├── pool_sticky.go
│   │   ├── pool_test.go
│   │   ├── pubsub.go
│   │   ├── try_dial_test.go
│   │   ├── want_conn.go
│   │   └── want_conn_test.go
│   ├── proto/
│   │   ├── peek_push_notification_test.go
│   │   ├── proto_test.go
│   │   ├── reader.go
│   │   ├── reader_test.go
│   │   ├── redis_errors.go
│   │   ├── redis_errors_test.go
│   │   ├── scan.go
│   │   ├── scan_test.go
│   │   ├── writer.go
│   │   └── writer_test.go
│   ├── rand/
│   │   └── rand.go
│   ├── redis.go
│   ├── routing/
│   │   ├── aggregator.go
│   │   ├── aggregator_test.go
│   │   ├── policy.go
│   │   └── shard_picker.go
│   ├── semaphore.go
│   ├── util/
│   │   ├── atomic_max.go
│   │   ├── atomic_min.go
│   │   ├── convert.go
│   │   ├── convert_test.go
│   │   ├── safe.go
│   │   ├── strconv.go
│   │   ├── strconv_test.go
│   │   ├── type.go
│   │   ├── unsafe.go
│   │   └── unsafe_test.go
│   ├── util.go
│   └── util_test.go
├── internal_maint_notif_test.go
├── internal_test.go
├── iterator.go
├── iterator_test.go
├── json.go
├── json_test.go
├── list_commands.go
├── logging/
│   ├── logging.go
│   └── logging_test.go
├── main_test.go
├── maintnotifications/
│   ├── FEATURES.md
│   ├── README.md
│   ├── circuit_breaker.go
│   ├── circuit_breaker_test.go
│   ├── config.go
│   ├── config_test.go
│   ├── e2e/
│   │   ├── .gitignore
│   │   ├── DATABASE_MANAGEMENT.md
│   │   ├── README_SCENARIOS.md
│   │   ├── cluster_maintnotif_test.go
│   │   ├── cmd/
│   │   │   └── proxy-fi-server/
│   │   │       ├── Dockerfile
│   │   │       └── main.go
│   │   ├── command_runner_test.go
│   │   ├── config_autostart_logic_test.go
│   │   ├── config_parser_test.go
│   │   ├── doc.go
│   │   ├── examples/
│   │   │   └── endpoints.json
│   │   ├── fault_injector.go
│   │   ├── logcollector_test.go
│   │   ├── main_test.go
│   │   ├── notification_injector_test.go
│   │   ├── notiftracker_test.go
│   │   ├── proxy_fault_injector_server.go
│   │   ├── scenario_endpoint_types_test.go
│   │   ├── scenario_push_notifications_test.go
│   │   ├── scenario_stress_test.go
│   │   ├── scenario_template.go.example
│   │   ├── scenario_timeout_configs_test.go
│   │   ├── scenario_tls_configs_test.go
│   │   ├── scenario_unified_injector_test.go
│   │   ├── scripts/
│   │   │   └── run-e2e-tests.sh
│   │   ├── slot_keys_test.go
│   │   ├── test_mode_test.go
│   │   └── utils_test.go
│   ├── errors.go
│   ├── example_hooks.go
│   ├── handoff_worker.go
│   ├── hooks.go
│   ├── manager.go
│   ├── manager_test.go
│   ├── pool_hook.go
│   ├── pool_hook_test.go
│   ├── push_notification_handler.go
│   ├── push_notification_handler_test.go
│   └── state.go
├── monitor_test.go
├── options.go
├── options_test.go
├── osscluster.go
├── osscluster_commands.go
├── osscluster_lazy_reload_test.go
├── osscluster_maintnotifications_test.go
├── osscluster_maintnotifications_unit_test.go
├── osscluster_router.go
├── osscluster_test.go
├── otel.go
├── pipeline.go
├── pipeline_test.go
├── pool_pubsub_bench_test.go
├── pool_test.go
├── probabilistic.go
├── probabilistic_test.go
├── pubsub.go
├── pubsub_commands.go
├── pubsub_test.go
├── push/
│   ├── errors.go
│   ├── handler.go
│   ├── handler_context.go
│   ├── processor.go
│   ├── processor_unit_test.go
│   ├── push.go
│   ├── push_test.go
│   └── registry.go
├── push_notifications.go
├── race_test.go
├── redis.go
├── redis_test.go
├── result.go
├── ring.go
├── ring_test.go
├── script.go
├── scripting_commands.go
├── scripts/
│   ├── bump_deps.sh
│   ├── release.sh
│   └── tag.sh
├── search_builders.go
├── search_builders_test.go
├── search_commands.go
├── search_commands_parse_test.go
├── search_test.go
├── sentinel.go
├── sentinel_test.go
├── set_commands.go
├── sortedset_commands.go
├── stream_commands.go
├── string_commands.go
├── timeseries_commands.go
├── timeseries_commands_test.go
├── tls_cert_auth_test.go
├── tls_cluster_test.go
├── tls_standalone_test.go
├── tls_test.go
├── tx.go
├── tx_test.go
├── unit_test.go
├── universal.go
├── universal_test.go
├── vectorset_commands.go
├── vectorset_commands_integration_test.go
├── vectorset_commands_test.go
└── version.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/CODEOWNERS
================================================
doctests/* @dmaier-redislabs


================================================
FILE: .github/FUNDING.yml
================================================
custom: ['https://uptrace.dev/sponsor']


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---

Issue tracker is used for reporting bugs and discussing new features. Please use
[stackoverflow](https://stackoverflow.com) for supporting issues.

<!--- Provide a general summary of the issue in the Title above -->

## Expected Behavior

<!--- Tell us what should happen -->

## Current Behavior

<!--- Tell us what happens instead of the expected behavior -->

## Possible Solution

<!--- Not obligatory, but suggest a fix/reason for the bug, -->

## Steps to Reproduce

<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->

1.
2.
3.
4.

## Context (Environment)

<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->

<!--- Provide a general summary of the issue in the Title above -->

## Detailed Description

<!--- Provide a detailed description of the change or addition you are proposing -->

## Possible Implementation

<!--- Not obligatory, but suggest an idea for implementing addition or change -->


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
contact_links:
  - name: Discussions
    url: https://github.com/go-redis/redis/discussions
    about: Ask a question via GitHub Discussions


================================================
FILE: .github/RELEASE_NOTES_TEMPLATE.md
================================================
# Release Notes Template for go-redis

This template provides a structured format for creating release notes for go-redis releases.

## Format Structure

```markdown
# X.Y.Z (YYYY-MM-DD)

## 🚀 Highlights

### [Category Name]
Brief description of the major feature/change with context and impact.
- Key points
- Performance metrics if applicable
- Links to documentation

### [Another Category]
...

## ✨ New Features

- Feature description ([#XXXX](https://github.com/redis/go-redis/pull/XXXX)) by [@username](https://github.com/username)
- ...

## 🐛 Bug Fixes

- Fix description ([#XXXX](https://github.com/redis/go-redis/pull/XXXX)) by [@username](https://github.com/username)
- ...

## ⚡ Performance

- Performance improvement description ([#XXXX](https://github.com/redis/go-redis/pull/XXXX)) by [@username](https://github.com/username)
- ...

## 🧪 Testing & Infrastructure

- Testing/CI improvement ([#XXXX](https://github.com/redis/go-redis/pull/XXXX)) by [@username](https://github.com/username)
- ...

## 👥 Contributors

We'd like to thank all the contributors who worked on this release!

[@username1](https://github.com/username1), [@username2](https://github.com/username2), ...

---

**Full Changelog**: https://github.com/redis/go-redis/compare/vX.Y-1.Z...vX.Y.Z
```

## Guidelines

### Highlights Section
The Highlights section should contain the **most important** user-facing changes. Common categories include:

- **Typed Errors** - Error handling improvements
- **New Commands** - New Redis commands support (especially for new Redis versions)
- **Search & Vector** - RediSearch and vector-related features
- **Connection Pool** - Pool improvements and performance
- **Metrics & Observability** - Monitoring and instrumentation
- **Breaking Changes** - Any breaking changes (should be prominent)

Each highlight should:
- Have a descriptive title
- Include context about why it matters
- Link to relevant PRs
- Include performance metrics if applicable

### New Features Section
- List all new features with PR links and contributor attribution
- Use descriptive text, not just PR titles
- Group related features together if it makes sense

### Bug Fixes Section
- Only include actual bug fixes
- Be specific about what was broken and how it's fixed
- Include issue links if the PR references an issue

### Performance Section
- Separate from New Features to highlight performance work
- Include metrics when available (e.g., "47-67% faster", "33% less memory")
- Explain the impact on users

### Testing & Infrastructure Section
- Include only important testing/CI changes
- **Exclude** dependency bumps (e.g., dependabot PRs for actions)
- **Exclude** minor CI tweaks unless they're significant
- Include major Redis version updates in CI

### What to Exclude
- Dependency bumps (dependabot PRs)
- Minor documentation typo fixes
- Internal refactoring that doesn't affect users
- Duplicate entries (same PR in multiple sections)
- `dependabot[bot]` from contributors list

### Formatting Rules
1. **PR Links**: Use `([#XXXX](https://github.com/redis/go-redis/pull/XXXX))` format
2. **Contributor Links**: Use `[@username](https://github.com/username)` format
3. **Issue Links**: Use `([#XXXX](https://github.com/redis/go-redis/issues/XXXX))` format
4. **Full Changelog**: Always include at the bottom with correct version comparison

### Getting PR Information
Use GitHub API to fetch PR details:
```bash
# Get recent merged PRs
gh pr list --state merged --limit 50 --json number,title,author,mergedAt,url
```

Or use the GitHub web interface to review merged PRs between releases.

### Example Workflow
1. Gather all merged PRs since last release
2. Categorize PRs by type (feature, bug fix, performance, etc.)
3. Identify the 3-5 most important changes for Highlights
4. Remove duplicates and dependency bumps
5. Add PR and contributor links
6. Review for clarity and completeness
7. Add Full Changelog link with correct version tags

## Example (v9.17.0)

See the v9.17.0 release notes in `RELEASE-NOTES.md` for a complete example following this template.



================================================
FILE: .github/actions/run-tests/action.yml
================================================
name: 'Run go-redis tests'
description: 'Runs go-redis tests against different Redis versions and configurations'
inputs:
  go-version:
    description: 'Go version to use for running tests'
    default: '1.24'
  redis-version:
    description: 'Redis version to test against'
    required: true
runs:
  using: "composite"
  steps:
    - name: Set up ${{ inputs.go-version }}
      uses: actions/setup-go@v6
      with:
        go-version: ${{ inputs.go-version }}

    - name: Setup Test environment
      env:
        REDIS_VERSION: ${{ inputs.redis-version }}
      run: |
        set -e
        redis_version_np=$(echo "$REDIS_VERSION" | grep -oP '^\d+.\d+')

        # Mapping of redis version to redis testing containers
        declare -A redis_version_mapping=(
          ["8.6.x"]="custom-21860421418-debian-amd64"
          ["8.4.x"]="8.4.0"
          ["8.2.x"]="8.2.1-pre"
          ["8.0.x"]="8.0.2"
        )

        if [[ -v redis_version_mapping[$REDIS_VERSION] ]]; then
          echo "REDIS_VERSION=${redis_version_np}" >> $GITHUB_ENV
          echo "REDIS_IMAGE=redis:${REDIS_VERSION}" >> $GITHUB_ENV
          echo "CLIENT_LIBS_TEST_IMAGE=redislabs/client-libs-test:${redis_version_mapping[$REDIS_VERSION]}" >> $GITHUB_ENV
        else
          echo "Version not found in the mapping."
          exit 1
        fi
        sleep 10 # wait for redis to start
      shell: bash
    - name: Set up Docker Compose environment with redis ${{ inputs.redis-version }}
      run: |
        make docker.start
        sleep 5
      shell: bash
    - name: Run tests
      env:
        RCE_DOCKER: "true"
        RE_CLUSTER: "false"
      run: |
        make test.ci
      shell: bash

================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: gomod
  directory: /
  schedule:
    interval: weekly
- package-ecosystem: github-actions
  directory: /
  schedule:
    interval: weekly


================================================
FILE: .github/release-drafter-config.yml
================================================
name-template: '$NEXT_MINOR_VERSION'
tag-template: 'v$NEXT_MINOR_VERSION'
autolabeler:
  - label: 'maintenance'
    files:
      - '*.md'
      - '.github/*'
  - label: 'bug'
    branch:
      - '/bug-.+'
  - label: 'maintenance'
    branch:
      - '/maintenance-.+'
  - label: 'feature'
    branch:
      - '/feature-.+'
categories:
  - title: 'Breaking Changes'
    labels:
      - 'breakingchange'
  - title: '🧪 Experimental Features'
    labels:
      - 'experimental'
  - title: '🚀 New Features'
    labels:
      - 'feature'
      - 'enhancement'
  - title: '🐛 Bug Fixes'
    labels:
      - 'fix'
      - 'bugfix'
      - 'bug'
      - 'BUG'
  - title: '🧰 Maintenance'
    label: 'maintenance'
change-template: '- $TITLE (#$NUMBER)'
exclude-labels:
  - 'skip-changelog'
exclude-contributors:
  - 'dependabot'
template: |
  # Changes

  $CHANGES

  ## Contributors
  We'd like to thank all the contributors who worked on this release!

  $CONTRIBUTORS



================================================
FILE: .github/spellcheck-settings.yml
================================================
matrix:
- name: Markdown
  expect_match: false
  apsell:
    lang: en
    d: en_US
    ignore-case: true
  dictionary:
    wordlists:
    - .github/wordlist.txt
    output: wordlist.dic
  pipeline:
  - pyspelling.filters.markdown:
      markdown_extensions:
      - markdown.extensions.extra:
  - pyspelling.filters.html:
      comments: false
      attributes:
      - alt
      ignores:
      - ':matches(code, pre)'
      - code
      - pre
      - blockquote
      - img
  sources:
  - 'README.md'
  - 'FAQ.md'
  - 'docs/**'


================================================
FILE: .github/wordlist.txt
================================================
ACLs
APIs
autoload
autoloader
autoloading
analytics
Autoloading
backend
backends
behaviour
CAS
ClickHouse
config
customizable
Customizable
dataset
de
DisableIdentity
ElastiCache
extensibility
FPM
Golang
IANA
keyspace
keyspaces
Kvrocks
localhost
Lua
MSSQL
namespace
NoSQL
OpenTelemetry
ORM
Packagist
PhpRedis
pipelining
pluggable
Predis
PSR
Quickstart
README
rebalanced
rebalancing
redis
Redis
RocksDB
runtime
SHA
sharding
SETNAME
SpellCheck
SSL
struct
stunnel
SynDump
TCP
TLS
UnstableResp
uri
URI
url
variadic
RedisStack
RedisGears
RedisTimeseries
RediSearch
RawResult
RawVal
entra
EntraID
Entra
OAuth
Azure
StreamingCredentialsProvider
oauth
entraid
MiB
KiB
oldstable
backoff


================================================
FILE: .github/workflows/build.yml
================================================
name: Go

on:
  push:
    branches: [master, v9, 'v9.*']
  pull_request:
    branches: [master, v9, v9.7, v9.8, 'ndyakov/**', 'ofekshenawa/**', 'ce/**']

permissions:
  contents: read

jobs:

  benchmark:
    name: benchmark
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        redis-version:
          - "8.6.x" # Redis CE 8.6
          - "8.4.x" # Redis CE 8.4
          - "8.2.x" # Redis CE 8.2
          - "8.0.x" # Redis CE 8.0
        go-version:
          - "1.24.x"
          - oldstable
          - stable

    steps:
      - name: Set up ${{ matrix.go-version }}
        uses: actions/setup-go@v6
        with:
          go-version: ${{ matrix.go-version }}

      - name: Checkout code
        uses: actions/checkout@v6

      - name: Setup Test environment
        env:
          REDIS_VERSION: ${{ matrix.redis-version }}
          CLIENT_LIBS_TEST_IMAGE: "redislabs/client-libs-test:${{ matrix.redis-version }}"
        run: |
          set -e
          redis_version_np=$(echo "$REDIS_VERSION" | grep -oP '^\d+.\d+')
          
          # Mapping of redis version to redis testing containers
          declare -A redis_version_mapping=(
            ["8.6.x"]="custom-21860421418-debian-amd64"
            ["8.4.x"]="8.4.0"
            ["8.2.x"]="8.2.1-pre"
            ["8.0.x"]="8.0.2"
          )
          if [[ -v redis_version_mapping[$REDIS_VERSION] ]]; then
            echo "REDIS_VERSION=${redis_version_np}" >> $GITHUB_ENV
            echo "REDIS_IMAGE=redis:${{ matrix.redis-version }}" >> $GITHUB_ENV
            echo "CLIENT_LIBS_TEST_IMAGE=redislabs/client-libs-test:${redis_version_mapping[$REDIS_VERSION]}" >> $GITHUB_ENV
          else
            echo "Version not found in the mapping."
            exit 1
          fi
        shell: bash
      - name: Set up Docker Compose environment with redis ${{ matrix.redis-version }}
        run: make docker.start
        shell: bash
      - name: Benchmark Tests
        env:
          RCE_DOCKER: "true"
          RE_CLUSTER: "false"
        run: make bench
        shell: bash

  test-redis-ce:
    name: test-redis-ce
    runs-on: ubuntu-latest
    strategy:
        fail-fast: false
        matrix:
          redis-version:
            - "8.6.x" # Redis CE 8.6
            - "8.4.x" # Redis CE 8.4
            - "8.2.x" # Redis CE 8.2
            - "8.0.x" # Redis CE 8.0
          go-version:
            - "1.24.x"
            - oldstable
            - stable

    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Run tests
        uses: ./.github/actions/run-tests
        with:
          go-version: ${{matrix.go-version}}
          redis-version: ${{ matrix.redis-version }}

      - name: Upload to Codecov
        uses: codecov/codecov-action@v5
        with:
          files: coverage.txt
          token: ${{ secrets.CODECOV_TOKEN }}



================================================
FILE: .github/workflows/codeql-analysis.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"

on:
  push:
    branches: [master, v9, v9.7, v9.8]
  pull_request:
    branches: [master, v9, v9.7, v9.8]

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: [ 'go' ]
        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
        # Learn more about CodeQL language support at https://git.io/codeql-language-support

    steps:
    - name: Checkout repository
      uses: actions/checkout@v6

    # Initializes the CodeQL tools for scanning.
    - name: Initialize CodeQL
      uses: github/codeql-action/init@v4
      with:
        languages: ${{ matrix.language }}
        # If you wish to specify custom queries, you can do so here or in a config file.
        # By default, queries listed here will override any specified in a config file.
        # Prefix the list here with "+" to use these queries and those in the config file.
        # queries: ./path/to/local/query, your-org/your-repo/queries@main

    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
    # If this step fails, then you should remove it and run the build manually (see below)
    - name: Autobuild
      uses: github/codeql-action/autobuild@v4

    # ℹ️ Command-line programs to run using the OS shell.
    # 📚 https://git.io/JvXDl

    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
    #    and modify them (or add more) to build your code if your project
    #    uses a compiled language

    #- run: |
    #   make bootstrap
    #   make release

    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v4


================================================
FILE: .github/workflows/doctests.yaml
================================================
name: Documentation Tests

on:
  push:
    branches: [master, examples]
  pull_request:
    branches: [master, examples]

permissions:
  contents: read

jobs:
  doctests:
    name: doctests
    runs-on: ubuntu-latest

    services:
      redis-stack:
        image: redislabs/client-libs-test:custom-21860421418-debian-amd64
        env:
          TLS_ENABLED: no
          REDIS_CLUSTER: no
          PORT: 6379
        ports:
          - 6379:6379

    strategy:
      fail-fast: false
      matrix:
        go-version: ["1.24"]

    steps:
      - name: Set up ${{ matrix.go-version }}
        uses: actions/setup-go@v6
        with:
          go-version: ${{ matrix.go-version }}

      - name: Checkout code
        uses: actions/checkout@v6

      - name: Test doc examples
        working-directory: ./doctests
        run: make test


================================================
FILE: .github/workflows/golangci-lint.yml
================================================
name: golangci-lint

on:
  push:
    tags:
      - v*
    branches:
      - master
      - main
      - v9
      - v9.8
  pull_request:

permissions:
  contents: read
  pull-requests: read  # for golangci/golangci-lint-action to fetch pull requests

jobs:
  golangci:
    name: lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: golangci-lint
        uses: golangci/golangci-lint-action@v9.2.0
        with:
          verify: true 



================================================
FILE: .github/workflows/release-drafter.yml
================================================
name: Release Drafter

on:
  push:
    # branches to consider in the event; optional, defaults to all
    branches:
      - master

permissions: {}
jobs:
  update_release_draft:
    permissions:
      pull-requests: write  #  to add label to PR (release-drafter/release-drafter)
      contents: write  #  to create a github release (release-drafter/release-drafter)

    runs-on: ubuntu-latest
    steps:
      # Drafts your next Release notes as Pull Requests are merged into "master"
      - uses: release-drafter/release-drafter@v7
        with:
          # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
           config-name: release-drafter-config.yml
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .github/workflows/spellcheck.yml
================================================
name: spellcheck
on:
  pull_request:
jobs:
  check-spelling:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Check Spelling
        uses: rojopolis/spellcheck-github-actions@0.60.0
        with:
          config_path: .github/spellcheck-settings.yml
          task_name: Markdown


================================================
FILE: .github/workflows/stale-issues.yml
================================================
name: "Stale Issue Management"
on:
  schedule:
    # Run daily at midnight UTC
    - cron: "0 0 * * *"
  workflow_dispatch: # Allow manual triggering

env:
  # Default stale policy timeframes
  DAYS_BEFORE_STALE: 365
  DAYS_BEFORE_CLOSE: 30

  # Accelerated timeline for needs-information issues
  NEEDS_INFO_DAYS_BEFORE_STALE: 30
  NEEDS_INFO_DAYS_BEFORE_CLOSE: 7

jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
      # First step: Handle regular issues (excluding needs-information)
      - name: Mark regular issues as stale
        uses: actions/stale@v10
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}

          # Default stale policy
          days-before-stale: ${{ env.DAYS_BEFORE_STALE }}
          days-before-close: ${{ env.DAYS_BEFORE_CLOSE }}

          # Explicit stale label configuration
          stale-issue-label: "stale"
          stale-pr-label: "stale"

          stale-issue-message: |
            This issue has been automatically marked as stale due to inactivity.
            It will be closed in 30 days if no further activity occurs.
            If you believe this issue is still relevant, please add a comment to keep it open.

          close-issue-message: |
            This issue has been automatically closed due to inactivity.
            If you believe this issue is still relevant, please reopen it or create a new issue with updated information.

          # Exclude needs-information issues from this step
          exempt-issue-labels: 'no-stale,needs-information'

          # Remove stale label when issue/PR becomes active again
          remove-stale-when-updated: true

          # Apply to pull requests with same timeline
          days-before-pr-stale: ${{ env.DAYS_BEFORE_STALE }}
          days-before-pr-close: ${{ env.DAYS_BEFORE_CLOSE }}

          stale-pr-message: |
            This pull request has been automatically marked as stale due to inactivity.
            It will be closed in 30 days if no further activity occurs.

          close-pr-message: |
            This pull request has been automatically closed due to inactivity.
            If you would like to continue this work, please reopen the PR or create a new one.

          # Only exclude no-stale PRs (needs-information PRs follow standard timeline)
          exempt-pr-labels: 'no-stale'

      # Second step: Handle needs-information issues with accelerated timeline
      - name: Mark needs-information issues as stale
        uses: actions/stale@v10
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}

          # Accelerated timeline for needs-information
          days-before-stale: ${{ env.NEEDS_INFO_DAYS_BEFORE_STALE }}
          days-before-close: ${{ env.NEEDS_INFO_DAYS_BEFORE_CLOSE }}

          # Explicit stale label configuration
          stale-issue-label: "stale"

          # Only target ISSUES with needs-information label (not PRs)
          only-issue-labels: 'needs-information'

          stale-issue-message: |
            This issue has been marked as stale because it requires additional information
            that has not been provided for 30 days. It will be closed in 7 days if the
            requested information is not provided.

          close-issue-message: |
            This issue has been closed because the requested information was not provided within the specified timeframe.
            If you can provide the missing information, please reopen this issue or create a new one.

          # Disable PR processing for this step
          days-before-pr-stale: -1
          days-before-pr-close: -1

          # Remove stale label when issue becomes active again
          remove-stale-when-updated: true


================================================
FILE: .github/workflows/test-e2e.yml
================================================
name: E2E Tests

on:
  push:
    branches: [master, v9, 'v9.*']
  pull_request:
    branches: [master, v9, v9.7, v9.8, 'ndyakov/**', 'ofekshenawa/**', 'ce/**']

permissions:
  contents: read

jobs:
  test-e2e-mock:
    name: E2E Tests (Mock Proxy)
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        go-version:
          - stable

    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Set up Go ${{ matrix.go-version }}
        uses: actions/setup-go@v6
        with:
          go-version: ${{ matrix.go-version }}

      - name: Start Docker services for E2E tests
        run: make docker.e2e.start

      - name: Wait for services to be ready
        run: |
          echo "Waiting for Redis to be ready..."
          timeout 30 bash -c 'until docker exec redis-standalone redis-cli ping 2>/dev/null; do sleep 1; done'
          echo "Waiting for cae-resp-proxy to be ready..."
          timeout 30 bash -c 'until curl -s http://localhost:18100/stats > /dev/null; do sleep 1; done'
          echo "All services are ready!"

      - name: Run E2E tests with mock proxy
        env:
          E2E_SCENARIO_TESTS: "true"
        run: |
          go test -v ./maintnotifications/e2e/ -timeout 30m -race
        continue-on-error: false

      - name: Stop Docker services
        if: always()
        run: make docker.e2e.stop

      - name: Show Docker logs on failure
        if: failure()
        run: |
          echo "=== Redis logs ==="
          docker logs redis-standalone 2>&1 | tail -100
          echo "=== cae-resp-proxy logs ==="
          docker logs cae-resp-proxy 2>&1 | tail -100
          echo "=== proxy-fault-injector logs ==="
          docker logs proxy-fault-injector 2>&1 | tail -100



================================================
FILE: .github/workflows/test-redis-enterprise.yml
================================================
name: RE Tests

on:
  push:
    branches: [master, v9, v9.7, v9.8]
  pull_request:

permissions:
  contents: read

jobs:
  build:
    name: build
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        go-version: [1.24.x]
        re-build: ["7.4.2-54"]

    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Clone Redis EE docker repository
        uses: actions/checkout@v6
        with:
          repository: RedisLabs/redis-ee-docker
          path: redis-ee

      - name: Set up ${{ matrix.go-version }}
        uses: actions/setup-go@v6
        with:
          go-version: ${{ matrix.go-version }}

      - name: Build cluster
        working-directory: redis-ee
        env:
          IMAGE: "redislabs/redis:${{ matrix.re-build }}"
          RE_USERNAME: test@test.com
          RE_PASS: 12345
          RE_CLUSTER_NAME: re-test
          RE_USE_OSS_CLUSTER: false
          RE_DB_PORT: 6379
        run: ./build.sh

      - name: Test
        env:
          RE_CLUSTER: true
          REDIS_VERSION: "7.4"
        run: |
          go test \
          -skip="^TestTLS" \
          --ginkgo.skip-file="ring_test.go" \
          --ginkgo.skip-file="sentinel_test.go" \
          --ginkgo.skip-file="osscluster_test.go" \
          --ginkgo.skip-file="pubsub_test.go" \
          --ginkgo.skip-file="tls_test.go" \
          --ginkgo.skip-file="tls_cluster_test.go" \
          --ginkgo.label-filter='!NonRedisEnterprise'


================================================
FILE: .gitignore
================================================
*.rdb
testdata/*
.idea/
.DS_Store
*.tar.gz
*.dic
redis8tests.sh
coverage.txt
**/coverage.txt
.vscode
tmp/*
*.test
extra/redisotel-native/metrics-collector-app/
# maintenanceNotifications upgrade documentation (temporary)
maintenanceNotifications/docs/

# Docker-generated files (TLS certificates, cluster data, etc.)
dockers/*/tls/
dockers/osscluster-tls/


================================================
FILE: .golangci.yml
================================================
version: "2"
run:
  timeout: 5m
  tests: false
linters:
  settings:
    staticcheck:
      checks:
        - all
        # Incorrect or missing package comment.
        # https://staticcheck.dev/docs/checks/#ST1000
        - -ST1000
        # Omit embedded fields from selector expression.
        # https://staticcheck.dev/docs/checks/#QF1008
        - -QF1008
        - -ST1003
  exclusions:
    generated: lax
    presets:
      - comments
      - common-false-positives
      - legacy
      - std-error-handling
    paths:
      - third_party$
      - builtin$
      - examples$
formatters:
  enable:
    - gofmt
  exclusions:
    generated: lax
    paths:
      - third_party$
      - builtin$
      - examples$


================================================
FILE: .prettierrc.yml
================================================
semi: false
singleQuote: true
proseWrap: always
printWidth: 100


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing

## Introduction

We appreciate your interest in considering contributing to go-redis.
Community contributions mean a lot to us.

## Contributions we need

You may already know how you'd like to contribute, whether it's a fix for a bug you
encountered, or a new feature your team wants to use.

If you don't know where to start, consider improving
documentation, bug triaging, and writing tutorials are all examples of
helpful contributions that mean less work for you.

## Your First Contribution

Unsure where to begin contributing? You can start by looking through
[help-wanted
issues](https://github.com/redis/go-redis/issues?q=is%3Aopen+is%3Aissue+label%3ahelp-wanted).

Never contributed to open source before? Here are a couple of friendly
tutorials:

-   <http://makeapullrequest.com/>
-   <http://www.firsttimersonly.com/>

## Getting Started

Here's how to get started with your code contribution:

1.  Create your own fork of go-redis
2.  Do the changes in your fork
3.  If you need a development environment, run `make docker.start`.
 
> Note: this clones and builds the docker containers specified in `docker-compose.yml`, to understand more about
> the infrastructure that will be started you can check the `docker-compose.yml`. You also have the possiblity
> to specify the redis image that will be pulled with the env variable `CLIENT_LIBS_TEST_IMAGE`.
> By default the docker image that will be pulled and started is `redislabs/client-libs-test:8.2.1-pre`.
> If you want to test with newer Redis version, using a newer version of `redislabs/client-libs-test` should work out of the box.

4.  While developing, make sure the tests pass by running `make test` (if you have the docker containers running, `make test.ci` may be sufficient).
> Note: `make test` will try to start all containers, run the tests with `make test.ci` and then stop all containers.
5.  If you like the change and think the project could use it, send a
    pull request

To see what else is part of the automation, run `invoke -l`


## Testing

### Setting up Docker
To run the tests, you need to have Docker installed and running. If you are using a host OS that does not support
docker host networks out of the box (e.g. Windows, OSX), you need to set up a docker desktop and enable docker host networks.

### Running tests
Call `make test` to run all tests.

Continuous Integration uses these same wrappers to run all of these
tests against multiple versions of redis. Feel free to test your
changes against all the go versions supported, as declared by the
[build.yml](./.github/workflows/build.yml) file.

### Troubleshooting

If you get any errors when running `make test`, make sure
that you are using supported versions of Docker and go.

## How to Report a Bug

### Security Vulnerabilities

**NOTE**: If you find a security vulnerability, do NOT open an issue.
Email [Redis Open Source (<oss@redis.com>)](mailto:oss@redis.com) instead.

In order to determine whether you are dealing with a security issue, ask
yourself these two questions:

-   Can I access something that's not mine, or something I shouldn't
    have access to?
-   Can I disable something for other people?

If the answer to either of those two questions are *yes*, then you're
probably dealing with a security issue. Note that even if you answer
*no*  to both questions, you may still be dealing with a security
issue, so if you're unsure, just email [us](mailto:oss@redis.com).

### Everything Else

When filing an issue, make sure to answer these five questions:

1.  What version of go-redis are you using?
2.  What version of redis are you using?
3.  What did you do?
4.  What did you expect to see?
5.  What did you see instead?

## Suggest a feature or enhancement

If you'd like to contribute a new feature, make sure you check our
issue list to see if someone has already proposed it. Work may already
be underway on the feature you want or we may have rejected a
feature like it already.

If you don't see anything, open a new issue that describes the feature
you would like and how it should work.

## Code review process

The core team regularly looks at pull requests. We will provide
feedback as soon as possible. After receiving our feedback, please respond
within two weeks. After that time, we may close your PR if it isn't
showing any activity.

## Support

Maintainers can provide limited support to contributors on discord: https://discord.gg/W4txy5AeKM


================================================
FILE: LICENSE
================================================
Copyright (c) 2013 The github.com/redis/go-redis Authors.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

   * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: Makefile
================================================
GO_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \; | sort)
REDIS_VERSION ?= 8.6
RE_CLUSTER ?= false
RCE_DOCKER ?= true
CLIENT_LIBS_TEST_IMAGE ?= redislabs/client-libs-test:custom-21860421418-debian-amd64

docker.start:
	export RE_CLUSTER=$(RE_CLUSTER) && \
	export RCE_DOCKER=$(RCE_DOCKER) && \
	export REDIS_VERSION=$(REDIS_VERSION) && \
	export CLIENT_LIBS_TEST_IMAGE=$(CLIENT_LIBS_TEST_IMAGE) && \
	docker compose --profile all up -d --quiet-pull

docker.stop:
	docker compose --profile all down

docker.e2e.start:
	@echo "Starting Redis and cae-resp-proxy for E2E tests..."
	docker compose --profile e2e up -d --quiet-pull
	@echo "Waiting for services to be ready..."
	@sleep 3
	@echo "Services ready!"

docker.e2e.stop:
	@echo "Stopping E2E services..."
	docker compose --profile e2e down

test:
	$(MAKE) docker.start
	@if [ -z "$(REDIS_VERSION)" ]; then \
		echo "REDIS_VERSION not set, running all tests"; \
		$(MAKE) test.ci; \
	else \
		MAJOR_VERSION=$$(echo "$(REDIS_VERSION)" | cut -d. -f1); \
		if [ "$$MAJOR_VERSION" -ge 8 ]; then \
			echo "REDIS_VERSION $(REDIS_VERSION) >= 8, running all tests"; \
			$(MAKE) test.ci; \
		else \
			echo "REDIS_VERSION $(REDIS_VERSION) < 8, skipping vector_sets tests"; \
			$(MAKE) test.ci.skip-vectorsets; \
		fi; \
	fi
	$(MAKE) docker.stop

test.ci:
	set -e; for dir in $(GO_MOD_DIRS); do \
	  echo "go test in $${dir}"; \
	  (cd "$${dir}" && \
	    export RE_CLUSTER=$(RE_CLUSTER) && \
	    export RCE_DOCKER=$(RCE_DOCKER) && \
	    export REDIS_VERSION=$(REDIS_VERSION) && \
	    go mod tidy && \
	    go vet && \
	    go test -v -coverprofile=coverage.txt -covermode=atomic ./... -race -skip Example); \
	done
	cd internal/customvet && go build .
	go vet -vettool ./internal/customvet/customvet

test.ci.skip-vectorsets:
	set -e; for dir in $(GO_MOD_DIRS); do \
	  echo "go test in $${dir} (skipping vector sets)"; \
	  (cd "$${dir}" && \
	    export RE_CLUSTER=$(RE_CLUSTER) && \
	    export RCE_DOCKER=$(RCE_DOCKER) && \
	    export REDIS_VERSION=$(REDIS_VERSION) && \
	    go mod tidy && \
	    go vet && \
	    go test -v -coverprofile=coverage.txt -covermode=atomic ./... -race \
	      -run '^(?!.*(?:VectorSet|vectorset|ExampleClient_vectorset)).*$$' -skip Example); \
	done
	cd internal/customvet && go build .
	go vet -vettool ./internal/customvet/customvet

bench:
	export RE_CLUSTER=$(RE_CLUSTER) && \
	export RCE_DOCKER=$(RCE_DOCKER) && \
	export REDIS_VERSION=$(REDIS_VERSION) && \
	go test ./... -test.run=NONE -test.bench=. -test.benchmem -skip Example

test.e2e:
	@echo "Running E2E tests with auto-start proxy..."
	$(MAKE) docker.e2e.start
	@echo "Running tests..."
	@E2E_SCENARIO_TESTS=true go test -v ./maintnotifications/e2e/ -timeout 30m || ($(MAKE) docker.e2e.stop && exit 1)
	$(MAKE) docker.e2e.stop
	@echo "E2E tests completed!"

test.e2e.docker:
	@echo "Running Docker-compatible E2E tests..."
	$(MAKE) docker.e2e.start
	@echo "Running unified injector tests..."
	@E2E_SCENARIO_TESTS=true go test -v -run "TestUnifiedInjector|TestCreateTestFaultInjectorLogic|TestFaultInjectorClientCreation" ./maintnotifications/e2e/ -timeout 10m || ($(MAKE) docker.e2e.stop && exit 1)
	$(MAKE) docker.e2e.stop
	@echo "Docker E2E tests completed!"

test.e2e.logic:
	@echo "Running E2E logic tests (no proxy required)..."
	@E2E_SCENARIO_TESTS=true \
		REDIS_ENDPOINTS_CONFIG_PATH=/tmp/test_endpoints_verify.json \
		FAULT_INJECTION_API_URL=http://localhost:8080 \
		go test -v -run "TestCreateTestFaultInjectorLogic|TestFaultInjectorClientCreation" ./maintnotifications/e2e/
	@echo "Logic tests completed!"

.PHONY: all test test.ci test.ci.skip-vectorsets bench fmt test.e2e test.e2e.logic docker.e2e.start docker.e2e.stop

build:
	export RE_CLUSTER=$(RE_CLUSTER) && \
	export RCE_DOCKER=$(RCE_DOCKER) && \
	export REDIS_VERSION=$(REDIS_VERSION) && \
	go build .

fmt:
	gofumpt -w ./
	goimports -w  -local github.com/redis/go-redis ./

go_mod_tidy:
	set -e; for dir in $(GO_MOD_DIRS); do \
	  echo "go mod tidy in $${dir}"; \
	  (cd "$${dir}" && \
	    go get -u ./... && \
	    go mod tidy); \
	done


================================================
FILE: README.md
================================================
# Redis client for Go

[![build workflow](https://github.com/redis/go-redis/actions/workflows/build.yml/badge.svg)](https://github.com/redis/go-redis/actions)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/redis/go-redis/v9)](https://pkg.go.dev/github.com/redis/go-redis/v9?tab=doc)
[![Documentation](https://img.shields.io/badge/redis-documentation-informational)](https://redis.io/docs/latest/develop/clients/go/)
[![Go Report Card](https://goreportcard.com/badge/github.com/redis/go-redis/v9)](https://goreportcard.com/report/github.com/redis/go-redis/v9)
[![codecov](https://codecov.io/github/redis/go-redis/graph/badge.svg?token=tsrCZKuSSw)](https://codecov.io/github/redis/go-redis)

[![Discord](https://img.shields.io/discord/697882427875393627.svg?style=social&logo=discord)](https://discord.gg/W4txy5AeKM)
[![Twitch](https://img.shields.io/twitch/status/redisinc?style=social)](https://www.twitch.tv/redisinc)
[![YouTube](https://img.shields.io/youtube/channel/views/UCD78lHSwYqMlyetR0_P4Vig?style=social)](https://www.youtube.com/redisinc)
[![Twitter](https://img.shields.io/twitter/follow/redisinc?style=social)](https://twitter.com/redisinc)
[![Stack Exchange questions](https://img.shields.io/stackexchange/stackoverflow/t/go-redis?style=social&logo=stackoverflow&label=Stackoverflow)](https://stackoverflow.com/questions/tagged/go-redis)

> go-redis is the official Redis client library for the Go programming language. It offers a straightforward interface for interacting with Redis servers. 

## Supported versions

In `go-redis` we are aiming to support the last three releases of Redis. Currently, this means we do support:
- [Redis 8.0](https://raw.githubusercontent.com/redis/redis/8.0/00-RELEASENOTES) - using Redis CE 8.0
- [Redis 8.2](https://raw.githubusercontent.com/redis/redis/8.2/00-RELEASENOTES) - using Redis CE 8.2 
- [Redis 8.4](https://raw.githubusercontent.com/redis/redis/8.4/00-RELEASENOTES) - using Redis CE 8.4

Although the `go.mod` states it requires at minimum `go 1.24`, our CI is configured to run the tests against all three
versions of Redis and multiple versions of Go ([1.24](https://go.dev/doc/devel/release#go1.24.0), oldstable, and stable). We observe that some modules related test may not pass with
Redis Stack 7.2 and some commands are changed with Redis CE 8.0.
Although it is not officially supported, `go-redis/v9`  should be able to work with any Redis 7.0+.
Please do refer to the documentation and the tests if you experience any issues.

## How do I Redis?

[Learn for free at Redis University](https://university.redis.com/)

[Build faster with the Redis Launchpad](https://launchpad.redis.com/)

[Try the Redis Cloud](https://redis.com/try-free/)

[Dive in developer tutorials](https://developer.redis.com/)

[Join the Redis community](https://redis.com/community/)

[Work at Redis](https://redis.com/company/careers/jobs/)


## Resources

- [Discussions](https://github.com/redis/go-redis/discussions)
- [Chat](https://discord.gg/W4txy5AeKM)
- [Reference](https://pkg.go.dev/github.com/redis/go-redis/v9)
- [Examples](https://pkg.go.dev/github.com/redis/go-redis/v9#pkg-examples)

## old documentation

- [English](https://redis.uptrace.dev)
- [简体中文](https://redis.uptrace.dev/zh/)

## Ecosystem

- [Entra ID (Azure AD)](https://github.com/redis/go-redis-entraid)
- [Distributed Locks](https://github.com/bsm/redislock)
- [Redis Cache](https://github.com/go-redis/cache)
- [Rate limiting](https://github.com/go-redis/redis_rate)

## Features

- Redis commands except QUIT and SYNC.
- Automatic connection pooling.
- [StreamingCredentialsProvider (e.g. entra id, oauth)](#1-streaming-credentials-provider-highest-priority) (experimental)
- [Pub/Sub](https://redis.uptrace.dev/guide/go-redis-pubsub.html).
- [Pipelines and transactions](https://redis.uptrace.dev/guide/go-redis-pipelines.html).
- [Scripting](https://redis.uptrace.dev/guide/lua-scripting.html).
- [Redis Sentinel](https://redis.uptrace.dev/guide/go-redis-sentinel.html).
- [Redis Cluster](https://redis.uptrace.dev/guide/go-redis-cluster.html).
- [Redis Performance Monitoring](https://redis.uptrace.dev/guide/redis-performance-monitoring.html).
- [Redis Probabilistic [RedisStack]](https://redis.io/docs/data-types/probabilistic/)
- [Customizable read and write buffers size.](#custom-buffer-sizes)

## Installation

go-redis supports 2 last Go versions and requires a Go version with
[modules](https://github.com/golang/go/wiki/Modules) support. So make sure to initialize a Go
module:

```shell
go mod init github.com/my/repo
```

Then install go-redis/**v9**:

```shell
go get github.com/redis/go-redis/v9
```

## Quickstart

```go
import (
    "context"
    "fmt"

    "github.com/redis/go-redis/v9"
)

var ctx = context.Background()

func ExampleClient() {
    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })
    defer rdb.Close()

    err := rdb.Set(ctx, "key", "value", 0).Err()
    if err != nil {
        panic(err)
    }

    val, err := rdb.Get(ctx, "key").Result()
    if err != nil {
        panic(err)
    }
    fmt.Println("key", val)

    val2, err := rdb.Get(ctx, "key2").Result()
    if err == redis.Nil {
        fmt.Println("key2 does not exist")
    } else if err != nil {
        panic(err)
    } else {
        fmt.Println("key2", val2)
    }
    // Output: key value
    // key2 does not exist
}
```

### Dial retries and backoff

Connection establishment can be retried by the connection pool when dialing fails.

- **`DialerRetries`**: maximum number of dial attempts (default: 5).
- **`DialerRetryTimeout`**: default delay between attempts when no custom backoff is provided (default: 100ms).
- **`DialerRetryBackoff`**: optional function hook to control the delay between attempts.

Example:

```go
rdb := redis.NewClient(&redis.Options{
	Addr: "localhost:6379",

	DialerRetries:      5,
	DialerRetryTimeout: 100 * time.Millisecond, // used when DialerRetryBackoff is nil

	// Optional: exponential backoff with jitter and a cap.
	DialerRetryBackoff: redis.DialRetryBackoffExponential(100*time.Millisecond, 2*time.Second),
})
defer rdb.Close()
```

### Authentication

The Redis client supports multiple ways to provide authentication credentials, with a clear priority order. Here are the available options:

#### 1. Streaming Credentials Provider (Highest Priority) - Experimental feature

The streaming credentials provider allows for dynamic credential updates during the connection lifetime. This is particularly useful for managed identity services and token-based authentication.

```go
type StreamingCredentialsProvider interface {
    Subscribe(listener CredentialsListener) (Credentials, UnsubscribeFunc, error)
}

type CredentialsListener interface {
    OnNext(credentials Credentials)  // Called when credentials are updated
    OnError(err error)              // Called when an error occurs
}

type Credentials interface {
    BasicAuth() (username string, password string)
    RawCredentials() string
}
```

Example usage:
```go
rdb := redis.NewClient(&redis.Options{
    Addr: "localhost:6379",
    StreamingCredentialsProvider: &MyCredentialsProvider{},
})
```

**Note:** The streaming credentials provider can be used with [go-redis-entraid](https://github.com/redis/go-redis-entraid) to enable Entra ID (formerly Azure AD) authentication. This allows for seamless integration with Azure's managed identity services and token-based authentication.

Example with Entra ID:
```go
import (
    "github.com/redis/go-redis/v9"
    "github.com/redis/go-redis-entraid"
)

// Create an Entra ID credentials provider
provider := entraid.NewDefaultAzureIdentityProvider()

// Configure Redis client with Entra ID authentication
rdb := redis.NewClient(&redis.Options{
    Addr: "your-redis-server.redis.cache.windows.net:6380",
    StreamingCredentialsProvider: provider,
    TLSConfig: &tls.Config{
        MinVersion: tls.VersionTLS12,
    },
})
```

#### 2. Context-based Credentials Provider

The context-based provider allows credentials to be determined at the time of each operation, using the context.

```go
rdb := redis.NewClient(&redis.Options{
    Addr: "localhost:6379",
    CredentialsProviderContext: func(ctx context.Context) (string, string, error) {
        // Return username, password, and any error
        return "user", "pass", nil
    },
})
```

#### 3. Regular Credentials Provider

A simple function-based provider that returns static credentials.

```go
rdb := redis.NewClient(&redis.Options{
    Addr: "localhost:6379",
    CredentialsProvider: func() (string, string) {
        // Return username and password
        return "user", "pass"
    },
})
```

#### 4. Username/Password Fields (Lowest Priority)

The most basic way to provide credentials is through the `Username` and `Password` fields in the options.

```go
rdb := redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Username: "user",
    Password: "pass",
})
```

#### Priority Order

The client will use credentials in the following priority order:
1. Streaming Credentials Provider (if set)
2. Context-based Credentials Provider (if set)
3. Regular Credentials Provider (if set)
4. Username/Password fields (if set)

If none of these are set, the client will attempt to connect without authentication.

### Protocol Version

The client supports both RESP2 and RESP3 protocols. You can specify the protocol version in the options:

```go
rdb := redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "", // no password set
    DB:       0,  // use default DB
    Protocol: 3,  // specify 2 for RESP 2 or 3 for RESP 3
})
```

### Connecting via a redis url

go-redis also supports connecting via the
[redis uri specification](https://github.com/redis/redis-specifications/tree/master/uri/redis.txt).
The example below demonstrates how the connection can easily be configured using a string, adhering
to this specification.

```go
import (
    "github.com/redis/go-redis/v9"
)

func ExampleClient() *redis.Client {
    url := "redis://user:password@localhost:6379/0?protocol=3"
    opts, err := redis.ParseURL(url)
    if err != nil {
        panic(err)
    }

    return redis.NewClient(opts)
}

```

### Instrument with OpenTelemetry

```go
import (
    "github.com/redis/go-redis/v9"
    "github.com/redis/go-redis/extra/redisotel/v9"
    "errors"
)

func main() {
    ...
    rdb := redis.NewClient(&redis.Options{...})

    if err := errors.Join(redisotel.InstrumentTracing(rdb), redisotel.InstrumentMetrics(rdb)); err != nil {
        log.Fatal(err)
    }
```


### Buffer Size Configuration

go-redis uses 32KiB read and write buffers by default for optimal performance. For high-throughput applications or large pipelines, you can customize buffer sizes:

```go
rdb := redis.NewClient(&redis.Options{
    Addr:            "localhost:6379",
    ReadBufferSize:  1024 * 1024, // 1MiB read buffer
    WriteBufferSize: 1024 * 1024, // 1MiB write buffer
})
```

### Advanced Configuration

go-redis supports extending the client identification phase to allow projects to send their own custom client identification.

#### Default Client Identification

By default, go-redis automatically sends the client library name and version during the connection process. This feature is available in redis-server as of version 7.2. As a result, the command is "fire and forget", meaning it should fail silently, in the case that the redis server does not support this feature.

#### Disabling Identity Verification

When connection identity verification is not required or needs to be explicitly disabled, a `DisableIdentity` configuration option exists.
Initially there was a typo and the option was named `DisableIndentity` instead of `DisableIdentity`. The misspelled option is marked as Deprecated and will be removed in V10 of this library.
Although both options will work at the moment, the correct option is `DisableIdentity`. The deprecated option will be removed in V10 of this library, so please use the correct option name to avoid any issues.

To disable verification, set the `DisableIdentity` option to `true` in the Redis client options:

```go
rdb := redis.NewClient(&redis.Options{
    Addr:            "localhost:6379",
    Password:        "",
    DB:              0,
    DisableIdentity: true, // Disable set-info on connect
})
```

#### Unstable RESP3 Structures for RediSearch Commands
When integrating Redis with application functionalities using RESP3, it's important to note that some response structures aren't final yet. This is especially true for more complex structures like search and query results. We recommend using RESP2 when using the search and query capabilities, but we plan to stabilize the RESP3-based API-s in the coming versions. You can find more guidance in the upcoming release notes.

To enable unstable RESP3, set the option in your client configuration:

```go
redis.NewClient(&redis.Options{
			UnstableResp3: true,
		})
```
**Note:** When UnstableResp3 mode is enabled, it's necessary to use RawResult() and RawVal() to retrieve a raw data.
          Since, raw response is the only option for unstable search commands Val() and Result() calls wouldn't have any affect on them:

```go
res1, err := client.FTSearchWithArgs(ctx, "txt", "foo bar", &redis.FTSearchOptions{}).RawResult()
val1 := client.FTSearchWithArgs(ctx, "txt", "foo bar", &redis.FTSearchOptions{}).RawVal()
```

#### Redis-Search Default Dialect

In the Redis-Search module, **the default dialect is 2**. If needed, you can explicitly specify a different dialect using the appropriate configuration in your queries.

**Important**: Be aware that the query dialect may impact the results returned. If needed, you can revert to a different dialect version by passing the desired dialect in the arguments of the command you want to execute.
For example:
```
	res2, err := rdb.FTSearchWithArgs(ctx,
		"idx:bicycle",
		"@pickup_zone:[CONTAINS $bike]",
		&redis.FTSearchOptions{
			Params: map[string]interface{}{
				"bike": "POINT(-0.1278 51.5074)",
			},
			DialectVersion: 3,
		},
	).Result()
```
You can find further details in the [query dialect documentation](https://redis.io/docs/latest/develop/interact/search-and-query/advanced-concepts/dialects/).

#### Custom buffer sizes
Prior to v9.12, the buffer size was the default go value of 4096 bytes. Starting from v9.12, 
go-redis uses 32KiB read and write buffers by default for optimal performance.
For high-throughput applications or large pipelines, you can customize buffer sizes:

```go
rdb := redis.NewClient(&redis.Options{
    Addr:            "localhost:6379",
    ReadBufferSize:  1024 * 1024, // 1MiB read buffer
    WriteBufferSize: 1024 * 1024, // 1MiB write buffer
})
```

**Important**: If you experience any issues with the default buffer sizes, please try setting them to the go default of 4096 bytes.

## Contributing
We welcome contributions to the go-redis library! If you have a bug fix, feature request, or improvement, please open an issue or pull request on GitHub.
We appreciate your help in making go-redis better for everyone.
If you are interested in contributing to the go-redis library, please check out our [contributing guidelines](CONTRIBUTING.md) for more information on how to get started.

## Look and feel

Some corner cases:

```go
// SET key value EX 10 NX
set, err := rdb.SetNX(ctx, "key", "value", 10*time.Second).Result()

// SET key value keepttl NX
set, err := rdb.SetNX(ctx, "key", "value", redis.KeepTTL).Result()

// SORT list LIMIT 0 2 ASC
vals, err := rdb.Sort(ctx, "list", &redis.Sort{Offset: 0, Count: 2, Order: "ASC"}).Result()

// ZRANGEBYSCORE zset -inf +inf WITHSCORES LIMIT 0 2
vals, err := rdb.ZRangeByScoreWithScores(ctx, "zset", &redis.ZRangeBy{
    Min: "-inf",
    Max: "+inf",
    Offset: 0,
    Count: 2,
}).Result()

// ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3 AGGREGATE SUM
vals, err := rdb.ZInterStore(ctx, "out", &redis.ZStore{
    Keys: []string{"zset1", "zset2"},
    Weights: []int64{2, 3}
}).Result()

// EVAL "return {KEYS[1],ARGV[1]}" 1 "key" "hello"
vals, err := rdb.Eval(ctx, "return {KEYS[1],ARGV[1]}", []string{"key"}, "hello").Result()

// custom command
res, err := rdb.Do(ctx, "set", "key", "value").Result()
```

## Typed Errors

go-redis provides typed error checking functions for common Redis errors:

```go
// Cluster and replication errors
redis.IsLoadingError(err)        // Redis is loading the dataset
redis.IsReadOnlyError(err)       // Write to read-only replica
redis.IsClusterDownError(err)    // Cluster is down
redis.IsTryAgainError(err)       // Command should be retried
redis.IsMasterDownError(err)     // Master is down
redis.IsMovedError(err)          // Returns (address, true) if key moved
redis.IsAskError(err)            // Returns (address, true) if key being migrated

// Connection and resource errors
redis.IsMaxClientsError(err)     // Maximum clients reached
redis.IsAuthError(err)           // Authentication failed (NOAUTH, WRONGPASS, unauthenticated)
redis.IsPermissionError(err)     // Permission denied (NOPERM)
redis.IsOOMError(err)            // Out of memory (OOM)

// Transaction errors
redis.IsExecAbortError(err)      // Transaction aborted (EXECABORT)
```

### Error Wrapping in Hooks

When wrapping errors in hooks, use custom error types with `Unwrap()` method (preferred) or `fmt.Errorf` with `%w`. Always call `cmd.SetErr()` to preserve error type information:

```go
// Custom error type (preferred)
type AppError struct {
    Code      string
    RequestID string
    Err       error
}

func (e *AppError) Error() string {
    return fmt.Sprintf("[%s] request_id=%s: %v", e.Code, e.RequestID, e.Err)
}

func (e *AppError) Unwrap() error {
    return e.Err
}

// Hook implementation
func (h MyHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
    return func(ctx context.Context, cmd redis.Cmder) error {
        err := next(ctx, cmd)
        if err != nil {
            // Wrap with custom error type
            wrappedErr := &AppError{
                Code:      "REDIS_ERROR",
                RequestID: getRequestID(ctx),
                Err:       err,
            }
            cmd.SetErr(wrappedErr)
            return wrappedErr  // Return wrapped error to preserve it
        }
        return nil
    }
}

// Typed error detection works through wrappers
if redis.IsLoadingError(err) {
    // Retry logic
}

// Extract custom error if needed
var appErr *AppError
if errors.As(err, &appErr) {
    log.Printf("Request: %s", appErr.RequestID)
}
```

Alternatively, use `fmt.Errorf` with `%w`:
```go
wrappedErr := fmt.Errorf("context: %w", err)
cmd.SetErr(wrappedErr)
```

### Pipeline Hook Example

For pipeline operations, use `ProcessPipelineHook`:

```go
type PipelineLoggingHook struct{}

func (h PipelineLoggingHook) DialHook(next redis.DialHook) redis.DialHook {
    return next
}

func (h PipelineLoggingHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
    return next
}

func (h PipelineLoggingHook) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook {
    return func(ctx context.Context, cmds []redis.Cmder) error {
        start := time.Now()

        // Execute the pipeline
        err := next(ctx, cmds)

        duration := time.Since(start)
        log.Printf("Pipeline executed %d commands in %v", len(cmds), duration)

        // Process individual command errors
        // Note: Individual command errors are already set on each cmd by the pipeline execution
        for _, cmd := range cmds {
            if cmdErr := cmd.Err(); cmdErr != nil {
                // Check for specific error types using typed error functions
                if redis.IsAuthError(cmdErr) {
                    log.Printf("Auth error in pipeline command %s: %v", cmd.Name(), cmdErr)
                } else if redis.IsPermissionError(cmdErr) {
                    log.Printf("Permission error in pipeline command %s: %v", cmd.Name(), cmdErr)
                }

                // Optionally wrap individual command errors to add context
                // The wrapped error preserves type information through errors.As()
                wrappedErr := fmt.Errorf("pipeline cmd %s failed: %w", cmd.Name(), cmdErr)
                cmd.SetErr(wrappedErr)
            }
        }

        // Return the pipeline-level error (connection errors, etc.)
        // You can wrap it if needed, or return it as-is
        return err
    }
}

// Register the hook
rdb.AddHook(PipelineLoggingHook{})

// Use pipeline - errors are still properly typed
pipe := rdb.Pipeline()
pipe.Set(ctx, "key1", "value1", 0)
pipe.Get(ctx, "key2")
_, err := pipe.Exec(ctx)
```

## Run the test

Recommended to use Docker, just need to run:
```shell
make test
```

## See also

- [Golang ORM](https://bun.uptrace.dev) for PostgreSQL, MySQL, MSSQL, and SQLite
- [Golang PostgreSQL](https://bun.uptrace.dev/postgres/)
- [Golang HTTP router](https://bunrouter.uptrace.dev/)
- [Golang ClickHouse ORM](https://github.com/uptrace/go-clickhouse)

## Contributors

> The go-redis project was originally initiated by :star: [**uptrace/uptrace**](https://github.com/uptrace/uptrace).
> Uptrace is an open-source APM tool that supports distributed tracing, metrics, and logs. You can
> use it to monitor applications and set up automatic alerts to receive notifications via email,
> Slack, Telegram, and others.
>
> See [OpenTelemetry](https://github.com/redis/go-redis/tree/master/example/otel) example which
> demonstrates how you can use Uptrace to monitor go-redis.

Thanks to all the people who already contributed!

<a href="https://github.com/redis/go-redis/graphs/contributors">
  <img src="https://contributors-img.web.app/image?repo=redis/go-redis" />
</a>


================================================
FILE: RELEASE-NOTES.md
================================================
# Release Notes

# 9.18.0 (2026-02-16)

## 🚀 Highlights

### Redis 8.6 Support

Added support for Redis 8.6, including new commands and features for streams idempotent production and HOTKEYS.

### Smart Client Handoff (Maintenance Notifications) for Cluster

This release introduces comprehensive support for Redis Cluster maintenance notifications via SMIGRATING/SMIGRATED push notifications. The client now automatically handles slot migrations by:
- **Relaxing timeouts during migration** (SMIGRATING) to prevent false failures
- **Triggering lazy cluster state reloads** upon completion (SMIGRATED)
- Enabling seamless operations during Redis Enterprise maintenance windows

([#3643](https://github.com/redis/go-redis/pull/3643)) by [@ndyakov](https://github.com/ndyakov)

### OpenTelemetry Native Metrics Support

Added comprehensive OpenTelemetry metrics support following the [OpenTelemetry Database Client Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/database/database-metrics/). The implementation uses a Bridge Pattern to keep the core library dependency-free while providing optional metrics instrumentation through the new `extra/redisotel-native` package.

**Metric groups include:**
- Command metrics: Operation duration with retry tracking
- Connection basic: Connection count and creation time
- Resiliency: Errors, handoffs, timeout relaxation
- Connection advanced: Wait time and use time
- Pubsub metrics: Published and received messages
- Stream metrics: Processing duration and maintenance notifications

([#3637](https://github.com/redis/go-redis/pull/3637)) by [@ofekshenawa](https://github.com/ofekshenawa)

## ✨ New Features

- **HOTKEYS Commands**: Added support for Redis HOTKEYS feature for identifying hot keys based on CPU consumption and network utilization ([#3695](https://github.com/redis/go-redis/pull/3695)) by [@ofekshenawa](https://github.com/ofekshenawa)
- **Streams Idempotent Production**: Added support for Redis 8.6+ Streams Idempotent Production with `ProducerID`, `IdempotentID`, `IdempotentAuto` in `XAddArgs` and new `XCFGSET` command ([#3693](https://github.com/redis/go-redis/pull/3693)) by [@ofekshenawa](https://github.com/ofekshenawa)
- **NaN Values for TimeSeries**: Added support for NaN (Not a Number) values in Redis time series commands ([#3687](https://github.com/redis/go-redis/pull/3687)) by [@ofekshenawa](https://github.com/ofekshenawa)
- **DialerRetries Options**: Added `DialerRetries` and `DialerRetryTimeout` to `ClusterOptions`, `RingOptions`, and `FailoverOptions` ([#3686](https://github.com/redis/go-redis/pull/3686)) by [@naveenchander30](https://github.com/naveenchander30)
- **ConnMaxLifetimeJitter**: Added jitter configuration to distribute connection expiration times and prevent thundering herd ([#3666](https://github.com/redis/go-redis/pull/3666)) by [@cyningsun](https://github.com/cyningsun)
- **Digest Helper Functions**: Added `DigestString` and `DigestBytes` helper functions for client-side xxh3 hashing compatible with Redis DIGEST command ([#3679](https://github.com/redis/go-redis/pull/3679)) by [@ofekshenawa](https://github.com/ofekshenawa)
- **SMIGRATED New Format**: Updated SMIGRATED parser to support new format and remember original host:port ([#3697](https://github.com/redis/go-redis/pull/3697)) by [@ndyakov](https://github.com/ndyakov)
- **Cluster State Reload Interval**: Added cluster state reload interval option for maintenance notifications ([#3663](https://github.com/redis/go-redis/pull/3663)) by [@ndyakov](https://github.com/ndyakov)

## 🐛 Bug Fixes

- **PubSub nil pointer dereference**: Fixed nil pointer dereference in PubSub after `WithTimeout()` - `pubSubPool` is now properly cloned ([#3710](https://github.com/redis/go-redis/pull/3710)) by [@Copilot](https://github.com/apps/copilot-swe-agent)
- **MaintNotificationsConfig nil check**: Guard against nil `MaintNotificationsConfig` in `initConn` ([#3707](https://github.com/redis/go-redis/pull/3707)) by [@veeceey](https://github.com/veeceey)
- **wantConnQueue zombie elements**: Fixed zombie `wantConn` elements accumulation in `wantConnQueue` ([#3680](https://github.com/redis/go-redis/pull/3680)) by [@cyningsun](https://github.com/cyningsun)
- **XADD/XTRIM approx flag**: Fixed XADD and XTRIM to use `=` when approx is false ([#3684](https://github.com/redis/go-redis/pull/3684)) by [@ndyakov](https://github.com/ndyakov)
- **Sentinel timeout retry**: When connection to a sentinel times out, attempt to connect to other sentinels ([#3654](https://github.com/redis/go-redis/pull/3654)) by [@cxljs](https://github.com/cxljs)

## ⚡ Performance

- **Fuzz test optimization**: Eliminated repeated string conversions, used functional approach for cleaner operation selection ([#3692](https://github.com/redis/go-redis/pull/3692)) by [@feiguoL](https://github.com/feiguoL)
- **Pre-allocate capacity**: Pre-allocate slice capacity to prevent multiple capacity expansions ([#3689](https://github.com/redis/go-redis/pull/3689)) by [@feelshu](https://github.com/feelshu)

## 🧪 Testing

- **Comprehensive TLS tests**: Added comprehensive TLS tests and example for standalone, cluster, and certificate authentication ([#3681](https://github.com/redis/go-redis/pull/3681)) by [@ndyakov](https://github.com/ndyakov)
- **Redis 8.6**: Updated CI to use Redis 8.6-pre ([#3685](https://github.com/redis/go-redis/pull/3685)) by [@ndyakov](https://github.com/ndyakov)

## 🧰 Maintenance

- **Deprecation warnings**: Added deprecation warnings for commands based on Redis documentation ([#3673](https://github.com/redis/go-redis/pull/3673)) by [@ndyakov](https://github.com/ndyakov)
- **Use errors.Join()**: Replaced custom error join function with standard library `errors.Join()` ([#3653](https://github.com/redis/go-redis/pull/3653)) by [@cxljs](https://github.com/cxljs)
- **Use Go 1.21 min/max**: Use Go 1.21's built-in min/max functions ([#3656](https://github.com/redis/go-redis/pull/3656)) by [@cxljs](https://github.com/cxljs)
- **Proper formatting**: Code formatting improvements ([#3670](https://github.com/redis/go-redis/pull/3670)) by [@12ya](https://github.com/12ya)
- **Set commands documentation**: Added comprehensive documentation to all set command methods ([#3642](https://github.com/redis/go-redis/pull/3642)) by [@iamamirsalehi](https://github.com/iamamirsalehi)
- **MaxActiveConns docs**: Added default value documentation for `MaxActiveConns` ([#3674](https://github.com/redis/go-redis/pull/3674)) by [@codykaup](https://github.com/codykaup)
- **README example update**: Updated README example ([#3657](https://github.com/redis/go-redis/pull/3657)) by [@cxljs](https://github.com/cxljs)
- **Cluster maintnotif example**: Added example application for cluster maintenance notifications ([#3651](https://github.com/redis/go-redis/pull/3651)) by [@ndyakov](https://github.com/ndyakov)

## 👥 Contributors

We'd like to thank all the contributors who worked on this release!

[@12ya](https://github.com/12ya), [@Copilot](https://github.com/apps/copilot-swe-agent), [@codykaup](https://github.com/codykaup), [@cxljs](https://github.com/cxljs), [@cyningsun](https://github.com/cyningsun), [@feelshu](https://github.com/feelshu), [@feiguoL](https://github.com/feiguoL), [@iamamirsalehi](https://github.com/iamamirsalehi), [@naveenchander30](https://github.com/naveenchander30), [@ndyakov](https://github.com/ndyakov), [@ofekshenawa](https://github.com/ofekshenawa), [@veeceey](https://github.com/veeceey)

---

**Full Changelog**: https://github.com/redis/go-redis/compare/v9.17.0...v9.18.0

# 9.18.0-beta.2 (2025-12-09)

## 🚀 Highlights

### Go Version Update

This release updates the minimum required Go version to 1.21. This is part of a gradual migration strategy where the minimum supported Go version will be three versions behind the latest release. With each new Go version release, we will bump the minimum version by one, ensuring compatibility while staying current with the Go ecosystem.

### Stability Improvements

This release includes several important stability fixes:
- Fixed a critical panic in the handoff worker manager that could occur when handling nil errors
- Improved test reliability for Smart Client Handoff functionality
- Fixed logging format issues that could cause runtime errors

## ✨ New Features

- OpenTelemetry metrics improvements for nil response handling ([#3638](https://github.com/redis/go-redis/pull/3638)) by [@fengve](https://github.com/fengve)

## 🐛 Bug Fixes

- Fixed panic on nil error in handoffWorkerManager closeConnFromRequest ([#3633](https://github.com/redis/go-redis/pull/3633)) by [@ccoVeille](https://github.com/ccoVeille)
- Fixed bad sprintf syntax in logging ([#3632](https://github.com/redis/go-redis/pull/3632)) by [@ccoVeille](https://github.com/ccoVeille)

## 🧰 Maintenance

- Updated minimum Go version to 1.21 ([#3640](https://github.com/redis/go-redis/pull/3640)) by [@ndyakov](https://github.com/ndyakov)
- Use Go 1.20 idiomatic string<->byte conversion ([#3435](https://github.com/redis/go-redis/pull/3435)) by [@justinhwang](https://github.com/justinhwang)
- Reduce flakiness of Smart Client Handoff test ([#3641](https://github.com/redis/go-redis/pull/3641)) by [@kiryazovi-redis](https://github.com/kiryazovi-redis)
- Revert PR #3634 (Observability metrics phase1) ([#3635](https://github.com/redis/go-redis/pull/3635)) by [@ofekshenawa](https://github.com/ofekshenawa)

## 👥 Contributors

We'd like to thank all the contributors who worked on this release!

[@justinhwang](https://github.com/justinhwang), [@ndyakov](https://github.com/ndyakov), [@kiryazovi-redis](https://github.com/kiryazovi-redis), [@fengve](https://github.com/fengve), [@ccoVeille](https://github.com/ccoVeille), [@ofekshenawa](https://github.com/ofekshenawa)

---

**Full Changelog**: https://github.com/redis/go-redis/compare/v9.18.0-beta.1...v9.18.0-beta.2

# 9.18.0-beta.1 (2025-12-01)

## 🚀 Highlights

### Request and Response Policy Based Routing in Cluster Mode

This beta release introduces comprehensive support for Redis COMMAND-based request and response policy routing for cluster clients. This feature enables intelligent command routing and response aggregation based on Redis command metadata.

**Key Features:**
- **Command Policy Loader**: Automatically parses and caches COMMAND metadata with routing/aggregation hints
- **Enhanced Routing Engine**: Supports all request policies including:
  - `default(keyless)` - Commands without keys
  - `default(hashslot)` - Commands with hash slot routing
  - `all_shards` - Commands that need to run on all shards
  - `all_nodes` - Commands that need to run on all nodes
  - `multi_shard` - Commands that span multiple shards
  - `special` - Commands with custom routing logic
- **Response Aggregator**: Intelligently combines multi-shard replies based on response policies:
  - `all_succeeded` - All shards must succeed
  - `one_succeeded` - At least one shard must succeed
  - `agg_sum` - Aggregate numeric responses
  - `special` - Custom aggregation logic (e.g., FT.CURSOR)
- **Raw Command Support**: Policies are enforced on `Client.Do(ctx, args...)`

This feature is particularly useful for Redis Stack commands like RediSearch that need to operate across multiple shards in a cluster.

### Connection Pool Improvements

Fixed a critical defect in the connection pool's turn management mechanism that could lead to connection leaks under certain conditions. The fix ensures proper 1:1 correspondence between turns and connections.

## ✨ New Features

- Request and Response Policy Based Routing in Cluster Mode ([#3422](https://github.com/redis/go-redis/pull/3422)) by [@ofekshenawa](https://github.com/ofekshenawa)

## 🐛 Bug Fixes

- Fixed connection pool turn management to prevent connection leaks ([#3626](https://github.com/redis/go-redis/pull/3626)) by [@cyningsun](https://github.com/cyningsun)

## 🧰 Maintenance

- chore(deps): bump rojopolis/spellcheck-github-actions from 0.54.0 to 0.55.0 ([#3627](https://github.com/redis/go-redis/pull/3627))

## 👥 Contributors

We'd like to thank all the contributors who worked on this release!

[@cyningsun](https://github.com/cyningsun), [@ofekshenawa](https://github.com/ofekshenawa), [@ndyakov](https://github.com/ndyakov)

---

**Full Changelog**: https://github.com/redis/go-redis/compare/v9.17.1...v9.18.0-beta.1

# 9.17.1 (2025-11-25)

## 🐛 Bug Fixes

- add wait to keyless commands list ([#3615](https://github.com/redis/go-redis/pull/3615)) by [@marcoferrer](https://github.com/marcoferrer)
- fix(time): remove cached time optimization ([#3611](https://github.com/redis/go-redis/pull/3611)) by [@ndyakov](https://github.com/ndyakov)

## 🧰 Maintenance

- chore(deps): bump golangci/golangci-lint-action from 9.0.0 to 9.1.0 ([#3609](https://github.com/redis/go-redis/pull/3609))
- chore(deps): bump actions/checkout from 5 to 6 ([#3610](https://github.com/redis/go-redis/pull/3610))
- chore(script): fix help call in tag.sh ([#3606](https://github.com/redis/go-redis/pull/3606)) by [@ndyakov](https://github.com/ndyakov)

## Contributors
We'd like to thank all the contributors who worked on this release!

[@marcoferrer](https://github.com/marcoferrer) and [@ndyakov](https://github.com/ndyakov)

---

**Full Changelog**: https://github.com/redis/go-redis/compare/v9.17.0...v9.17.1

# 9.17.0 (2025-11-19)

## 🚀 Highlights

### Redis 8.4 Support
Added support for Redis 8.4, including new commands and features ([#3572](https://github.com/redis/go-redis/pull/3572))

### Typed Errors
Introduced typed errors for better error handling using `errors.As` instead of string checks. Errors can now be wrapped and set to commands in hooks without breaking library functionality ([#3602](https://github.com/redis/go-redis/pull/3602))

### New Commands
- **CAS/CAD Commands**: Added support for Compare-And-Set/Compare-And-Delete operations with conditional matching (`IFEQ`, `IFNE`, `IFDEQ`, `IFDNE`) ([#3583](https://github.com/redis/go-redis/pull/3583), [#3595](https://github.com/redis/go-redis/pull/3595))
- **MSETEX**: Atomically set multiple key-value pairs with expiration options and conditional modes ([#3580](https://github.com/redis/go-redis/pull/3580))
- **XReadGroup CLAIM**: Consume both incoming and idle pending entries from streams in a single call ([#3578](https://github.com/redis/go-redis/pull/3578))
- **ACL Commands**: Added `ACLGenPass`, `ACLUsers`, and `ACLWhoAmI` ([#3576](https://github.com/redis/go-redis/pull/3576))
- **SLOWLOG Commands**: Added `SLOWLOG LEN` and `SLOWLOG RESET` ([#3585](https://github.com/redis/go-redis/pull/3585))
- **LATENCY Commands**: Added `LATENCY LATEST` and `LATENCY RESET` ([#3584](https://github.com/redis/go-redis/pull/3584))

### Search & Vector Improvements
- **Hybrid Search**: Added  **EXPERIMENTAL** support for the new `FT.HYBRID` command ([#3573](https://github.com/redis/go-redis/pull/3573))
- **Vector Range**: Added `VRANGE` command for vector sets ([#3543](https://github.com/redis/go-redis/pull/3543))
- **FT.INFO Enhancements**: Added vector-specific attributes in FT.INFO response ([#3596](https://github.com/redis/go-redis/pull/3596))

### Connection Pool Improvements
- **Improved Connection Success Rate**: Implemented FIFO queue-based fairness and context pattern for connection creation to prevent premature cancellation under high concurrency ([#3518](https://github.com/redis/go-redis/pull/3518))
- **Connection State Machine**: Resolved race conditions and improved pool performance with proper state tracking ([#3559](https://github.com/redis/go-redis/pull/3559))
- **Pool Performance**: Significant performance improvements with faster semaphores, lockless hook manager, and reduced allocations (47-67% faster Get/Put operations) ([#3565](https://github.com/redis/go-redis/pull/3565))

### Metrics & Observability
- **Canceled Metric Attribute**: Added 'canceled' metrics attribute to distinguish context cancellation errors from other errors ([#3566](https://github.com/redis/go-redis/pull/3566))

## ✨ New Features

- Typed errors with wrapping support ([#3602](https://github.com/redis/go-redis/pull/3602)) by [@ndyakov](https://github.com/ndyakov)
- CAS/CAD commands (marked as experimental) ([#3583](https://github.com/redis/go-redis/pull/3583), [#3595](https://github.com/redis/go-redis/pull/3595)) by [@ndyakov](https://github.com/ndyakov), [@htemelski-redis](https://github.com/htemelski-redis)
- MSETEX command support ([#3580](https://github.com/redis/go-redis/pull/3580)) by [@ofekshenawa](https://github.com/ofekshenawa)
- XReadGroup CLAIM argument ([#3578](https://github.com/redis/go-redis/pull/3578)) by [@ofekshenawa](https://github.com/ofekshenawa)
- ACL commands: GenPass, Users, WhoAmI ([#3576](https://github.com/redis/go-redis/pull/3576)) by [@destinyoooo](https://github.com/destinyoooo)
- SLOWLOG commands: LEN, RESET ([#3585](https://github.com/redis/go-redis/pull/3585)) by [@destinyoooo](https://github.com/destinyoooo)
- LATENCY commands: LATEST, RESET ([#3584](https://github.com/redis/go-redis/pull/3584)) by [@destinyoooo](https://github.com/destinyoooo)
- Hybrid search command (FT.HYBRID) ([#3573](https://github.com/redis/go-redis/pull/3573)) by [@htemelski-redis](https://github.com/htemelski-redis)
- Vector range command (VRANGE) ([#3543](https://github.com/redis/go-redis/pull/3543)) by [@cxljs](https://github.com/cxljs)
- Vector-specific attributes in FT.INFO ([#3596](https://github.com/redis/go-redis/pull/3596)) by [@ndyakov](https://github.com/ndyakov)
- Improved connection pool success rate with FIFO queue ([#3518](https://github.com/redis/go-redis/pull/3518)) by [@cyningsun](https://github.com/cyningsun)
- Canceled metrics attribute for context errors ([#3566](https://github.com/redis/go-redis/pull/3566)) by [@pvragov](https://github.com/pvragov)

## 🐛 Bug Fixes

- Fixed Failover Client MaintNotificationsConfig ([#3600](https://github.com/redis/go-redis/pull/3600)) by [@ajax16384](https://github.com/ajax16384)
- Fixed ACLGenPass function to use the bit parameter ([#3597](https://github.com/redis/go-redis/pull/3597)) by [@destinyoooo](https://github.com/destinyoooo)
- Return error instead of panic from commands ([#3568](https://github.com/redis/go-redis/pull/3568)) by [@dragneelfps](https://github.com/dragneelfps)
- Safety harness in `joinErrors` to prevent panic ([#3577](https://github.com/redis/go-redis/pull/3577)) by [@manisharma](https://github.com/manisharma)

## ⚡ Performance

- Connection state machine with race condition fixes ([#3559](https://github.com/redis/go-redis/pull/3559)) by [@ndyakov](https://github.com/ndyakov)
- Pool performance improvements: 47-67% faster Get/Put, 33% less memory, 50% fewer allocations ([#3565](https://github.com/redis/go-redis/pull/3565)) by [@ndyakov](https://github.com/ndyakov)

## 🧪 Testing & Infrastructure

- Updated to Redis 8.4.0 image ([#3603](https://github.com/redis/go-redis/pull/3603)) by [@ndyakov](https://github.com/ndyakov)
- Added Redis 8.4-RC1-pre to CI ([#3572](https://github.com/redis/go-redis/pull/3572)) by [@ndyakov](https://github.com/ndyakov)
- Refactored tests for idiomatic Go ([#3561](https://github.com/redis/go-redis/pull/3561), [#3562](https://github.com/redis/go-redis/pull/3562), [#3563](https://github.com/redis/go-redis/pull/3563)) by [@12ya](https://github.com/12ya)

## 👥 Contributors

We'd like to thank all the contributors who worked on this release!

[@12ya](https://github.com/12ya), [@ajax16384](https://github.com/ajax16384), [@cxljs](https://github.com/cxljs), [@cyningsun](https://github.com/cyningsun), [@destinyoooo](https://github.com/destinyoooo), [@dragneelfps](https://github.com/dragneelfps), [@htemelski-redis](https://github.com/htemelski-redis), [@manisharma](https://github.com/manisharma), [@ndyakov](https://github.com/ndyakov), [@ofekshenawa](https://github.com/ofekshenawa), [@pvragov](https://github.com/pvragov)

---

**Full Changelog**: https://github.com/redis/go-redis/compare/v9.16.0...v9.17.0

# 9.16.0 (2025-10-23)

## 🚀 Highlights

### Maintenance Notifications Support

This release introduces comprehensive support for Redis maintenance notifications, enabling applications to handle server maintenance events gracefully. The new `maintnotifications` package provides:

- **RESP3 Push Notifications**: Full support for Redis RESP3 protocol push notifications
- **Connection Handoff**: Automatic connection migration during server maintenance with configurable retry policies and circuit breakers
- **Graceful Degradation**: Configurable timeout relaxation during maintenance windows to prevent false failures
- **Event-Driven Architecture**: Background workers with on-demand scaling for efficient handoff processing
- **Production-Ready**: Comprehensive E2E testing framework and monitoring capabilities

For detailed usage examples and configuration options, see the [maintenance notifications documentation](maintnotifications/README.md).

## ✨ New Features

- **Trace Filtering**: Add support for filtering traces for specific commands, including pipeline operations and dial operations ([#3519](https://github.com/redis/go-redis/pull/3519), [#3550](https://github.com/redis/go-redis/pull/3550))
  - New `TraceCmdFilter` option to selectively trace commands
  - Reduces overhead by excluding high-frequency or low-value commands from traces

## 🐛 Bug Fixes

- **Pipeline Error Handling**: Fix issue where pipeline repeatedly sets the same error ([#3525](https://github.com/redis/go-redis/pull/3525))
- **Connection Pool**: Ensure re-authentication does not interfere with connection handoff operations ([#3547](https://github.com/redis/go-redis/pull/3547))

## 🔧 Improvements

- **Hash Commands**: Update hash command implementations ([#3523](https://github.com/redis/go-redis/pull/3523))
- **OpenTelemetry**: Use `metric.WithAttributeSet` to avoid unnecessary attribute copying in redisotel ([#3552](https://github.com/redis/go-redis/pull/3552))

## 📚 Documentation

- **Cluster Client**: Add explanation for why `MaxRetries` is disabled for `ClusterClient` ([#3551](https://github.com/redis/go-redis/pull/3551))

## 🧪 Testing & Infrastructure

- **E2E Testing**: Upgrade E2E testing framework with improved reliability and coverage ([#3541](https://github.com/redis/go-redis/pull/3541))
- **Release Process**: Improved resiliency of the release process ([#3530](https://github.com/redis/go-redis/pull/3530))

## 📦 Dependencies

- Bump `rojopolis/spellcheck-github-actions` from 0.51.0 to 0.52.0 ([#3520](https://github.com/redis/go-redis/pull/3520))
- Bump `github/codeql-action` from 3 to 4 ([#3544](https://github.com/redis/go-redis/pull/3544))

## 👥 Contributors

We'd like to thank all the contributors who worked on this release!

[@ndyakov](https://github.com/ndyakov), [@htemelski-redis](https://github.com/htemelski-redis), [@Sovietaced](https://github.com/Sovietaced), [@Udhayarajan](https://github.com/Udhayarajan), [@boekkooi-impossiblecloud](https://github.com/boekkooi-impossiblecloud), [@Pika-Gopher](https://github.com/Pika-Gopher), [@cxljs](https://github.com/cxljs), [@huiyifyj](https://github.com/huiyifyj), [@omid-h70](https://github.com/omid-h70)

---

**Full Changelog**: https://github.com/redis/go-redis/compare/v9.14.0...v9.16.0


# 9.15.0 was accidentally released. Please use version 9.16.0 instead.

# 9.15.0-beta.3 (2025-09-26)

## Highlights
This beta release includes a pre-production version of processing push notifications and hitless upgrades.

# Changes

- chore: Update hash_commands.go ([#3523](https://github.com/redis/go-redis/pull/3523))

## 🚀 New Features

- feat: RESP3 notifications support & Hitless notifications handling ([#3418](https://github.com/redis/go-redis/pull/3418))

## 🐛 Bug Fixes

- fix: pipeline repeatedly sets the error ([#3525](https://github.com/redis/go-redis/pull/3525))

## 🧰 Maintenance

- chore(deps): bump rojopolis/spellcheck-github-actions from 0.51.0 to 0.52.0 ([#3520](https://github.com/redis/go-redis/pull/3520))
- feat(e2e-testing): maintnotifications e2e and refactor ([#3526](https://github.com/redis/go-redis/pull/3526))
- feat(tag.sh): Improved resiliency of the release process ([#3530](https://github.com/redis/go-redis/pull/3530))

## Contributors
We'd like to thank all the contributors who worked on this release!

[@cxljs](https://github.com/cxljs), [@ndyakov](https://github.com/ndyakov), [@htemelski-redis](https://github.com/htemelski-redis), and [@omid-h70](https://github.com/omid-h70)


# 9.15.0-beta.1 (2025-09-10)

## Highlights
This beta release includes a pre-production version of processing push notifications and hitless upgrades.

### Hitless Upgrades
Hitless upgrades is a major new feature that allows for zero-downtime upgrades in Redis clusters.
You can find more information in the [Hitless Upgrades documentation](https://github.com/redis/go-redis/tree/master/hitless).

# Changes

## 🚀 New Features
- [CAE-1088] & [CAE-1072] feat: RESP3 notifications support & Hitless notifications handling ([#3418](https://github.com/redis/go-redis/pull/3418))

## Contributors
We'd like to thank all the contributors who worked on this release!

[@ndyakov](https://github.com/ndyakov), [@htemelski-redis](https://github.com/htemelski-redis), [@ofekshenawa](https://github.com/ofekshenawa)


# 9.14.0 (2025-09-10)

## Highlights
- Added batch process method to the pipeline ([#3510](https://github.com/redis/go-redis/pull/3510))

# Changes

## 🚀 New Features

- Added batch process method to the pipeline ([#3510](https://github.com/redis/go-redis/pull/3510))

## 🐛 Bug Fixes

- fix: SetErr on Cmd if the command cannot be queued correctly in multi/exec ([#3509](https://github.com/redis/go-redis/pull/3509))

## 🧰 Maintenance

- Updates release drafter config to exclude dependabot ([#3511](https://github.com/redis/go-redis/pull/3511))
- chore(deps): bump actions/setup-go from 5 to 6 ([#3504](https://github.com/redis/go-redis/pull/3504))

## Contributors
We'd like to thank all the contributors who worked on this release!

[@elena-kolevska](https://github.com/elena-kolevksa), [@htemelski-redis](https://github.com/htemelski-redis) and [@ndyakov](https://github.com/ndyakov)


# 9.13.0 (2025-09-03)

## Highlights
- Pipeliner expose queued commands ([#3496](https://github.com/redis/go-redis/pull/3496))
- Ensure that JSON.GET returns Nil response ([#3470](https://github.com/redis/go-redis/pull/3470))
- Fixes on Read and Write buffer sizes and UniversalOptions

## Changes
- Pipeliner expose queued commands ([#3496](https://github.com/redis/go-redis/pull/3496))
- fix(test): fix a timing issue in pubsub test ([#3498](https://github.com/redis/go-redis/pull/3498))
- Allow users to enable read-write splitting in failover mode. ([#3482](https://github.com/redis/go-redis/pull/3482))
- Set the read/write buffer size of the sentinel client to 4KiB ([#3476](https://github.com/redis/go-redis/pull/3476))

## 🚀 New Features

- fix(otel): register wait metrics ([#3499](https://github.com/redis/go-redis/pull/3499))
- Support subscriptions against cluster slave nodes ([#3480](https://github.com/redis/go-redis/pull/3480))
- Add wait metrics to otel ([#3493](https://github.com/redis/go-redis/pull/3493))
- Clean failing timeout implementation ([#3472](https://github.com/redis/go-redis/pull/3472))

## 🐛 Bug Fixes

- Do not assume that all non-IP hosts are loopbacks ([#3085](https://github.com/redis/go-redis/pull/3085))
- Ensure that JSON.GET returns Nil response ([#3470](https://github.com/redis/go-redis/pull/3470))

## 🧰 Maintenance

- fix(otel): register wait metrics ([#3499](https://github.com/redis/go-redis/pull/3499))
- fix(make test): Add default env in makefile ([#3491](https://github.com/redis/go-redis/pull/3491))
- Update the introduction to running tests in README.md ([#3495](https://github.com/redis/go-redis/pull/3495))
- test: Add comprehensive edge case tests for IncrByFloat command ([#3477](https://github.com/redis/go-redis/pull/3477))
- Set the default read/write buffer size of Redis connection to 32KiB ([#3483](https://github.com/redis/go-redis/pull/3483))
- Bumps test image to 8.2.1-pre ([#3478](https://github.com/redis/go-redis/pull/3478))
- fix UniversalOptions miss ReadBufferSize and WriteBufferSize options ([#3485](https://github.com/redis/go-redis/pull/3485))
- chore(deps): bump actions/checkout from 4 to 5 ([#3484](https://github.com/redis/go-redis/pull/3484))
- Removes dry run for stale issues policy ([#3471](https://github.com/redis/go-redis/pull/3471))
- Update otel metrics URL ([#3474](https://github.com/redis/go-redis/pull/3474))

## Contributors
We'd like to thank all the contributors who worked on this release!

[@LINKIWI](https://github.com/LINKIWI), [@cxljs](https://github.com/cxljs), [@cybersmeashish](https://github.com/cybersmeashish), [@elena-kolevska](https://github.com/elena-kolevska), [@htemelski-redis](https://github.com/htemelski-redis), [@mwhooker](https://github.com/mwhooker), [@ndyakov](https://github.com/ndyakov), [@ofekshenawa](https://github.com/ofekshenawa), [@suever](https://github.com/suever)


# 9.12.1 (2025-08-11)
## 🚀 Highlights
In the last version (9.12.0) the client introduced bigger write and read buffer sized. The default value we set was 512KiB.
However, users reported that this is too big for most use cases and can lead to high memory usage.
In this version the default value is changed to 256KiB. The `README.md` was updated to reflect the
correct default value and include a note that the default value can be changed.

## 🐛 Bug Fixes

- fix(options): Add buffer sizes to failover. Update README ([#3468](https://github.com/redis/go-redis/pull/3468))

## 🧰 Maintenance

- fix(options): Add buffer sizes to failover. Update README ([#3468](https://github.com/redis/go-redis/pull/3468))
- chore: update & fix otel example ([#3466](https://github.com/redis/go-redis/pull/3466))

## Contributors
We'd like to thank all the contributors who worked on this release!

[@ndyakov](https://github.com/ndyakov) and [@vmihailenco](https://github.com/vmihailenco)

# 9.12.0 (2025-08-05)

## 🚀 Highlights

- This release includes support for [Redis 8.2](https://redis.io/docs/latest/operate/oss_and_stack/stack-with-enterprise/release-notes/redisce/redisos-8.2-release-notes/).
- Introduces an experimental Query Builders for `FTSearch`, `FTAggregate` and other search commands.
- Adds support for `EPSILON` option in `FT.VSIM`.
- Includes bug fixes and improvements contributed by the community related to ring and [redisotel](https://github.com/redis/go-redis/tree/master/extra/redisotel).

## Changes
- Improve stale issue workflow ([#3458](https://github.com/redis/go-redis/pull/3458))
- chore(ci): Add 8.2 rc2 pre build for CI ([#3459](https://github.com/redis/go-redis/pull/3459))
- Added new stream commands ([#3450](https://github.com/redis/go-redis/pull/3450))
- feat: Add "skip_verify" to Sentinel ([#3428](https://github.com/redis/go-redis/pull/3428))
- fix: `errors.Join` requires Go 1.20 or later ([#3442](https://github.com/redis/go-redis/pull/3442))
- DOC-4344 document quickstart examples ([#3426](https://github.com/redis/go-redis/pull/3426))
- feat(bitop): add support for the new bitop operations ([#3409](https://github.com/redis/go-redis/pull/3409))

## 🚀 New Features

- feat: recover addIdleConn may occur panic ([#2445](https://github.com/redis/go-redis/pull/2445))
- feat(ring): specify custom health check func via HeartbeatFn option ([#2940](https://github.com/redis/go-redis/pull/2940))
- Add Query Builder for RediSearch commands ([#3436](https://github.com/redis/go-redis/pull/3436))
- add configurable buffer sizes for Redis connections ([#3453](https://github.com/redis/go-redis/pull/3453))
- Add VAMANA vector type to RediSearch ([#3449](https://github.com/redis/go-redis/pull/3449))
- VSIM add `EPSILON` option ([#3454](https://github.com/redis/go-redis/pull/3454))
- Add closing support to otel metrics instrumentation ([#3444](https://github.com/redis/go-redis/pull/3444))

## 🐛 Bug Fixes

- fix(redisotel): fix buggy append in reportPoolStats ([#3122](https://github.com/redis/go-redis/pull/3122))
- fix(search): return results even if doc is empty ([#3457](https://github.com/redis/go-redis/pull/3457))
- [ISSUE-3402]: Ring.Pipelined return dial timeout error ([#3403](https://github.com/redis/go-redis/pull/3403))

## 🧰 Maintenance

- Merges stale issues jobs into one job with two steps ([#3463](https://github.com/redis/go-redis/pull/3463))
- improve code readability ([#3446](https://github.com/redis/go-redis/pull/3446))
- chore(release): 9.12.0-beta.1 ([#3460](https://github.com/redis/go-redis/pull/3460))
- DOC-5472 time series doc examples ([#3443](https://github.com/redis/go-redis/pull/3443))
- Add VAMANA compression algorithm tests ([#3461](https://github.com/redis/go-redis/pull/3461))
- bumped redis 8.2 version used in the CI/CD ([#3451](https://github.com/redis/go-redis/pull/3451))

## Contributors
We'd like to thank all the contributors who worked on this release!

[@andy-stark-redis](https://github.com/andy-stark-redis), [@cxljs](https://github.com/cxljs), [@elena-kolevska](https://github.com/elena-kolevska), [@htemelski-redis](https://github.com/htemelski-redis), [@jouir](https://github.com/jouir), [@monkey92t](https://github.com/monkey92t), [@ndyakov](https://github.com/ndyakov), [@ofekshenawa](https://github.com/ofekshenawa), [@rokn](https://github.com/rokn), [@smnvdev](https://github.com/smnvdev), [@strobil](https://github.com/strobil) and [@wzy9607](https://github.com/wzy9607)

## New Contributors
* [@htemelski-redis](https://github.com/htemelski-redis) made their first contribution in [#3409](https://github.com/redis/go-redis/pull/3409)
* [@smnvdev](https://github.com/smnvdev) made their first contribution in [#3403](https://github.com/redis/go-redis/pull/3403)
* [@rokn](https://github.com/rokn) made their first contribution in [#3444](https://github.com/redis/go-redis/pull/3444)

# 9.11.0 (2025-06-24)

## 🚀 Highlights

Fixes TxPipeline to work correctly in cluster scenarios, allowing execution of commands
only in the same slot.

# Changes

## 🚀 New Features

- Set cluster slot for `scan` commands, rather than random ([#2623](https://github.com/redis/go-redis/pull/2623))
- Add CredentialsProvider field to UniversalOptions ([#2927](https://github.com/redis/go-redis/pull/2927))
- feat(redisotel): add WithCallerEnabled option ([#3415](https://github.com/redis/go-redis/pull/3415))

## 🐛 Bug Fixes

- fix(txpipeline): keyless commands should take the slot of the keyed ([#3411](https://github.com/redis/go-redis/pull/3411))
- fix(loading): cache the loaded flag for slave nodes ([#3410](https://github.com/redis/go-redis/pull/3410))
- fix(txpipeline): should return error on multi/exec on multiple slots ([#3408](https://github.com/redis/go-redis/pull/3408))
- fix: check if the shard exists to avoid returning nil ([#3396](https://github.com/redis/go-redis/pull/3396))

## 🧰 Maintenance

- feat: optimize connection pool waitTurn ([#3412](https://github.com/redis/go-redis/pull/3412))
- chore(ci): update CI redis builds ([#3407](https://github.com/redis/go-redis/pull/3407))
- chore: remove a redundant method from `Ring`, `Client` and `ClusterClient` ([#3401](https://github.com/redis/go-redis/pull/3401))
- test: refactor TestBasicCredentials using table-driven tests ([#3406](https://github.com/redis/go-redis/pull/3406))
- perf: reduce unnecessary memory allocation operations ([#3399](https://github.com/redis/go-redis/pull/3399))
- fix: insert entry during iterating over a map ([#3398](https://github.com/redis/go-redis/pull/3398))
- DOC-5229 probabilistic data type examples ([#3413](https://github.com/redis/go-redis/pull/3413))
- chore(deps): bump rojopolis/spellcheck-github-actions from 0.49.0 to 0.51.0 ([#3414](https://github.com/redis/go-redis/pull/3414))

## Contributors
We'd like to thank all the contributors who worked on this release!

[@andy-stark-redis](https://github.com/andy-stark-redis), [@boekkooi-impossiblecloud](https://github.com/boekkooi-impossiblecloud), [@cxljs](https://github.com/cxljs), [@dcherubini](https://github.com/dcherubini), [@dependabot[bot]](https://github.com/apps/dependabot), [@iamamirsalehi](https://github.com/iamamirsalehi), [@ndyakov](https://github.com/ndyakov), [@pete-woods](https://github.com/pete-woods), [@twz915](https://github.com/twz915) and [dependabot[bot]](https://github.com/apps/dependabot)

# 9.10.0 (2025-06-06)

## 🚀 Highlights

`go-redis` now supports [vector sets](https://redis.io/docs/latest/develop/data-types/vector-sets/). This data type is marked
as "in preview" in Redis and its support in `go-redis` is marked as experimental. You can find examples in the documentation and
in the `doctests` folder.

# Changes

## 🚀 New Features

- feat: support vectorset ([#3375](https://github.com/redis/go-redis/pull/3375))

## 🧰 Maintenance

- Add the missing NewFloatSliceResult for testing ([#3393](https://github.com/redis/go-redis/pull/3393))
- DOC-5078 vector set examples ([#3394](https://github.com/redis/go-redis/pull/3394))

## Contributors
We'd like to thank all the contributors who worked on this release!

[@AndBobsYourUncle](https://github.com/AndBobsYourUncle), [@andy-stark-redis](https://github.com/andy-stark-redis), [@fukua95](https://github.com/fukua95) and [@ndyakov](https://github.com/ndyakov)



# 9.9.0 (2025-05-27)

## 🚀 Highlights
- **Token-based Authentication**: Added `StreamingCredentialsProvider` for dynamic credential updates (experimental)
  - Can be used with [go-redis-entraid](https://github.com/redis/go-redis-entraid) for Azure AD authentication
- **Connection Statistics**: Added connection waiting statistics for better monitoring
- **Failover Improvements**: Added `ParseFailoverURL` for easier failover configuration
- **Ring Client Enhancements**: Added shard access methods for better Pub/Sub management

## ✨ New Features
- Added `StreamingCredentialsProvider` for token-based authentication ([#3320](https://github.com/redis/go-redis/pull/3320))
  - Supports dynamic credential updates
  - Includes connection close hooks
  - Note: Currently marked as experimental
- Added `ParseFailoverURL` for parsing failover URLs ([#3362](https://github.com/redis/go-redis/pull/3362))
- Added connection waiting statistics ([#2804](https://github.com/redis/go-redis/pull/2804))
- Added new utility functions:
  - `ParseFloat` and `MustParseFloat` in public utils package ([#3371](https://github.com/redis/go-redis/pull/3371))
  - Unit tests for `Atoi`, `ParseInt`, `ParseUint`, and `ParseFloat` ([#3377](https://github.com/redis/go-redis/pull/3377))
- Added Ring client shard access methods:
  - `GetShardClients()` to retrieve all active shard clients
  - `GetShardClientForKey(key string)` to get the shard client for a specific key ([#3388](https://github.com/redis/go-redis/pull/3388))

## 🐛 Bug Fixes
- Fixed routing reads to loading slave nodes ([#3370](https://github.com/redis/go-redis/pull/3370))
- Added support for nil lag in XINFO GROUPS ([#3369](https://github.com/redis/go-redis/pull/3369))
- Fixed pool acquisition timeout issues ([#3381](https://github.com/redis/go-redis/pull/3381))
- Optimized unnecessary copy operations ([#3376](https://github.com/redis/go-redis/pull/3376))

## 📚 Documentation
- Updated documentation for XINFO GROUPS with nil lag support ([#3369](https://github.com/redis/go-redis/pull/3369))
- Added package-level comments for new features

## ⚡ Performance and Reliability
- Optimized `ReplaceSpaces` function ([#3383](https://github.com/redis/go-redis/pull/3383))
- Set default value for `Options.Protocol` in `init()` ([#3387](https://github.com/redis/go-redis/pull/3387))
- Exported pool errors for public consumption ([#3380](https://github.com/redis/go-redis/pull/3380))

## 🔧 Dependencies and Infrastructure
- Updated Redis CI to version 8.0.1 ([#3372](https://github.com/redis/go-redis/pull/3372))
- Updated spellcheck GitHub Actions ([#3389](https://github.com/redis/go-redis/pull/3389))
- Removed unused parameters ([#3382](https://github.com/redis/go-redis/pull/3382), [#3384](https://github.com/redis/go-redis/pull/3384))

## 🧪 Testing
- Added unit tests for pool acquisition timeout ([#3381](https://github.com/redis/go-redis/pull/3381))
- Added unit tests for utility functions ([#3377](https://github.com/redis/go-redis/pull/3377))

## 👥 Contributors

We would like to thank all the contributors who made this release possible:

[@ndyakov](https://github.com/ndyakov), [@ofekshenawa](https://github.com/ofekshenawa), [@LINKIWI](https://github.com/LINKIWI), [@iamamirsalehi](https://github.com/iamamirsalehi), [@fukua95](https://github.com/fukua95), [@lzakharov](https://github.com/lzakharov), [@DengY11](https://github.com/DengY11)

## 📝 Changelog

For a complete list of changes, see the [full changelog](https://github.com/redis/go-redis/compare/v9.8.0...v9.9.0).

# 9.8.0 (2025-04-30)

## 🚀 Highlights
- **Redis 8 Support**: Full compatibility with Redis 8.0, including testing and CI integration
- **Enhanced Hash Operations**: Added support for new hash commands (`HGETDEL`, `HGETEX`, `HSETEX`) and `HSTRLEN` command
- **Search Improvements**: Enabled Search DIALECT 2 by default and added `CountOnly` argument for `FT.Search`

## ✨ New Features
- Added support for new hash commands: `HGETDEL`, `HGETEX`, `HSETEX` ([#3305](https://github.com/redis/go-redis/pull/3305))
- Added `HSTRLEN` command for hash operations ([#2843](https://github.com/redis/go-redis/pull/2843))
- Added `Do` method for raw query by single connection from `pool.Conn()` ([#3182](https://github.com/redis/go-redis/pull/3182))
- Prevent false-positive marshaling by treating zero time.Time as empty in isEmptyValue ([#3273](https://github.com/redis/go-redis/pull/3273))
- Added FailoverClusterClient support for Universal client ([#2794](https://github.com/redis/go-redis/pull/2794))
- Added support for cluster mode with `IsClusterMode` config parameter ([#3255](https://github.com/redis/go-redis/pull/3255))
- Added client name support in `HELLO` RESP handshake ([#3294](https://github.com/redis/go-redis/pull/3294))
- **Enabled Search DIALECT 2 by default** ([#3213](https://github.com/redis/go-redis/pull/3213))
- Added read-only option for failover configurations ([#3281](https://github.com/redis/go-redis/pull/3281))
- Added `CountOnly` argument for `FT.Search` to use `LIMIT 0 0` ([#3338](https://github.com/redis/go-redis/pull/3338))
- Added `DB` option support in `NewFailoverClusterClient` ([#3342](https://github.com/redis/go-redis/pull/3342))
- Added `nil` check for the options when creating a client ([#3363](https://github.com/redis/go-redis/pull/3363))

## 🐛 Bug Fixes
- Fixed `PubSub` concurrency safety issues ([#3360](https://github.com/redis/go-redis/pull/3360))
- Fixed panic caused when argument is `nil` ([#3353](https://github.com/redis/go-redis/pull/3353))
- Improved error handling when fetching master node from sentinels ([#3349](https://github.com/redis/go-redis/pull/3349))
- Fixed connection pool timeout issues and increased retries ([#3298](https://github.com/redis/go-redis/pull/3298))
- Fixed context cancellation error leading to connection spikes on Primary instances ([#3190](https://github.com/redis/go-redis/pull/3190))
- Fixed RedisCluster client to consider `MASTERDOWN` a retriable error ([#3164](https://github.com/redis/go-redis/pull/3164))
- Fixed tracing to show complete commands instead of truncated versions ([#3290](https://github.com/redis/go-redis/pull/3290))
- Fixed OpenTelemetry instrumentation to prevent multiple span reporting ([#3168](https://github.com/redis/go-redis/pull/3168))
- Fixed `FT.Search` Limit argument and added `CountOnly` argument for limit 0 0 ([#3338](https://github.com/redis/go-redis/pull/3338))
- Fixed missing command in interface ([#3344](https://github.com/redis/go-redis/pull/3344))
- Fixed slot calculation for `COUNTKEYSINSLOT` command ([#3327](https://github.com/redis/go-redis/pull/3327))
- Updated PubSub implementation with correct context ([#3329](https://github.com/redis/go-redis/pull/3329))

## 📚 Documentation
- Added hash search examples ([#3357](https://github.com/redis/go-redis/pull/3357))
- Fixed documentation comments ([#3351](https://github.com/redis/go-redis/pull/3351))
- Added `CountOnly` search example ([#3345](https://github.com/redis/go-redis/pull/3345))
- Added examples for list commands: `LLEN`, `LPOP`, `LPUSH`, `LRANGE`, `RPOP`, `RPUSH` ([#3234](https://github.com/redis/go-redis/pull/3234))
- Added `SADD` and `SMEMBERS` command examples ([#3242](https://github.com/redis/go-redis/pull/3242))
- Updated `README.md` to use Redis Discord guild ([#3331](https://github.com/redis/go-redis/pull/3331))
- Updated `HExpire` command documentation ([#3355](https://github.com/redis/go-redis/pull/3355))
- Featured OpenTelemetry instrumentation more prominently ([#3316](https://github.com/redis/go-redis/pull/3316))
- Updated `README.md` with additional information ([#310ce55](https://github.com/redis/go-redis/commit/310ce55))

## ⚡ Performance and Reliability
- Bound connection pool background dials to configured dial timeout ([#3089](https://github.com/redis/go-redis/pull/3089))
- Ensured context isn't exhausted via concurrent query ([#3334](https://github.com/redis/go-redis/pull/3334))

## 🔧 Dependencies and Infrastructure
- Updated testing image to Redis 8.0-RC2 ([#3361](https://github.com/redis/go-redis/pull/3361))
- Enabled CI for Redis CE 8.0 ([#3274](https://github.com/redis/go-redis/pull/3274))
- Updated various dependencies:
  - Bumped golangci/golangci-lint-action from 6.5.0 to 7.0.0 ([#3354](https://github.com/redis/go-redis/pull/3354))
  - Bumped rojopolis/spellcheck-github-actions ([#3336](https://github.com/redis/go-redis/pull/3336))
  - Bumped golang.org/x/net in example/otel ([#3308](https://github.com/redis/go-redis/pull/3308))
- Migrated golangci-lint configuration to v2 format ([#3354](https://github.com/redis/go-redis/pull/3354))

## ⚠️ Breaking Changes
- **Enabled Search DIALECT 2 by default** ([#3213](https://github.com/redis/go-redis/pull/3213))
- Dropped RedisGears (Triggers and Functions) support ([#3321](https://github.com/redis/go-redis/pull/3321))
- Dropped FT.PROFILE command that was never enabled ([#3323](https://github.com/redis/go-redis/pull/3323))

## 🔒 Security
- Fixed network error handling on SETINFO (CVE-2025-29923) ([#3295](https://github.com/redis/go-redis/pull/3295))

## 🧪 Testing
- Added integration tests for Redis 8 behavior changes in Redis Search ([#3337](https://github.com/redis/go-redis/pull/3337))
- Added vector types INT8 and UINT8 tests ([#3299](https://github.com/redis/go-redis/pull/3299))
- Added test codes for search_commands.go ([#3285](https://github.com/redis/go-redis/pull/3285))
- Fixed example test sorting ([#3292](https://github.com/redis/go-redis/pull/3292))

## 👥 Contributors

We would like to thank all the contributors who made this release possible:

[@alexander-menshchikov](https://github.com/alexander-menshchikov), [@EXPEbdodla](https://github.com/EXPEbdodla), [@afti](https://github.com/afti), [@dmaier-redislabs](https://github.com/dmaier-redislabs), [@four_leaf_clover](https://github.com/four_leaf_clover), [@alohaglenn](https://github.com/alohaglenn), [@gh73962](https://github.com/gh73962), [@justinmir](https://github.com/justinmir), [@LINKIWI](https://github.com/LINKIWI), [@liushuangbill](https://github.com/liushuangbill), [@golang88](https://github.com/golang88), [@gnpaone](https://github.com/gnpaone), [@ndyakov](https://github.com/ndyakov), [@nikolaydubina](https://github.com/nikolaydubina), [@oleglacto](https://github.com/oleglacto), [@andy-stark-redis](https://github.com/andy-stark-redis), [@rodneyosodo](https://github.com/rodneyosodo), [@dependabot](https://github.com/dependabot), [@rfyiamcool](https://github.com/rfyiamcool), [@frankxjkuang](https://github.com/frankxjkuang), [@fukua95](https://github.com/fukua95), [@soleymani-milad](https://github.com/soleymani-milad), [@ofekshenawa](https://github.com/ofekshenawa), [@khasanovbi](https://github.com/khasanovbi)


# Old Changelog
## Unreleased

### Changed

* `go-redis` won't skip span creation if the parent spans is not recording. ([#2980](https://github.com/redis/go-redis/issues/2980))
  Users can use the OpenTelemetry sampler to control the sampling behavior.
  For instance, you can use the `ParentBased(NeverSample())` sampler from `go.opentelemetry.io/otel/sdk/trace` to keep
  a similar behavior (drop orphan spans) of `go-redis` as before.

## [9.0.5](https://github.com/redis/go-redis/compare/v9.0.4...v9.0.5) (2023-05-29)


### Features

* Add ACL LOG ([#2536](https://github.com/redis/go-redis/issues/2536)) ([31ba855](https://github.com/redis/go-redis/commit/31ba855ddebc38fbcc69a75d9d4fb769417cf602))
* add field protocol to setupClusterQueryParams ([#2600](https://github.com/redis/go-redis/issues/2600)) ([840c25c](https://github.com/redis/go-redis/commit/840c25cb6f320501886a82a5e75f47b491e46fbe))
* add protocol option ([#2598](https://github.com/redis/go-redis/issues/2598)) ([3917988](https://github.com/redis/go-redis/commit/391798880cfb915c4660f6c3ba63e0c1a459e2af))



## [9.0.4](https://github.com/redis/go-redis/compare/v9.0.3...v9.0.4) (2023-05-01)


### Bug Fixes

* reader float parser ([#2513](https://github.com/redis/go-redis/issues/2513)) ([46f2450](https://github.com/redis/go-redis/commit/46f245075e6e3a8bd8471f9ca67ea95fd675e241))


### Features

* add client info command ([#2483](https://github.com/redis/go-redis/issues/2483)) ([b8c7317](https://github.com/redis/go-redis/commit/b8c7317cc6af444603731f7017c602347c0ba61e))
* no longer verify HELLO error messages ([#2515](https://github.com/redis/go-redis/issues/2515)) ([7b4f217](https://github.com/redis/go-redis/commit/7b4f2179cb5dba3d3c6b0c6f10db52b837c912c8))
* read the structure to increase the judgment of the omitempty op… ([#2529](https://github.com/redis/go-redis/issues/2529)) ([37c057b](https://github.com/redis/go-redis/commit/37c057b8e597c5e8a0e372337f6a8ad27f6030af))



## [9.0.3](https://github.com/redis/go-redis/compare/v9.0.2...v9.0.3) (2023-04-02)

### New Features

- feat(scan): scan time.Time sets the default decoding (#2413)
- Add support for CLUSTER LINKS command (#2504)
- Add support for acl dryrun command (#2502)
- Add support for COMMAND GETKEYS & COMMAND GETKEYSANDFLAGS (#2500)
- Add support for LCS Command (#2480)
- Add support for BZMPOP (#2456)
- Adding support for ZMPOP command (#2408)
- Add support for LMPOP (#2440)
- feat: remove pool unused fields (#2438)
- Expiretime and PExpireTime (#2426)
- Implement `FUNCTION` group of commands (#2475)
- feat(zadd): add ZAddLT and ZAddGT (#2429)
- Add: Support for COMMAND LIST command (#2491)
- Add support for BLMPOP (#2442)
- feat: check pipeline.Do to prevent confusion with Exec (#2517)
- Function stats, function kill, fcall and fcall_ro (#2486)
- feat: Add support for CLUSTER SHARDS command (#2507)
- feat(cmd): support for adding byte,bit parameters to the bitpos command (#2498)

### Fixed

- fix: eval api cmd.SetFirstKeyPos (#2501)
- fix: limit the number of connections created (#2441)
- fixed #2462  v9 continue support dragonfly,  it's Hello command return "NOAUTH Authentication required" error (#2479)
- Fix for internal/hscan/structmap.go:89:23: undefined: reflect.Pointer (#2458)
- fix: group lag can be null (#2448)

### Maintenance

- Updating to the latest version of redis (#2508)
- Allowing for running tests on a port other than the fixed 6380 (#2466)
- redis 7.0.8 in tests (#2450)
- docs: Update redisotel example for v9 (#2425)
- chore: update go mod, Upgrade golang.org/x/net version to 0.7.0 (#2476)
- chore: add Chinese translation (#2436)
- chore(deps): bump github.com/bsm/gomega from 1.20.0 to 1.26.0 (#2421)
- chore(deps): bump github.com/bsm/ginkgo/v2 from 2.5.0 to 2.7.0 (#2420)
- chore(deps): bump actions/setup-go from 3 to 4 (#2495)
- docs: add instructions for the HSet api (#2503)
- docs: add reading lag field comment (#2451)
- test: update go mod before testing(go mod tidy) (#2423)
- docs: fix comment typo (#2505)
- test: remove testify (#2463)
- refactor: change ListElementCmd to KeyValuesCmd. (#2443)
- fix(appendArg): appendArg case special type (#2489)

## [9.0.2](https://github.com/redis/go-redis/compare/v9.0.1...v9.0.2) (2023-02-01)

### Features

* upgrade OpenTelemetry, use the new metrics API. ([#2410](https://github.com/redis/go-redis/issues/2410)) ([e29e42c](https://github.com/redis/go-redis/commit/e29e42cde2755ab910d04185025dc43ce6f59c65))

## v9 2023-01-30

### Breaking

- Changed Pipelines to not be thread-safe any more.

### Added

- Added support for [RESP3](https://github.com/antirez/RESP3/blob/master/spec.md) protocol. It was
  contributed by @monkey92t who has done the majority of work in this release.
- Added `ContextTimeoutEnabled` option that controls whether the client respects context timeouts
  and deadlines. See
  [Redis Timeouts](https://redis.uptrace.dev/guide/go-redis-debugging.html#timeouts) for details.
- Added `ParseClusterURL` to parse URLs into `ClusterOptions`, for example,
  `redis://user:password@localhost:6789?dial_timeout=3&read_timeout=6s&addr=localhost:6790&addr=localhost:6791`.
- Added metrics instrumentation using `redisotel.IstrumentMetrics`. See
  [documentation](https://redis.uptrace.dev/guide/go-redis-monitoring.html)
- Added `redis.HasErrorPrefix` to help working with errors.

### Changed

- Removed asynchronous cancellation based on the context timeout. It was racy in v8 and is
  completely gone in v9.
- Reworked hook interface and added `DialHook`.
- Replaced `redisotel.NewTracingHook` with `redisotel.InstrumentTracing`. See
  [example](example/otel) and
  [documentation](https://redis.uptrace.dev/guide/go-redis-monitoring.html).
- Replaced `*redis.Z` with `redis.Z` since it is small enough to be passed as value without making
  an allocation.
- Renamed the option `MaxConnAge` to `ConnMaxLifetime`.
- Renamed the option `IdleTimeout` to `ConnMaxIdleTime`.
- Removed connection reaper in favor of `MaxIdleConns`.
- Removed `WithContext` since `context.Context` can be passed directly as an arg.
- Removed `Pipeline.Close` since there is no real need to explicitly manage pipeline resources and
  it can be safely reused via `sync.Pool` etc. `Pipeline.Discard` is still available if you want to
  reset commands for some reason.

### Fixed

- Improved and fixed pipeline retries.
- As usually, added support for more commands and fixed some bugs.


================================================
FILE: RELEASING.md
================================================
# Releasing

1. Run `release.sh` script which updates versions in go.mod files and pushes a new branch to GitHub:

```shell
TAG=v1.0.0 ./scripts/release.sh
```

2. Open a pull request and wait for the build to finish.

3. Merge the pull request and run `tag.sh` to create tags for packages:

```shell
TAG=v1.0.0 ./scripts/tag.sh
```


================================================
FILE: acl_commands.go
================================================
package redis

import "context"

type ACLCmdable interface {
	ACLDryRun(ctx context.Context, username string, command ...interface{}) *StringCmd

	ACLLog(ctx context.Context, count int64) *ACLLogCmd
	ACLLogReset(ctx context.Context) *StatusCmd

	ACLGenPass(ctx context.Context, bit int) *StringCmd

	ACLSetUser(ctx context.Context, username string, rules ...string) *StatusCmd
	ACLDelUser(ctx context.Context, username string) *IntCmd
	ACLUsers(ctx context.Context) *StringSliceCmd
	ACLWhoAmI(ctx context.Context) *StringCmd
	ACLList(ctx context.Context) *StringSliceCmd

	ACLCat(ctx context.Context) *StringSliceCmd
	ACLCatArgs(ctx context.Context, options *ACLCatArgs) *StringSliceCmd
}

type ACLCatArgs struct {
	Category string
}

func (c cmdable) ACLDryRun(ctx context.Context, username string, command ...interface{}) *StringCmd {
	args := make([]interface{}, 0, 3+len(command))
	args = append(args, "acl", "dryrun", username)
	args = append(args, command...)
	cmd := NewStringCmd(ctx, args...)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ACLLog(ctx context.Context, count int64) *ACLLogCmd {
	args := make([]interface{}, 0, 3)
	args = append(args, "acl", "log")
	if count > 0 {
		args = append(args, count)
	}
	cmd := NewACLLogCmd(ctx, args...)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ACLLogReset(ctx context.Context) *StatusCmd {
	cmd := NewStatusCmd(ctx, "acl", "log", "reset")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ACLDelUser(ctx context.Context, username string) *IntCmd {
	cmd := NewIntCmd(ctx, "acl", "deluser", username)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ACLSetUser(ctx context.Context, username string, rules ...string) *StatusCmd {
	args := make([]interface{}, 3+len(rules))
	args[0] = "acl"
	args[1] = "setuser"
	args[2] = username
	for i, rule := range rules {
		args[i+3] = rule
	}
	cmd := NewStatusCmd(ctx, args...)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ACLGenPass(ctx context.Context, bit int) *StringCmd {
	args := make([]interface{}, 0, 3)
	args = append(args, "acl", "genpass")
	if bit > 0 {
		args = append(args, bit)
	}
	cmd := NewStringCmd(ctx, args...)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ACLUsers(ctx context.Context) *StringSliceCmd {
	cmd := NewStringSliceCmd(ctx, "acl", "users")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ACLWhoAmI(ctx context.Context) *StringCmd {
	cmd := NewStringCmd(ctx, "acl", "whoami")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ACLList(ctx context.Context) *StringSliceCmd {
	cmd := NewStringSliceCmd(ctx, "acl", "list")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ACLCat(ctx context.Context) *StringSliceCmd {
	cmd := NewStringSliceCmd(ctx, "acl", "cat")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ACLCatArgs(ctx context.Context, options *ACLCatArgs) *StringSliceCmd {
	// if there is a category passed, build new cmd, if there isn't - use the ACLCat method
	if options != nil && options.Category != "" {
		cmd := NewStringSliceCmd(ctx, "acl", "cat", options.Category)
		_ = c(ctx, cmd)
		return cmd
	}

	return c.ACLCat(ctx)
}


================================================
FILE: acl_commands_test.go
================================================
package redis_test

import (
	"context"

	"github.com/redis/go-redis/v9"

	. "github.com/bsm/ginkgo/v2"
	. "github.com/bsm/gomega"
)

var TestUserName string = "goredis"
var _ = Describe("ACL", func() {
	var client *redis.Client
	var ctx context.Context

	BeforeEach(func() {
		ctx = context.Background()
		opt := redisOptions()
		client = redis.NewClient(opt)
	})

	It("should ACL LOG", Label("NonRedisEnterprise"), func() {
		Expect(client.ACLLogReset(ctx).Err()).NotTo(HaveOccurred())
		err := client.Do(ctx, "acl", "setuser", "test", ">test", "on", "allkeys", "+get").Err()
		Expect(err).NotTo(HaveOccurred())

		clientAcl := redis.NewClient(redisOptions())
		clientAcl.Options().Username = "test"
		clientAcl.Options().Password = "test"
		clientAcl.Options().DB = 0
		_ = clientAcl.Set(ctx, "mystring", "foo", 0).Err()
		_ = clientAcl.HSet(ctx, "myhash", "foo", "bar").Err()
		_ = clientAcl.SAdd(ctx, "myset", "foo", "bar").Err()

		logEntries, err := client.ACLLog(ctx, 10).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(len(logEntries)).To(Equal(4))

		for _, entry := range logEntries {
			Expect(entry.Reason).To(Equal("command"))
			Expect(entry.Context).To(Equal("toplevel"))
			Expect(entry.Object).NotTo(BeEmpty())
			Expect(entry.Username).To(Equal("test"))
			Expect(entry.AgeSeconds).To(BeNumerically(">=", 0))
			Expect(entry.ClientInfo).NotTo(BeNil())
			Expect(entry.EntryID).To(BeNumerically(">=", 0))
			Expect(entry.TimestampCreated).To(BeNumerically(">=", 0))
			Expect(entry.TimestampLastUpdated).To(BeNumerically(">=", 0))
		}

		limitedLogEntries, err := client.ACLLog(ctx, 2).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(len(limitedLogEntries)).To(Equal(2))

		// cleanup after creating the user
		err = client.Do(ctx, "acl", "deluser", "test").Err()
		Expect(err).NotTo(HaveOccurred())
	})

	It("should ACL LOG RESET", Label("NonRedisEnterprise"), func() {
		// Call ACL LOG RESET
		resetCmd := client.ACLLogReset(ctx)
		Expect(resetCmd.Err()).NotTo(HaveOccurred())
		Expect(resetCmd.Val()).To(Equal("OK"))

		// Verify that the log is empty after the reset
		logEntries, err := client.ACLLog(ctx, 10).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(len(logEntries)).To(Equal(0))
	})

})
var _ = Describe("ACL user commands", Label("NonRedisEnterprise"), func() {
	var client *redis.Client
	var ctx context.Context

	BeforeEach(func() {
		ctx = context.Background()
		opt := redisOptions()
		client = redis.NewClient(opt)
	})

	AfterEach(func() {
		_, err := client.ACLDelUser(context.Background(), TestUserName).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(client.Close()).NotTo(HaveOccurred())
	})

	It("list only default user", func() {
		res, err := client.ACLList(ctx).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(res).To(HaveLen(1))
		Expect(res[0]).To(ContainSubstring("default"))

		res, err = client.ACLUsers(ctx).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(res).To(HaveLen(1))
		Expect(res[0]).To(Equal("default"))

		res1, err := client.ACLWhoAmI(ctx).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(res1).To(Equal("default"))
	})

	It("gen password", func() {
		password, err := client.ACLGenPass(ctx, 0).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(password).NotTo(BeEmpty())
	})

	It("gen password with length", func() {
		bit := 128
		password, err := client.ACLGenPass(ctx, bit).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(password).NotTo(BeEmpty())
		Expect(len(password)).To(Equal(bit / 4))
	})

	It("setuser and deluser", func() {
		res, err := client.ACLList(ctx).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(res).To(HaveLen(1))
		Expect(res[0]).To(ContainSubstring("default"))

		add, err := client.ACLSetUser(ctx, TestUserName, "nopass", "on", "allkeys", "+set", "+get").Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(add).To(Equal("OK"))

		resAfter, err := client.ACLList(ctx).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(resAfter).To(HaveLen(2))
		Expect(resAfter[1]).To(ContainSubstring(TestUserName))

		deletedN, err := client.ACLDelUser(ctx, TestUserName).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(deletedN).To(BeNumerically("==", 1))

		resAfterDeletion, err := client.ACLList(ctx).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(resAfterDeletion).To(HaveLen(1))
		Expect(resAfterDeletion[0]).To(BeEquivalentTo(res[0]))
	})

	It("should acl dryrun", func() {
		dryRun := client.ACLDryRun(ctx, "default", "get", "randomKey")
		Expect(dryRun.Err()).NotTo(HaveOccurred())
		Expect(dryRun.Val()).To(Equal("OK"))
	})
})

var _ = Describe("ACL permissions", Label("NonRedisEnterprise"), func() {
	var client *redis.Client
	var ctx context.Context

	BeforeEach(func() {
		ctx = context.Background()
		opt := redisOptions()
		opt.UnstableResp3 = true
		client = redis.NewClient(opt)
	})

	AfterEach(func() {
		_, err := client.ACLDelUser(context.Background(), TestUserName).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(client.Close()).NotTo(HaveOccurred())
	})

	It("reset permissions", func() {
		add, err := client.ACLSetUser(ctx,
			TestUserName,
			"reset",
			"nopass",
			"on",
		).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(add).To(Equal("OK"))

		connection := client.Conn()
		authed, err := connection.AuthACL(ctx, TestUserName, "").Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(authed).To(Equal("OK"))

		_, err = connection.Get(ctx, "anykey").Result()
		Expect(err).To(HaveOccurred())
	})

	It("add write permissions", func() {
		add, err := client.ACLSetUser(ctx,
			TestUserName,
			"reset",
			"nopass",
			"on",
			"~*",
			"+SET",
		).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(add).To(Equal("OK"))

		connection := client.Conn()
		authed, err := connection.AuthACL(ctx, TestUserName, "").Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(authed).To(Equal("OK"))

		// can write
		v, err := connection.Set(ctx, "anykey", "anyvalue", 0).Result()
		Expect(err).ToNot(HaveOccurred())
		Expect(v).To(Equal("OK"))

		// but can't read
		value, err := connection.Get(ctx, "anykey").Result()
		Expect(err).To(HaveOccurred())
		Expect(value).To(BeEmpty())
	})

	It("add read permissions", func() {
		add, err := client.ACLSetUser(ctx,
			TestUserName,
			"reset",
			"nopass",
			"on",
			"~*",
			"+GET",
		).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(add).To(Equal("OK"))

		connection := client.Conn()
		authed, err := connection.AuthACL(ctx, TestUserName, "").Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(authed).To(Equal("OK"))

		// can read
		value, err := connection.Get(ctx, "anykey").Result()
		Expect(err).ToNot(HaveOccurred())
		Expect(value).To(Equal("anyvalue"))

		// but can't delete
		del, err := connection.Del(ctx, "anykey").Result()
		Expect(err).To(HaveOccurred())
		Expect(del).ToNot(Equal(1))
	})

	It("add del permissions", func() {
		add, err := client.ACLSetUser(ctx,
			TestUserName,
			"reset",
			"nopass",
			"on",
			"~*",
			"+DEL",
		).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(add).To(Equal("OK"))

		connection := client.Conn()
		authed, err := connection.AuthACL(ctx, TestUserName, "").Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(authed).To(Equal("OK"))

		// can read
		del, err := connection.Del(ctx, "anykey").Result()
		Expect(err).ToNot(HaveOccurred())
		Expect(del).To(BeEquivalentTo(1))
	})

	It("set permissions for module commands", func() {
		SkipBeforeRedisVersion(8, "permissions for modules are supported for Redis Version >=8")
		Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
		val, err := client.FTCreate(ctx, "txt", &redis.FTCreateOptions{}, &redis.FieldSchema{FieldName: "txt", FieldType: redis.SearchFieldTypeText}).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(val).To(BeEquivalentTo("OK"))
		WaitForIndexing(client, "txt")
		client.HSet(ctx, "doc1", "txt", "foo baz")
		client.HSet(ctx, "doc2", "txt", "foo bar")
		add, err := client.ACLSetUser(ctx,
			TestUserName,
			"reset",
			"nopass",
			"on",
			"~*",
			"+FT.SEARCH",
			"-FT.DROPINDEX",
			"+json.set",
			"+json.get",
			"-json.clear",
			"+bf.reserve",
			"-bf.info",
			"+cf.reserve",
			"+cms.initbydim",
			"+topk.reserve",
			"+tdigest.create",
			"+ts.create",
			"-ts.info",
		).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(add).To(Equal("OK"))

		c := client.Conn()
		authed, err := c.AuthACL(ctx, TestUserName, "").Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(authed).To(Equal("OK"))

		// has perm for search
		Expect(c.FTSearch(ctx, "txt", "foo ~bar").Err()).NotTo(HaveOccurred())

		// no perm for dropindex
		err = c.FTDropIndex(ctx, "txt").Err()
		Expect(err).To(HaveOccurred())
		Expect(err.Error()).To(ContainSubstring("NOPERM"))

		// json set and get have perm
		Expect(c.JSONSet(ctx, "foo", "$", "\"bar\"").Err()).NotTo(HaveOccurred())
		Expect(c.JSONGet(ctx, "foo", "$").Val()).To(BeEquivalentTo("[\"bar\"]"))

		// no perm for json clear
		err = c.JSONClear(ctx, "foo", "$").Err()
		Expect(err).To(HaveOccurred())
		Expect(err.Error()).To(ContainSubstring("NOPERM"))

		// perm for reserve
		Expect(c.BFReserve(ctx, "bloom", 0.01, 100).Err()).NotTo(HaveOccurred())

		// no perm for info
		err = c.BFInfo(ctx, "bloom").Err()
		Expect(err).To(HaveOccurred())
		Expect(err.Error()).To(ContainSubstring("NOPERM"))

		// perm for cf.reserve
		Expect(c.CFReserve(ctx, "cfres", 100).Err()).NotTo(HaveOccurred())
		// perm for cms.initbydim
		Expect(c.CMSInitByDim(ctx, "cmsdim", 100, 5).Err()).NotTo(HaveOccurred())
		// perm for topk.reserve
		Expect(c.TopKReserve(ctx, "topk", 10).Err()).NotTo(HaveOccurred())
		// perm for tdigest.create
		Expect(c.TDigestCreate(ctx, "tdc").Err()).NotTo(HaveOccurred())
		// perm for ts.create
		Expect(c.TSCreate(ctx, "tsts").Err()).NotTo(HaveOccurred())
		// noperm for ts.info
		err = c.TSInfo(ctx, "tsts").Err()
		Expect(err).To(HaveOccurred())
		Expect(err.Error()).To(ContainSubstring("NOPERM"))

		Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
	})

	It("set permissions for module categories", func() {
		SkipBeforeRedisVersion(8, "permissions for modules are supported for Redis Version >=8")
		Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
		val, err := client.FTCreate(ctx, "txt", &redis.FTCreateOptions{}, &redis.FieldSchema{FieldName: "txt", FieldType: redis.SearchFieldTypeText}).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(val).To(BeEquivalentTo("OK"))
		WaitForIndexing(client, "txt")
		client.HSet(ctx, "doc1", "txt", "foo baz")
		client.HSet(ctx, "doc2", "txt", "foo bar")
		add, err := client.ACLSetUser(ctx,
			TestUserName,
			"reset",
			"nopass",
			"on",
			"~*",
			"+@search",
			"+@json",
			"+@bloom",
			"+@cuckoo",
			"+@topk",
			"+@cms",
			"+@timeseries",
			"+@tdigest",
		).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(add).To(Equal("OK"))

		c := client.Conn()
		authed, err := c.AuthACL(ctx, TestUserName, "").Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(authed).To(Equal("OK"))

		// has perm for search
		Expect(c.FTSearch(ctx, "txt", "foo ~bar").Err()).NotTo(HaveOccurred())
		// perm for dropindex
		Expect(c.FTDropIndex(ctx, "txt").Err()).NotTo(HaveOccurred())
		// json set and get have perm
		Expect(c.JSONSet(ctx, "foo", "$", "\"bar\"").Err()).NotTo(HaveOccurred())
		Expect(c.JSONGet(ctx, "foo", "$").Val()).To(BeEquivalentTo("[\"bar\"]"))
		// perm for json clear
		Expect(c.JSONClear(ctx, "foo", "$").Err()).NotTo(HaveOccurred())
		// perm for reserve
		Expect(c.BFReserve(ctx, "bloom", 0.01, 100).Err()).NotTo(HaveOccurred())
		// perm for info
		Expect(c.BFInfo(ctx, "bloom").Err()).NotTo(HaveOccurred())
		// perm for cf.reserve
		Expect(c.CFReserve(ctx, "cfres", 100).Err()).NotTo(HaveOccurred())
		// perm for cms.initbydim
		Expect(c.CMSInitByDim(ctx, "cmsdim", 100, 5).Err()).NotTo(HaveOccurred())
		// perm for topk.reserve
		Expect(c.TopKReserve(ctx, "topk", 10).Err()).NotTo(HaveOccurred())
		// perm for tdigest.create
		Expect(c.TDigestCreate(ctx, "tdc").Err()).NotTo(HaveOccurred())
		// perm for ts.create
		Expect(c.TSCreate(ctx, "tsts").Err()).NotTo(HaveOccurred())
		// perm for ts.info
		Expect(c.TSInfo(ctx, "tsts").Err()).NotTo(HaveOccurred())

		Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
	})
})

var _ = Describe("ACL Categories", func() {
	var client *redis.Client
	var ctx context.Context

	BeforeEach(func() {
		ctx = context.Background()
		opt := redisOptions()
		client = redis.NewClient(opt)
	})

	AfterEach(func() {
		Expect(client.Close()).NotTo(HaveOccurred())
	})

	It("lists acl categories and subcategories", func() {
		res, err := client.ACLCat(ctx).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(len(res)).To(BeNumerically(">", 20))
		Expect(res).To(ContainElements(
			"read",
			"write",
			"keyspace",
			"dangerous",
			"slow",
			"set",
			"sortedset",
			"list",
			"hash",
		))

		res, err = client.ACLCatArgs(ctx, &redis.ACLCatArgs{Category: "read"}).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(res).To(ContainElement("get"))
	})

	It("lists acl categories and subcategories with Modules", func() {
		SkipBeforeRedisVersion(8, "modules are included in acl for redis version >= 8")
		aclTestCase := map[string]string{
			"search":     "FT.CREATE",
			"bloom":      "bf.add",
			"json":       "json.get",
			"cuckoo":     "cf.insert",
			"cms":        "cms.query",
			"topk":       "topk.list",
			"tdigest":    "tdigest.rank",
			"timeseries": "ts.range",
		}
		var cats []interface{}

		for cat, subitem := range aclTestCase {
			cats = append(cats, cat)

			res, err := client.ACLCatArgs(ctx, &redis.ACLCatArgs{
				Category: cat,
			}).Result()
			Expect(err).NotTo(HaveOccurred())
			Expect(res).To(ContainElement(subitem))
		}

		res, err := client.ACLCat(ctx).Result()
		Expect(err).NotTo(HaveOccurred())
		Expect(res).To(ContainElements(cats...))
	})
})


================================================
FILE: adapters.go
================================================
package redis

import (
	"context"
	"errors"
	"net"
	"time"

	"github.com/redis/go-redis/v9/internal/interfaces"
	"github.com/redis/go-redis/v9/push"
)

// ErrInvalidCommand is returned when an invalid command is passed to ExecuteCommand.
var ErrInvalidCommand = errors.New("invalid command type")

// ErrInvalidPool is returned when the pool type is not supported.
var ErrInvalidPool = errors.New("invalid pool type")

// newClientAdapter creates a new client adapter for regular Redis clients.
func newClientAdapter(client *baseClient) interfaces.ClientInterface {
	return &clientAdapter{client: client}
}

// clientAdapter adapts a Redis client to implement interfaces.ClientInterface.
type clientAdapter struct {
	client *baseClient
}

// GetOptions returns the client options.
func (ca *clientAdapter) GetOptions() interfaces.OptionsInterface {
	return &optionsAdapter{options: ca.client.opt}
}

// GetPushProcessor returns the client's push notification processor.
func (ca *clientAdapter) GetPushProcessor() interfaces.NotificationProcessor {
	return &pushProcessorAdapter{processor: ca.client.pushProcessor}
}

// optionsAdapter adapts Redis options to implement interfaces.OptionsInterface.
type optionsAdapter struct {
	options *Options
}

// GetReadTimeout returns the read timeout.
func (oa *optionsAdapter) GetReadTimeout() time.Duration {
	return oa.options.ReadTimeout
}

// GetWriteTimeout returns the write timeout.
func (oa *optionsAdapter) GetWriteTimeout() time.Duration {
	return oa.options.WriteTimeout
}

// GetNetwork returns the network type.
func (oa *optionsAdapter) GetNetwork() string {
	return oa.options.Network
}

// GetAddr returns the connection address.
func (oa *optionsAdapter) GetAddr() string {
	return oa.options.Addr
}

// GetNodeAddress returns the address of the Redis node as reported by the server.
// For cluster clients, this is the endpoint from CLUSTER SLOTS before any transformation.
// For standalone clients, this defaults to Addr.
func (oa *optionsAdapter) GetNodeAddress() string {
	return oa.options.NodeAddress
}

// IsTLSEnabled returns true if TLS is enabled.
func (oa *optionsAdapter) IsTLSEnabled() bool {
	return oa.options.TLSConfig != nil
}

// GetProtocol returns the protocol version.
func (oa *optionsAdapter) GetProtocol() int {
	return oa.options.Protocol
}

// GetPoolSize returns the connection pool size.
func (oa *optionsAdapter) GetPoolSize() int {
	return oa.options.PoolSize
}

// NewDialer returns a new dialer function for the connection.
func (oa *optionsAdapter) NewDialer() func(context.Context) (net.Conn, error) {
	baseDialer := oa.options.NewDialer()
	return func(ctx context.Context) (net.Conn, error) {
		// Extract network and address from the options
		network := oa.options.Network
		addr := oa.options.Addr
		return baseDialer(ctx, network, addr)
	}
}

// pushProcessorAdapter adapts a push.NotificationProcessor to implement interfaces.NotificationProcessor.
type pushProcessorAdapter struct {
	processor push.NotificationProcessor
}

// RegisterHandler registers a handler for a specific push notification name.
func (ppa *pushProcessorAdapter) RegisterHandler(pushNotificationName string, handler interface{}, protected bool) error {
	if pushHandler, ok := handler.(push.NotificationHandler); ok {
		return ppa.processor.RegisterHandler(pushNotificationName, pushHandler, protected)
	}
	return errors.New("handler must implement push.NotificationHandler")
}

// UnregisterHandler removes a handler for a specific push notification name.
func (ppa *pushProcessorAdapter) UnregisterHandler(pushNotificationName string) error {
	return ppa.processor.UnregisterHandler(pushNotificationName)
}

// GetHandler returns the handler for a specific push notification name.
func (ppa *pushProcessorAdapter) GetHandler(pushNotificationName string) interface{} {
	return ppa.processor.GetHandler(pushNotificationName)
}


================================================
FILE: async_handoff_integration_test.go
================================================
package redis

import (
	"context"
	"net"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/redis/go-redis/v9/internal/pool"
	"github.com/redis/go-redis/v9/logging"
	"github.com/redis/go-redis/v9/maintnotifications"
)

// mockNetConn implements net.Conn for testing
type mockNetConn struct {
	addr string
}

func (m *mockNetConn) Read(b []byte) (n int, err error)   { return 0, nil }
func (m *mockNetConn) Write(b []byte) (n int, err error)  { return len(b), nil }
func (m *mockNetConn) Close() error                       { return nil }
func (m *mockNetConn) LocalAddr() net.Addr                { return &mockAddr{m.addr} }
func (m *mockNetConn) RemoteAddr() net.Addr               { return &mockAddr{m.addr} }
func (m *mockNetConn) SetDeadline(t time.Time) error      { return nil }
func (m *mockNetConn) SetReadDeadline(t time.Time) error  { return nil }
func (m *mockNetConn) SetWriteDeadline(t time.Time) error { return nil }

type mockAddr struct {
	addr string
}

func (m *mockAddr) Network() string { return "tcp" }
func (m *mockAddr) String() string  { return m.addr }

// TestEventDrivenHandoffIntegration tests the complete event-driven handoff flow
func TestEventDrivenHandoffIntegration(t *testing.T) {
	t.Run("EventDrivenHandoffWithPoolSkipping", func(t *testing.T) {
		// Create a base dialer for testing
		baseDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
			return &mockNetConn{addr: addr}, nil
		}

		// Create processor with event-driven handoff support
		processor := maintnotifications.NewPoolHook(baseDialer, "tcp", nil, nil)
		defer processor.Shutdown(context.Background())

		// Reset circuit breakers to ensure clean state for this test
		processor.ResetCircuitBreakers()

		// Create a test pool with hooks
		hookManager := pool.NewPoolHookManager()
		hookManager.AddHook(processor)

		testPool := pool.NewConnPool(&pool.Options{
			Dialer: func(ctx context.Context) (net.Conn, error) {
				return &mockNetConn{addr: "original:6379"}, nil
			},
			PoolSize:           int32(5),
			MaxConcurrentDials: 5,
			PoolTimeout:        time.Second,
		})

		// Add the hook to the pool after creation
		testPool.AddPoolHook(processor)
		defer testPool.Close()

		// Set the pool reference in the processor for connection removal on handoff failure
		processor.SetPool(testPool)

		ctx := context.Background()

		// Get a connection and mark it for handoff
		conn, err := testPool.Get(ctx)
		if err != nil {
			t.Fatalf("Failed to get connection: %v", err)
		}

		// Set initialization function with a small delay to ensure handoff is pending
		var initConnCalled atomic.Bool
		initConnStarted := make(chan struct{})
		initConnFunc := func(ctx context.Context, cn *pool.Conn) error {
			close(initConnStarted)            // Signal that InitConn has started
			time.Sleep(50 * time.Millisecond) // Add delay to keep handoff pending
			initConnCalled.Store(true)
			return nil
		}
		conn.SetInitConnFunc(initConnFunc)

		// Mark connection for handoff
		err = conn.MarkForHandoff("new-endpoint:6379", 12345)
		if err != nil {
			t.Fatalf("Failed to mark connection for handoff: %v", err)
		}

		t.Logf("Connection state before Put: %v, ShouldHandoff: %v", conn.GetStateMachine().GetState(), conn.ShouldHandoff())

		// Return connection to pool - this should queue handoff
		testPool.Put(ctx, conn)

		t.Logf("Connection state after Put: %v, ShouldHandoff: %v, IsHandoffPending: %v",
			conn.GetStateMachine().GetState(), conn.ShouldHandoff(), processor.IsHandoffPending(conn))

		// Give the worker goroutine time to start and begin processing
		// We wait for InitConn to actually start (which signals via channel)
		// This ensures the handoff is actively being processed
		select {
		case <-initConnStarted:
			// Good - handoff started processing, InitConn is now running
		case <-time.After(500 * time.Millisecond):
			// Handoff didn't start - this could be due to:
			// 1. Worker didn't start yet (on-demand worker creation is async)
			// 2. Circuit breaker is open
			// 3. Connection was not queued
			// For now, we'll skip the pending map check and just verify behavioral correctness below
			t.Logf("Warning: Handoff did not start processing within 500ms, skipping pending map check")
		}

		// Only check pending map if handoff actually started
		select {
		case <-initConnStarted:
			// Handoff started - verify it's still pending (InitConn is sleeping)
			if !processor.IsHandoffPending(conn) {
				t.Error("Handoff should be in pending map while InitConn is running")
			}
		default:
			// Handoff didn't start yet - skip this check
		}

		// Try to get the same connection - should be skipped due to pending handoff
		conn2, err := testPool.Get(ctx)
		if err != nil {
			t.Fatalf("Failed to get second connection: %v", err)
		}

		// Should get a different connection (the pending one should be skipped)
		if conn == conn2 {
			t.Error("Should have gotten a different connection while handoff is pending")
		}

		// Return the second connection
		testPool.Put(ctx, conn2)

		// Wait for handoff to complete
		time.Sleep(200 * time.Millisecond)

		// Only verify handoff completion if it actually started
		select {
		case <-initConnStarted:
			// Handoff started - verify it completed
			if processor.IsHandoffPending(conn) {
				t.Error("Handoff should have completed and been removed from pending map")
			}

			if !initConnCalled.Load() {
				t.Error("InitConn should have been called during handoff")
			}
		default:
			// Handoff never started - this is a known timing issue with on-demand workers
			// The test still validates the important behavior: connections are skipped when marked for handoff
			t.Logf("Handoff did not start within timeout - skipping completion checks")
		}

		// Now the original connection should be available again
		conn3, err := testPool.Get(ctx)
		if err != nil {
			t.Fatalf("Failed to get third connection: %v", err)
		}

		// Could be the original connection (now handed off) or a new one
		testPool.Put(ctx, conn3)
	})

	t.Run("ConcurrentHandoffs", func(t *testing.T) {
		// Create a base dialer that simulates slow handoffs
		baseDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
			time.Sleep(50 * time.Millisecond) // Simulate network delay
			return &mockNetConn{addr: addr}, nil
		}

		processor := maintnotifications.NewPoolHook(baseDialer, "tcp", nil, nil)
		defer processor.Shutdown(context.Background())

		// Create hooks manager and add processor as hook
		hookManager := pool.NewPoolHookManager()
		hookManager.AddHook(processor)

		testPool := pool.NewConnPool(&pool.Options{
			Dialer: func(ctx context.Context) (net.Conn, error) {
				return &mockNetConn{addr: "original:6379"}, nil
			},

			PoolSize:           int32(10),
			MaxConcurrentDials: 10,
			PoolTimeout:        time.Second,
		})
		defer testPool.Close()

		// Add the hook to the pool after creation
		testPool.AddPoolHook(processor)

		// Set the pool reference in the processor
		processor.SetPool(testPool)

		ctx := context.Background()
		var wg sync.WaitGroup

		// Start multiple concurrent handoffs
		for i := 0; i < 5; i++ {
			wg.Add(1)
			go func(id int) {
				defer wg.Done()

				// Get connection
				conn, err := testPool.Get(ctx)
				if err != nil {
					t.Errorf("Failed to get conn[%d]: %v", id, err)
					return
				}

				// Set initialization function
				initConnFunc := func(ctx context.Context, cn *pool.Conn) error {
					return nil
				}
				conn.SetInitConnFunc(initConnFunc)

				// Mark for handoff
				conn.MarkForHandoff("new-endpoint:6379", int64(id))

				// Return to pool (starts async handoff)
				testPool.Put(ctx, conn)
			}(i)
		}

		wg.Wait()

		// Wait for all handoffs to complete
		time.Sleep(300 * time.Millisecond)

		// Verify pool is still functional
		conn, err := testPool.Get(ctx)
		if err != nil {
			t.Fatalf("Pool should still be functional after concurrent handoffs: %v", err)
		}
		testPool.Put(ctx, conn)
	})

	t.Run("HandoffFailureRecovery", func(t *testing.T) {
		// Create a failing base dialer
		failingDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
			return nil, &net.OpError{Op: "dial", Err: &net.DNSError{Name: addr}}
		}

		processor := maintnotifications.NewPoolHook(failingDialer, "tcp", nil, nil)
		defer processor.Shutdown(context.Background())

		// Create hooks manager and add processor as hook
		hookManager := pool.NewPoolHookManager()
		hookManager.AddHook(processor)

		testPool := pool.NewConnPool(&pool.Options{
			Dialer: func(ctx context.Context) (net.Conn, error) {
				return &mockNetConn{addr: "original:6379"}, nil
			},

			PoolSize:           int32(3),
			MaxConcurrentDials: 3,
			PoolTimeout:        time.Second,
		})
		defer testPool.Close()

		// Add the hook to the pool after creation
		testPool.AddPoolHook(processor)

		// Set the pool reference in the processor
		processor.SetPool(testPool)

		ctx := context.Background()

		// Get connection and mark for handoff
		conn, err := testPool.Get(ctx)
		if err != nil {
			t.Fatalf("Failed to get connection: %v", err)
		}

		conn.MarkForHandoff("unreachable-endpoint:6379", 12345)

		// Return to pool (starts async handoff that will fail)
		testPool.Put(ctx, conn)

		// Wait for handoff to start processing
		time.Sleep(50 * time.Millisecond)

		// Connection should still be in pending map (waiting for retry after dial failure)
		if !processor.IsHandoffPending(conn) {
			t.Error("Connection should still be in pending map while waiting for retry")
		}

		// Wait for retry delay to pass and handoff to be re-queued
		time.Sleep(600 * time.Millisecond)

		// Connection should still be pending (retry was queued)
		if !processor.IsHandoffPending(conn) {
			t.Error("Connection should still be in pending map after retry was queued")
		}

		// Pool should still be functional
		conn2, err := testPool.Get(ctx)
		if err != nil {
			t.Fatalf("Pool should still be functional: %v", err)
		}

		// In event-driven approach, the original connection remains in pool
		// even after failed handoff (it's still a valid connection)
		// We might get the same connection or a different one
		testPool.Put(ctx, conn2)
	})

	t.Run("GracefulShutdown", func(t *testing.T) {
		// Create a slow base dialer
		slowDialer := func(ctx context.Context, network, addr string) (net.Conn, error) {
			time.Sleep(100 * time.Millisecond)
			return &mockNetConn{addr: addr}, nil
		}

		processor := maintnotifications.NewPoolHook(slowDialer, "tcp", nil, nil)
		defer processor.Shutdown(context.Background())

		// Create hooks manager and add processor as hook
		hookManager := pool.NewPoolHookManager()
		hookManager.AddHook(processor)

		testPool := pool.NewConnPool(&pool.Options{
			Dialer: func(ctx context.Context) (net.Conn, error) {
				return &mockNetConn{addr: "original:6379"}, nil
			},

			PoolSize:           int32(2),
			MaxConcurrentDials: 2,
			PoolTimeout:        time.Second,
		})
		defer testPool.Close()

		// Add the hook to the pool after creation
		testPool.AddPoolHook(processor)

		// Set the pool reference in the processor
		processor.SetPool(testPool)

		ctx := context.Background()

		// Start a handoff
		conn, err := testPool.Get(ctx)
		if err != nil {
			t.Fatalf("Failed to get connection: %v", err)
		}

		if err := conn.MarkForHandoff("new-endpoint:6379", 12345); err != nil {
			t.Fatalf("Failed to mark connection for handoff: %v", err)
		}

		// Set a mock initialization function with delay to ensure handoff is pending
		conn.SetInitConnFunc(func(ctx context.Context, cn *pool.Conn) error {
			time.Sleep(50 * time.Millisecond) // Add delay to keep handoff pending
			return nil
		})

		testPool.Put(ctx, conn)

		// Give the on-demand worker a moment to start and begin processing
		// The handoff should be pending because the slowDialer takes 100ms
		time.Sleep(10 * time.Millisecond)

		// Verify handoff was queued and is being processed
		if !processor.IsHandoffPending(conn) {
			t.Error("Handoff should be queued in pending map")
		}

		// Give the handoff a moment to start processing
		time.Sleep(50 * time.Millisecond)

		// Shutdown processor gracefully
		// Use a longer timeout to account for slow dialer (100ms) plus processing overhead
		shutdownCtx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
		defer cancel()

		err = processor.Shutdown(shutdownCtx)
		if err != nil {
			t.Errorf("Graceful shutdown should succeed: %v", err)
		}

		// Handoff should have completed (removed from pending map)
		if processor.IsHandoffPending(conn) {
			t.Error("Handoff should have completed and been removed from pending map after shutdown")
		}
	})
}

func init() {
	logging.Disable()
}


================================================
FILE: auth/auth.go
================================================
// Package auth package provides authentication-related interfaces and types.
// It also includes a basic implementation of credentials using username and password.
package auth

// StreamingCredentialsProvider is an interface that defines the methods for a streaming credentials provider.
// It is used to provide credentials for authentication.
// The CredentialsListener is used to receive updates when the credentials change.
type StreamingCredentialsProvider interface {
	// Subscribe subscribes to the credentials provider for updates.
	// It returns the current credentials, a cancel function to unsubscribe from the provider,
	// and an error if any.
	// TODO(ndyakov): Should we add context to the Subscribe method?
	Subscribe(listener CredentialsListener) (Credentials, UnsubscribeFunc, error)
}

// UnsubscribeFunc is a function that is used to cancel the subscription to the credentials provider.
// It is used to unsubscribe from the provider when the credentials are no longer needed.
type UnsubscribeFunc func() error

// CredentialsListener is an interface that defines the methods for a credentials listener.
// It is used to receive updates when the credentials change.
// The OnNext method is called when the credentials change.
// The OnError method is called when an error occurs while requesting the credentials.
type CredentialsListener interface {
	OnNext(credentials Credentials)
	OnError(err error)
}

// Credentials is an interface that defines the methods for credentials.
// It is used to provide the credentials for authentication.
type Credentials interface {
	// BasicAuth returns the username and password for basic authentication.
	BasicAuth() (username string, password string)
	// RawCredentials returns the raw credentials as a string.
	// This can be used to extract the username and password from the raw credentials or
	// additional information if present in the token.
	RawCredentials() string
}

type basicAuth struct {
	username string
	password string
}

// RawCredentials returns the raw credentials as a string.
func (b *basicAuth) RawCredentials() string {
	return b.username + ":" + b.password
}

// BasicAuth returns the username and password for basic authentication.
func (b *basicAuth) BasicAuth() (username string, password string) {
	return b.username, b.password
}

// NewBasicCredentials creates a new Credentials object from the given username and password.
func NewBasicCredentials(username, password string) Credentials {
	return &basicAuth{
		username: username,
		password: password,
	}
}


================================================
FILE: auth/auth_test.go
================================================
package auth

import (
	"errors"
	"strings"
	"sync"
	"testing"
	"time"
)

type mockStreamingProvider struct {
	credentials Credentials
	err         error
	updates     chan Credentials
}

func newMockStreamingProvider(initialCreds Credentials) *mockStreamingProvider {
	return &mockStreamingProvider{
		credentials: initialCreds,
		updates:     make(chan Credentials, 10),
	}
}

func (m *mockStreamingProvider) Subscribe(listener CredentialsListener) (Credentials, UnsubscribeFunc, error) {
	if m.err != nil {
		return nil, nil, m.err
	}

	// Send initial credentials
	listener.OnNext(m.credentials)

	// Start goroutine to handle updates
	go func() {
		for creds := range m.updates {
			listener.OnNext(creds)
		}
	}()

	return m.credentials, func() error {
		close(m.updates)
		return nil
	}, nil
}

func TestStreamingCredentialsProvider(t *testing.T) {
	t.Run("successful subscription", func(t *testing.T) {
		initialCreds := NewBasicCredentials("user1", "pass1")
		provider := newMockStreamingProvider(initialCreds)

		var receivedCreds []Credentials
		var receivedErrors []error
		var mu sync.Mutex

		listener := NewReAuthCredentialsListener(
			func(creds Credentials) error {
				mu.Lock()
				receivedCreds = append(receivedCreds, creds)
				mu.Unlock()
				return nil
			},
			func(err error) {
				receivedErrors = append(receivedErrors, err)
			},
		)

		creds, cancel, err := provider.Subscribe(listener)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if cancel == nil {
			t.Fatal("expected cancel function to be non-nil")
		}
		if creds != initialCreds {
			t.Fatalf("expected credentials %v, got %v", initialCreds, creds)
		}
		if len(receivedCreds) != 1 {
			t.Fatalf("expected 1 received credential, got %d", len(receivedCreds))
		}
		if receivedCreds[0] != initialCreds {
			t.Fatalf("expected received credential %v, got %v", initialCreds, receivedCreds[0])
		}
		if len(receivedErrors) != 0 {
			t.Fatalf("expected no errors, got %d", len(receivedErrors))
		}

		// Send an update
		newCreds := NewBasicCredentials("user2", "pass2")
		provider.updates <- newCreds

		// Wait for update to be processed
		time.Sleep(100 * time.Millisecond)
		mu.Lock()
		if len(receivedCreds) != 2 {
			t.Fatalf("expected 2 received credentials, got %d", len(receivedCreds))
		}
		if receivedCreds[1] != newCreds {
			t.Fatalf("expected received credential %v, got %v", newCreds, receivedCreds[1])
		}
		mu.Unlock()

		// Cancel subscription
		if err := cancel(); err != nil {
			t.Fatalf("unexpected error cancelling subscription: %v", err)
		}
	})

	t.Run("subscription error", func(t *testing.T) {
		provider := &mockStreamingProvider{
			err: errors.New("subscription failed"),
		}

		var receivedCreds []Credentials
		var receivedErrors []error

		listener := NewReAuthCredentialsListener(
			func(creds Credentials) error {
				receivedCreds = append(receivedCreds, creds)
				return nil
			},
			func(err error) {
				receivedErrors = append(receivedErrors, err)
			},
		)

		creds, cancel, err := provider.Subscribe(listener)
		if err == nil {
			t.Fatal("expected error, got nil")
		}
		if cancel != nil {
			t.Fatal("expected cancel function to be nil")
		}
		if creds != nil {
			t.Fatalf("expected nil credentials, got %v", creds)
		}
		if len(receivedCreds) != 0 {
			t.Fatalf("expected no received credentials, got %d", len(receivedCreds))
		}
		if len(receivedErrors) != 0 {
			t.Fatalf("expected no errors, got %d", len(receivedErrors))
		}
	})

	t.Run("re-auth error", func(t *testing.T) {
		initialCreds := NewBasicCredentials("user1", "pass1")
		provider := newMockStreamingProvider(initialCreds)

		reauthErr := errors.New("re-auth failed")
		var receivedErrors []error

		listener := NewReAuthCredentialsListener(
			func(creds Credentials) error {
				return reauthErr
			},
			func(err error) {
				receivedErrors = append(receivedErrors, err)
			},
		)

		creds, cancel, err := provider.Subscribe(listener)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if cancel == nil {
			t.Fatal("expected cancel function to be non-nil")
		}
		if creds != initialCreds {
			t.Fatalf("expected credentials %v, got %v", initialCreds, creds)
		}
		if len(receivedErrors) != 1 {
			t.Fatalf("expected 1 error, got %d", len(receivedErrors))
		}
		if receivedErrors[0] != reauthErr {
			t.Fatalf("expected error %v, got %v", reauthErr, receivedErrors[0])
		}

		if err := cancel(); err != nil {
			t.Fatalf("unexpected error cancelling subscription: %v", err)
		}
	})
}

func TestBasicCredentials(t *testing.T) {
	tests := []struct {
		name         string
		username     string
		password     string
		expectedUser string
		expectedPass string
		expectedRaw  string
	}{
		{
			name:         "basic auth",
			username:     "user1",
			password:     "pass1",
			expectedUser: "user1",
			expectedPass: "pass1",
			expectedRaw:  "user1:pass1",
		},
		{
			name:         "empty username",
			username:     "",
			password:     "pass1",
			expectedUser: "",
			expectedPass: "pass1",
			expectedRaw:  ":pass1",
		},
		{
			name:         "empty password",
			username:     "user1",
			password:     "",
			expectedUser: "user1",
			expectedPass: "",
			expectedRaw:  "user1:",
		},
		{
			name:         "both username and password empty",
			username:     "",
			password:     "",
			expectedUser: "",
			expectedPass: "",
			expectedRaw:  ":",
		},
		{
			name:         "special characters",
			username:     "user:1",
			password:     "pa:ss@!#",
			expectedUser: "user:1",
			expectedPass: "pa:ss@!#",
			expectedRaw:  "user:1:pa:ss@!#",
		},
		{
			name:         "unicode characters",
			username:     "ユーザー",
			password:     "密碼123",
			expectedUser: "ユーザー",
			expectedPass: "密碼123",
			expectedRaw:  "ユーザー:密碼123",
		},
		{
			name:         "long credentials",
			username:     strings.Repeat("u", 1000),
			password:     strings.Repeat("p", 1000),
			expectedUser: strings.Repeat("u", 1000),
			expectedPass: strings.Repeat("p", 1000),
			expectedRaw:  strings.Repeat("u", 1000) + ":" + strings.Repeat("p", 1000),
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			creds := NewBasicCredentials(tt.username, tt.password)

			user, pass := creds.BasicAuth()
			if user != tt.expectedUser {
				t.Errorf("BasicAuth() username = %q; want %q", user, tt.expectedUser)
			}
			if pass != tt.expectedPass {
				t.Errorf("BasicAuth() password = %q; want %q", pass, tt.expectedPass)
			}

			raw := creds.RawCredentials()
			if raw != tt.expectedRaw {
				t.Errorf("RawCredentials() = %q; want %q", raw, tt.expectedRaw)
			}
		})
	}
}

func TestReAuthCredentialsListener(t *testing.T) {
	t.Run("successful re-auth", func(t *testing.T) {
		var reAuthCalled bool
		var onErrCalled bool
		var receivedCreds Credentials

		listener := NewReAuthCredentialsListener(
			func(creds Credentials) error {
				reAuthCalled = true
				receivedCreds = creds
				return nil
			},
			func(err error) {
				onErrCalled = true
			},
		)

		creds := NewBasicCredentials("user1", "pass1")
		listener.OnNext(creds)

		if !reAuthCalled {
			t.Fatal("expected reAuth to be called")
		}
		if onErrCalled {
			t.Fatal("expected onErr not to be called")
		}
		if receivedCreds != creds {
			t.Fatalf("expected credentials %v, got %v", creds, receivedCreds)
		}
	})

	t.Run("re-auth error", func(t *testing.T) {
		var reAuthCalled bool
		var onErrCalled bool
		var receivedErr error
		expectedErr := errors.New("re-auth failed")

		listener := NewReAuthCredentialsListener(
			func(creds Credentials) error {
				reAuthCalled = true
				return expectedErr
			},
			func(err error) {
				onErrCalled = true
				receivedErr = err
			},
		)

		creds := NewBasicCredentials("user1", "pass1")
		listener.OnNext(creds)

		if !reAuthCalled {
			t.Fatal("expected reAuth to be called")
		}
		if !onErrCalled {
			t.Fatal("expected onErr to be called")
		}
		if receivedErr != expectedErr {
			t.Fatalf("expected error %v, got %v", expectedErr, receivedErr)
		}
	})

	t.Run("on error", func(t *testing.T) {
		var onErrCalled bool
		var receivedErr error
		expectedErr := errors.New("provider error")

		listener := NewReAuthCredentialsListener(
			func(creds Credentials) error {
				return nil
			},
			func(err error) {
				onErrCalled = true
				receivedErr = err
			},
		)

		listener.OnError(expectedErr)

		if !onErrCalled {
			t.Fatal("expected onErr to be called")
		}
		if receivedErr != expectedErr {
			t.Fatalf("expected error %v, got %v", expectedErr, receivedErr)
		}
	})

	t.Run("nil callbacks", func(t *testing.T) {
		listener := NewReAuthCredentialsListener(nil, nil)

		// Should not panic
		listener.OnNext(NewBasicCredentials("user1", "pass1"))
		listener.OnError(errors.New("test error"))
	})
}


================================================
FILE: auth/reauth_credentials_listener.go
================================================
package auth

// ReAuthCredentialsListener is a struct that implements the CredentialsListener interface.
// It is used to re-authenticate the credentials when they are updated.
// It contains:
// - reAuth: a function that takes the new credentials and returns an error if any.
// - onErr: a function that takes an error and handles it.
type ReAuthCredentialsListener struct {
	reAuth func(credentials Credentials) error
	onErr  func(err error)
}

// OnNext is called when the credentials are updated.
// It calls the reAuth function with the new credentials.
// If the reAuth function returns an error, it calls the onErr function with the error.
func (c *ReAuthCredentialsListener) OnNext(credentials Credentials) {
	if c.reAuth == nil {
		return
	}

	err := c.reAuth(credentials)
	if err != nil {
		c.OnError(err)
	}
}

// OnError is called when an error occurs.
// It can be called from both the credentials provider and the reAuth function.
func (c *ReAuthCredentialsListener) OnError(err error) {
	if c.onErr == nil {
		return
	}

	c.onErr(err)
}

// NewReAuthCredentialsListener creates a new ReAuthCredentialsListener.
// Implements the auth.CredentialsListener interface.
func NewReAuthCredentialsListener(reAuth func(credentials Credentials) error, onErr func(err error)) *ReAuthCredentialsListener {
	return &ReAuthCredentialsListener{
		reAuth: reAuth,
		onErr:  onErr,
	}
}

// Ensure ReAuthCredentialsListener implements the CredentialsListener interface.
var _ CredentialsListener = (*ReAuthCredentialsListener)(nil)


================================================
FILE: bench_test.go
================================================
package redis_test

import (
	"bytes"
	"context"
	"fmt"
	"strconv"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/redis/go-redis/v9"
)

func benchmarkRedisClient(ctx context.Context, poolSize int) *redis.Client {
	client := redis.NewClient(&redis.Options{
		Addr:         ":6379",
		DialTimeout:  time.Second,
		ReadTimeout:  time.Second,
		WriteTimeout: time.Second,
		PoolSize:     poolSize,
	})
	if err := client.FlushDB(ctx).Err(); err != nil {
		panic(err)
	}
	return client
}

func BenchmarkRedisPing(b *testing.B) {
	ctx := context.Background()
	rdb := benchmarkRedisClient(ctx, 10)
	defer rdb.Close()

	b.ResetTimer()

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			if err := rdb.Ping(ctx).Err(); err != nil {
				b.Fatal(err)
			}
		}
	})
}

func BenchmarkSetGoroutines(b *testing.B) {
	ctx := context.Background()
	rdb := benchmarkRedisClient(ctx, 10)
	defer rdb.Close()

	for i := 0; i < b.N; i++ {
		var wg sync.WaitGroup

		for i := 0; i < 1000; i++ {
			wg.Add(1)
			go func() {
				defer wg.Done()

				err := rdb.Set(ctx, "hello", "world", 0).Err()
				if err != nil {
					panic(err)
				}
			}()
		}

		wg.Wait()
	}
}

func BenchmarkRedisGetNil(b *testing.B) {
	ctx := context.Background()
	client := benchmarkRedisClient(ctx, 10)
	defer client.Close()

	b.ResetTimer()

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			if err := client.Get(ctx, "key").Err(); err != redis.Nil {
				b.Fatal(err)
			}
		}
	})
}

type setStringBenchmark struct {
	poolSize  int
	valueSize int
}

func (bm setStringBenchmark) String() string {
	return fmt.Sprintf("pool=%d value=%d", bm.poolSize, bm.valueSize)
}

func BenchmarkRedisSetString(b *testing.B) {
	benchmarks := []setStringBenchmark{
		{10, 64},
		{10, 1024},
		{10, 64 * 1024},
		{10, 1024 * 1024},
		{10, 10 * 1024 * 1024},

		{100, 64},
		{100, 1024},
		{100, 64 * 1024},
		{100, 1024 * 1024},
		{100, 10 * 1024 * 1024},
	}
	for _, bm := range benchmarks {
		b.Run(bm.String(), func(b *testing.B) {
			ctx := context.Background()
			client := benchmarkRedisClient(ctx, bm.poolSize)
			defer client.Close()

			value := strings.Repeat("1", bm.valueSize)

			b.ResetTimer()

			b.RunParallel(func(pb *testing.PB) {
				for pb.Next() {
					err := client.Set(ctx, "key", value, 0).Err()
					if err != nil {
						b.Fatal(err)
					}
				}
			})
		})
	}
}

func BenchmarkRedisSetGetBytes(b *testing.B) {
	ctx := context.Background()
	client := benchmarkRedisClient(ctx, 10)
	defer client.Close()

	value := bytes.Repeat([]byte{'1'}, 10000)

	b.ResetTimer()

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			if err := client.Set(ctx, "key", value, 0).Err(); err != nil {
				b.Fatal(err)
			}

			got, err := client.Get(ctx, "key").Bytes()
			if err != nil {
				b.Fatal(err)
			}
			if !bytes.Equal(got, value) {
				b.Fatalf("got != value")
			}
		}
	})
}

func BenchmarkRedisMGet(b *testing.B) {
	ctx := context.Background()
	client := benchmarkRedisClient(ctx, 10)
	defer client.Close()

	if err := client.MSet(ctx, "key1", "hello1", "key2", "hello2").Err(); err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			if err := client.MGet(ctx, "key1", "key2").Err(); err != nil {
				b.Fatal(err)
			}
		}
	})
}

func BenchmarkSetExpire(b *testing.B) {
	ctx := context.Background()
	client := benchmarkRedisClient(ctx, 10)
	defer client.Close()

	b.ResetTimer()

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			if err := client.Set(ctx, "key", "hello", 0).Err(); err != nil {
				b.Fatal(err)
			}
			if err := client.Expire(ctx, "key", time.Second).Err(); err != nil {
				b.Fatal(err)
			}
		}
	})
}

func BenchmarkPipeline(b *testing.B) {
	ctx := context.Background()
	client := benchmarkRedisClient(ctx, 10)
	defer client.Close()

	b.ResetTimer()

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			_, err := client.Pipelined(ctx, func(pipe redis.Pipeliner) error {
				pipe.Set(ctx, "key", "hello", 0)
				pipe.Expire(ctx, "key", time.Second)
				return nil
			})
			if err != nil {
				b.Fatal(err)
			}
		}
	})
}

func BenchmarkZAdd(b *testing.B) {
	ctx := context.Background()
	client := benchmarkRedisClient(ctx, 10)
	defer client.Close()

	b.ResetTimer()

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			err := client.ZAdd(ctx, "key", redis.Z{
				Score:  float64(1),
				Member: "hello",
			}).Err()
			if err != nil {
				b.Fatal(err)
			}
		}
	})
}

func BenchmarkXRead(b *testing.B) {
	ctx := context.Background()
	client := benchmarkRedisClient(ctx, 10)
	defer client.Close()

	args := redis.XAddArgs{
		Stream: "1",
		ID:     "*",
		Values: map[string]string{"uno": "dos"},
	}

	lenStreams := 16
	streams := make([]string, 0, lenStreams)
	for i := 0; i < lenStreams; i++ {
		streams = append(streams, strconv.Itoa(i))
	}
	for i := 0; i < lenStreams; i++ {
		streams = append(streams, "0")
	}

	b.ReportAllocs()
	b.ResetTimer()

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			client.XAdd(ctx, &args)

			err := client.XRead(ctx, &redis.XReadArgs{
				Streams: streams,
				Count:   1,
				Block:   time.Second,
			}).Err()
			if err != nil {
				b.Fatal(err)
			}
		}
	})
}

//------------------------------------------------------------------------------

func newClusterScenario() *clusterScenario {
	return &clusterScenario{
		ports:   []string{"16600", "16601", "16602", "16603", "16604", "16605"},
		nodeIDs: make([]string, 6),
		clients: make(map[string]*redis.Client, 6),
	}
}

var clusterBench *clusterScenario

func BenchmarkClusterPing(b *testing.B) {
	if testing.Short() {
		b.Skip("skipping in short mode")
	}

	ctx := context.Background()
	if clusterBench == nil {
		clusterBench = newClusterScenario()
		if err := configureClusterTopology(ctx, clusterBench); err != nil {
			b.Fatal(err)
		}
	}

	client := clusterBench.newClusterClient(ctx, redisClusterOptions())
	defer client.Close()

	b.Run("cluster ping", func(b *testing.B) {
		b.ResetTimer()

		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				err := client.Ping(ctx).Err()
				if err != nil {
					b.Fatal(err)
				}
			}
		})
	})
}

func BenchmarkClusterDoInt(b *testing.B) {
	if testing.Short() {
		b.Skip("skipping in short mode")
	}

	ctx := context.Background()
	if clusterBench == nil {
		clusterBench = newClusterScenario()
		if err := configureClusterTopology(ctx, clusterBench); err != nil {
			b.Fatal(err)
		}
	}

	client := clusterBench.newClusterClient(ctx, redisClusterOptions())
	defer client.Close()

	b.Run("cluster do set int", func(b *testing.B) {
		b.ResetTimer()
		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				err := client.Do(ctx, "SET", 10, 10).Err()
				if err != nil {
					b.Fatal(err)
				}
			}
		})
	})
}

func BenchmarkClusterSetString(b *testing.B) {
	if testing.Short() {
		b.Skip("skipping in short mode")
	}

	ctx := context.Background()
	if clusterBench == nil {
		clusterBench = newClusterScenario()
		if err := configureClusterTopology(ctx, clusterBench); err != nil {
			b.Fatal(err)
		}
	}

	client := clusterBench.newClusterClient(ctx, redisClusterOptions())
	defer client.Close()

	value := string(bytes.Repeat([]byte{'1'}, 10000))

	b.Run("cluster set string", func(b *testing.B) {
		b.ResetTimer()

		b.RunParallel(func(pb *testing.PB) {
			for pb.Next() {
				err := client.Set(ctx, "key", value, 0).Err()
				if err != nil {
					b.Fatal(err)
				}
			}
		})
	})
}

func BenchmarkExecRingSetAddrsCmd(b *testing.B) {
	const (
		ringShard1Name = "ringShardOne"
		ringShard2Name = "ringShardTwo"
	)

	ring := redis.NewRing(&redis.RingOptions{
		Addrs: map[string]string{
			"ringShardOne": ":" + ringShard1Port,
		},
		NewClient: func(opt *redis.Options) *redis.Client {
			// Simulate slow shard creation
			time.Sleep(100 * time.Millisecond)
			return redis.NewClient(opt)
		},
	})
	defer ring.Close()

	if _, err := ring.Ping(context.Background()).Result(); err != nil {
		b.Fatal(err)
	}

	// Continuously update addresses by adding and removing one address
	updatesDone := make(chan struct{})
	defer func() { close(updatesDone) }()
	go func() {
		ticker := time.NewTicker(10 * time.Millisecond)
		defer ticker.Stop()
		for i := 0; ; i++ {
			select {
			case <-ticker.C:
				if i%2 == 0 {
					ring.SetAddrs(map[string]string{
						ringShard1Name: ":" + ringShard1Port,
					})
				} else {
					ring.SetAddrs(map[string]string{
						ringShard1Name: ":" + ringShard1Port,
						ringShard2Name: ":" + ringShard2Port,
					})
				}
			case <-updatesDone:
				return
			}
		}
	}()

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if _, err := ring.Ping(context.Background()).Result(); err != nil {
			if err == redis.ErrClosed {
				// The shard client could be closed while ping command is in progress
				continue
			} else {
				b.Fatal(err)
			}
		}
	}
}


================================================
FILE: bitmap_commands.go
================================================
package redis

import (
	"context"
	"errors"
)

type BitMapCmdable interface {
	GetBit(ctx context.Context, key string, offset int64) *IntCmd
	SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd
	BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd
	BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd
	BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd
	BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd
	BitOpDiff(ctx context.Context, destKey string, keys ...string) *IntCmd
	BitOpDiff1(ctx context.Context, destKey string, keys ...string) *IntCmd
	BitOpAndOr(ctx context.Context, destKey string, keys ...string) *IntCmd
	BitOpOne(ctx context.Context, destKey string, keys ...string) *IntCmd
	BitOpNot(ctx context.Context, destKey string, key string) *IntCmd
	BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd
	BitPosSpan(ctx context.Context, key string, bit int8, start, end int64, span string) *IntCmd
	BitField(ctx context.Context, key string, values ...interface{}) *IntSliceCmd
	BitFieldRO(ctx context.Context, key string, values ...interface{}) *IntSliceCmd
}

func (c cmdable) GetBit(ctx context.Context, key string, offset int64) *IntCmd {
	cmd := NewIntCmd(ctx, "getbit", key, offset)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd {
	cmd := NewIntCmd(
		ctx,
		"setbit",
		key,
		offset,
		value,
	)
	_ = c(ctx, cmd)
	return cmd
}

type BitCount struct {
	Start, End int64
	Unit       string // BYTE(default) | BIT
}

const BitCountIndexByte string = "BYTE"
const BitCountIndexBit string = "BIT"

func (c cmdable) BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd {
	args := make([]any, 2, 5)
	args[0] = "bitcount"
	args[1] = key
	if bitCount != nil {
		args = append(args, bitCount.Start, bitCount.End)
		if bitCount.Unit != "" {
			if bitCount.Unit != BitCountIndexByte && bitCount.Unit != BitCountIndexBit {
				cmd := NewIntCmd(ctx)
				cmd.SetErr(errors.New("redis: invalid bitcount index"))
				return cmd
			}
			args = append(args, bitCount.Unit)
		}
	}
	cmd := NewIntCmd(ctx, args...)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) bitOp(ctx context.Context, op, destKey string, keys ...string) *IntCmd {
	args := make([]interface{}, 3+len(keys))
	args[0] = "bitop"
	args[1] = op
	args[2] = destKey
	for i, key := range keys {
		args[3+i] = key
	}
	cmd := NewIntCmd(ctx, args...)
	_ = c(ctx, cmd)
	return cmd
}

// BitOpAnd creates a new bitmap in which users are members of all given bitmaps
func (c cmdable) BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd {
	return c.bitOp(ctx, "and", destKey, keys...)
}

// BitOpOr creates a new bitmap in which users are member of at least one given bitmap
func (c cmdable) BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
	return c.bitOp(ctx, "or", destKey, keys...)
}

// BitOpXor creates a new bitmap in which users are the result of XORing all given bitmaps
func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd {
	return c.bitOp(ctx, "xor", destKey, keys...)
}

// BitOpNot creates a new bitmap in which users are not members of a given bitmap
func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntCmd {
	return c.bitOp(ctx, "not", destKey, key)
}

// BitOpDiff creates a new bitmap in which users are members of bitmap X but not of any of bitmaps Y1, Y2, …
// Introduced with Redis 8.2
func (c cmdable) BitOpDiff(ctx context.Context, destKey string, keys ...string) *IntCmd {
	return c.bitOp(ctx, "diff", destKey, keys...)
}

// BitOpDiff1 creates a new bitmap in which users are members of one or more of bitmaps Y1, Y2, … but not members of bitmap X
// Introduced with Redis 8.2
func (c cmdable) BitOpDiff1(ctx context.Context, destKey string, keys ...string) *IntCmd {
	return c.bitOp(ctx, "diff1", destKey, keys...)
}

// BitOpAndOr creates a new bitmap in which users are members of bitmap X and also members of one or more of bitmaps Y1, Y2, …
// Introduced with Redis 8.2
func (c cmdable) BitOpAndOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
	return c.bitOp(ctx, "andor", destKey, keys...)
}

// BitOpOne creates a new bitmap in which users are members of exactly one of the given bitmaps
// Introduced with Redis 8.2
func (c cmdable) BitOpOne(ctx context.Context, destKey string, keys ...string) *IntCmd {
	return c.bitOp(ctx, "one", destKey, keys...)
}

// BitPos is an API before Redis version 7.0, cmd: bitpos key bit start end
// if you need the `byte | bit` parameter, please use `BitPosSpan`.
func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd {
	args := make([]interface{}, 3+len(pos))
	args[0] = "bitpos"
	args[1] = key
	args[2] = bit
	switch len(pos) {
	case 0:
	case 1:
		args[3] = pos[0]
	case 2:
		args[3] = pos[0]
		args[4] = pos[1]
	default:
		cmd := NewIntCmd(ctx)
		cmd.SetErr(errors.New("too many arguments"))
		return cmd
	}
	cmd := NewIntCmd(ctx, args...)
	_ = c(ctx, cmd)
	return cmd
}

// BitPosSpan supports the `byte | bit` parameters in redis version 7.0,
// the bitpos command defaults to using byte type for the `start-end` range,
// which means it counts in bytes from start to end. you can set the value
// of "span" to determine the type of `start-end`.
// span = "bit", cmd: bitpos key bit start end bit
// span = "byte", cmd: bitpos key bit start end byte
func (c cmdable) BitPosSpan(ctx context.Context, key string, bit int8, start, end int64, span string) *IntCmd {
	cmd := NewIntCmd(ctx, "bitpos", key, bit, start, end, span)
	_ = c(ctx, cmd)
	return cmd
}

// BitField accepts multiple values:
//   - BitField("set", "i1", "offset1", "value1","cmd2", "type2", "offset2", "value2")
//   - BitField([]string{"cmd1", "type1", "offset1", "value1","cmd2", "type2", "offset2", "value2"})
//   - BitField([]interface{}{"cmd1", "type1", "offset1", "value1","cmd2", "type2", "offset2", "value2"})
func (c cmdable) BitField(ctx context.Context, key string, values ...interface{}) *IntSliceCmd {
	args := make([]interface{}, 2, 2+len(values))
	args[0] = "bitfield"
	args[1] = key
	args = appendArgs(args, values)
	cmd := NewIntSliceCmd(ctx, args...)
	_ = c(ctx, cmd)
	return cmd
}

// BitFieldRO - Read-only variant of the BITFIELD command.
// It is like the original BITFIELD but only accepts GET subcommand and can safely be used in read-only replicas.
// - BitFieldRO(ctx, key, "<Encoding0>", "<Offset0>", "<Encoding1>","<Offset1>")
func (c cmdable) BitFieldRO(ctx context.Context, key string, values ...interface{}) *IntSliceCmd {
	args := make([]interface{}, 2, 2+len(values))
	args[0] = "BITFIELD_RO"
	args[1] = key
	if len(values)%2 != 0 {
		c := NewIntSliceCmd(ctx)
		c.SetErr(errors.New("BitFieldRO: invalid number of arguments, must be even"))
		return c
	}
	for i := 0; i < len(values); i += 2 {
		args = append(args, "GET", values[i], values[i+1])
	}
	cmd := NewIntSliceCmd(ctx, args...)
	_ = c(ctx, cmd)
	return cmd
}


================================================
FILE: bitmap_commands_test.go
================================================
package redis_test

import (
	. "github.com/bsm/ginkgo/v2"
	. "github.com/bsm/gomega"
	"github.com/redis/go-redis/v9"
)

type bitCountExpected struct {
	Start    int64
	End      int64
	Expected int64
}

var _ = Describe("BitCountBite", func() {
	var client *redis.Client
	key := "bit_count_test"

	BeforeEach(func() {
		client = redis.NewClient(redisOptions())
		Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
		values := []int{0, 1, 0, 0, 1, 0, 1, 0, 1, 1}
		for i, v := range values {
			cmd := client.SetBit(ctx, key, int64(i), v)
			Expect(cmd.Err()).NotTo(HaveOccurred())
		}
	})

	AfterEach(func() {
		Expect(client.Close()).NotTo(HaveOccurred())
	})

	It("bit count bite", func() {
		var expected = []bitCountExpected{
			{0, 0, 0},
			{0, 1, 1},
			{0, 2, 1},
			{0, 3, 1},
			{0, 4, 2},
			{0, 5, 2},
			{0, 6, 3},
			{0, 7, 3},
			{0, 8, 4},
			{0, 9, 5},
		}

		for _, e := range expected {
			cmd := client.BitCount(ctx, key, &redis.BitCount{Start: e.Start, End: e.End, Unit: redis.BitCountIndexBit})
			Expect(cmd.Err()).NotTo(HaveOccurred())
			Expect(cmd.Val()).To(Equal(e.Expected))
		}
	})
})

var _ = Describe("BitCountByte", func() {
	var client *redis.Client
	key := "bit_count_test"

	BeforeEach(func() {
		client = redis.NewClient(redisOptions())
		Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
		values := []int{0, 0, 0, 0, 0, 0, 0, 1, 1, 1}
		for i, v := range values {
			cmd := client.SetBit(ctx, key, int64(i), v)
			Expect(cmd.Err()).NotTo(HaveOccurred())
		}
	})

	AfterEach(func() {
		Expect(client.Close()).NotTo(HaveOccurred())
	})

	It("bit count byte", func() {
		var expected = []bitCountExpected{
			{0, 0, 1},
			{0, 1, 3},
		}

		for _, e := range expected {
			cmd := client.BitCount(ctx, key, &redis.BitCount{Start: e.Start, End: e.End, Unit: redis.BitCountIndexByte})
			Expect(cmd.Err()).NotTo(HaveOccurred())
			Expect(cmd.Val()).To(Equal(e.Expected))
		}
	})

	It("bit count byte with no unit specified", func() {
		var expected = []bitCountExpected{
			{0, 0, 1},
			{0, 1, 3},
		}

		for _, e := range expected {
			cmd := client.BitCount(ctx, key, &redis.BitCount{Start: e.Start, End: e.End})
			Expect(cmd.Err()).NotTo(HaveOccurred())
			Expect(cmd.Val()).To(Equal(e.Expected))
		}
	})
})


================================================
FILE: cluster_commands.go
================================================
package redis

import "context"

type ClusterCmdable interface {
	ClusterMyShardID(ctx context.Context) *StringCmd
	ClusterMyID(ctx context.Context) *StringCmd
	ClusterSlots(ctx context.Context) *ClusterSlotsCmd
	ClusterShards(ctx context.Context) *ClusterShardsCmd
	ClusterLinks(ctx context.Context) *ClusterLinksCmd
	ClusterNodes(ctx context.Context) *StringCmd
	ClusterMeet(ctx context.Context, host, port string) *StatusCmd
	ClusterForget(ctx context.Context, nodeID string) *StatusCmd
	ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd
	ClusterResetSoft(ctx context.Context) *StatusCmd
	ClusterResetHard(ctx context.Context) *StatusCmd
	ClusterInfo(ctx context.Context) *StringCmd
	ClusterKeySlot(ctx context.Context, key string) *IntCmd
	ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd
	ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd
	ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd
	ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd
	ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd
	ClusterSaveConfig(ctx context.Context) *StatusCmd
	ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd
	ClusterFailover(ctx context.Context) *StatusCmd
	ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd
	ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd
	ReadOnly(ctx context.Context) *StatusCmd
	ReadWrite(ctx context.Context) *StatusCmd
}

func (c cmdable) ClusterMyShardID(ctx context.Context) *StringCmd {
	cmd := NewStringCmd(ctx, "cluster", "myshardid")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterMyID(ctx context.Context) *StringCmd {
	cmd := NewStringCmd(ctx, "cluster", "myid")
	_ = c(ctx, cmd)
	return cmd
}

// ClusterSlots returns the mapping of cluster slots to nodes.
//
// Deprecated: Use ClusterShards instead as of Redis 7.0.0.
func (c cmdable) ClusterSlots(ctx context.Context) *ClusterSlotsCmd {
	cmd := NewClusterSlotsCmd(ctx, "cluster", "slots")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterShards(ctx context.Context) *ClusterShardsCmd {
	cmd := NewClusterShardsCmd(ctx, "cluster", "shards")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterLinks(ctx context.Context) *ClusterLinksCmd {
	cmd := NewClusterLinksCmd(ctx, "cluster", "links")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterNodes(ctx context.Context) *StringCmd {
	cmd := NewStringCmd(ctx, "cluster", "nodes")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterMeet(ctx context.Context, host, port string) *StatusCmd {
	cmd := NewStatusCmd(ctx, "cluster", "meet", host, port)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterForget(ctx context.Context, nodeID string) *StatusCmd {
	cmd := NewStatusCmd(ctx, "cluster", "forget", nodeID)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd {
	cmd := NewStatusCmd(ctx, "cluster", "replicate", nodeID)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterResetSoft(ctx context.Context) *StatusCmd {
	cmd := NewStatusCmd(ctx, "cluster", "reset", "soft")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterResetHard(ctx context.Context) *StatusCmd {
	cmd := NewStatusCmd(ctx, "cluster", "reset", "hard")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterInfo(ctx context.Context) *StringCmd {
	cmd := NewStringCmd(ctx, "cluster", "info")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterKeySlot(ctx context.Context, key string) *IntCmd {
	cmd := NewIntCmd(ctx, "cluster", "keyslot", key)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd {
	cmd := NewStringSliceCmd(ctx, "cluster", "getkeysinslot", slot, count)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd {
	cmd := NewIntCmd(ctx, "cluster", "count-failure-reports", nodeID)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd {
	cmd := NewIntCmd(ctx, "cluster", "countkeysinslot", slot)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd {
	args := make([]interface{}, 2+len(slots))
	args[0] = "cluster"
	args[1] = "delslots"
	for i, slot := range slots {
		args[2+i] = slot
	}
	cmd := NewStatusCmd(ctx, args...)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd {
	size := max - min + 1
	slots := make([]int, size)
	for i := 0; i < size; i++ {
		slots[i] = min + i
	}
	return c.ClusterDelSlots(ctx, slots...)
}

func (c cmdable) ClusterSaveConfig(ctx context.Context) *StatusCmd {
	cmd := NewStatusCmd(ctx, "cluster", "saveconfig")
	_ = c(ctx, cmd)
	return cmd
}

// ClusterSlaves lists the replica nodes of a master node.
//
// Deprecated: Use ClusterReplicas instead as of Redis 5.0.0.
func (c cmdable) ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd {
	cmd := NewStringSliceCmd(ctx, "cluster", "slaves", nodeID)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterFailover(ctx context.Context) *StatusCmd {
	cmd := NewStatusCmd(ctx, "cluster", "failover")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd {
	args := make([]interface{}, 2+len(slots))
	args[0] = "cluster"
	args[1] = "addslots"
	for i, num := range slots {
		args[2+i] = num
	}
	cmd := NewStatusCmd(ctx, args...)
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd {
	size := max - min + 1
	slots := make([]int, size)
	for i := 0; i < size; i++ {
		slots[i] = min + i
	}
	return c.ClusterAddSlots(ctx, slots...)
}

func (c cmdable) ReadOnly(ctx context.Context) *StatusCmd {
	cmd := NewStatusCmd(ctx, "readonly")
	_ = c(ctx, cmd)
	return cmd
}

func (c cmdable) ReadWrite(ctx context.Context) *StatusCmd {
	cmd := NewStatusCmd(ctx, "readwrite")
	_ = c(ctx, cmd)
	return cmd
}


================================================
FILE: command.go
================================================
package redis

import (
	"bufio"
	"context"
	"fmt"
	"maps"
	"net"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/redis/go-redis/v9/internal"
	"github.com/redis/go-redis/v9/internal/hscan"
	"github.com/redis/go-redis/v9/internal/proto"
	"github.com/redis/go-redis/v9/internal/routing"
	"github.com/redis/go-redis/v9/internal/util"
)

// keylessCommands contains Redis commands that have empty key specifications (9th slot empty)
// Only includes core Redis commands, excludes FT.*, ts.*, timeseries.*, search.* and subcommands
var keylessCommands = map[string]struct{}{
	"acl":          {},
	"asking":       {},
	"auth":         {},
	"bgrewriteaof": {},
	"bgsave":       {},
	"client":       {},
	"cluster":      {},
	"config":       {},
	"debug":        {},
	"discard":      {},
	"echo":         {},
	"exec":         {},
	"failover":     {},
	"function":     {},
	"hello":        {},
	"hotkeys":      {},
	"latency":      {},
	"lolwut":       {},
	"module":       {},
	"monitor":      {},
	"multi":        {},
	"pfselftest":   {},
	"ping":         {},
	"psubscribe":   {},
	"psync":        {},
	"publish":      {},
	"pubsub":       {},
	"punsubscribe": {},
	"quit":         {},
	"readonly":     {},
	"readwrite":    {},
	"replconf":     {},
	"replicaof":    {},
	"role":         {},
	"save":         {},
	"script":       {},
	"select":       {},
	"shutdown":     {},
	"slaveof":      {},
	"slowlog":      {},
	"subscribe":    {},
	"swapdb":       {},
	"sync":         {},
	"time":         {},
	"unsubscribe":  {},
	"unwatch":      {},
	"wait":         {},
}

// CmdTyper interface for getting command type
type CmdTyper interface {
	GetCmdType() CmdType
}

// CmdTypeGetter interface for getting command type without circular imports
type CmdTypeGetter interface {
	GetCmdType() CmdType
}

type CmdType uint8

const (
	CmdTypeGeneric CmdType = iota
	CmdTypeString
	CmdTypeInt
	CmdTypeBool
	CmdTypeFloat
	CmdTypeStringSlice
	CmdTypeIntSlice
	CmdTypeFloatSlice
	CmdTypeBoolSlice
	CmdTypeMapStringString
	CmdTypeMapStringInt
	CmdTypeMapStringInterface
	CmdTypeMapStringInterfaceSlice
	CmdTypeSlice
	CmdTypeStatus
	CmdTypeDuration
	CmdTypeTime
	CmdTypeKeyValueSlice
	CmdTypeStringStructMap
	CmdTypeXMessageSlice
	CmdTypeXStreamSlice
	CmdTypeXPending
	CmdTypeXPendingExt
	CmdTypeXAutoClaim
	CmdTypeXAutoClaimJustID
	CmdTypeXInfoConsumers
	CmdTypeXInfoGroups
	CmdTypeXInfoStream
	CmdTypeXInfoStreamFull
	CmdTypeZSlice
	CmdTypeZWithKey
	CmdTypeScan
	CmdTypeClusterSlots
	CmdTypeGeoLocation
	CmdTypeGeoSearchLocation
	CmdTypeGeoPos
	CmdTypeCommandsInfo
	CmdTypeSlowLog
	CmdTypeMapStringStringSlice
	CmdTypeMapMapStringInterface
	CmdTypeKeyValues
	CmdTypeZSliceWithKey
	CmdTypeFunctionList
	CmdTypeFunctionStats
	CmdTypeLCS
	CmdTypeKeyFlags
	CmdTypeClusterLinks
	CmdTypeClusterShards
	CmdTypeRankWithScore
	CmdTypeClientInfo
	CmdTypeACLLog
	CmdTypeInfo
	CmdTypeMonitor
	CmdTypeJSON
	CmdTypeJSONSlice
	CmdTypeIntPointerSlice
	CmdTypeScanDump
	CmdTypeBFInfo
	CmdTypeCFInfo
	CmdTypeCMSInfo
	CmdTypeTopKInfo
	CmdTypeTDigestInfo
	CmdTypeFTSynDump
	CmdTypeAggregate
	CmdTypeFTInfo
	CmdTypeFTSpellCheck
	CmdTypeFTSearch
	CmdTypeTSTimestampValue
	CmdTypeTSTimestampValueSlice
	CmdTypeHotKeys
)

type (
	CmdTypeXAutoClaimValue struct {
		messages []XMessage
		start    string
	}

	CmdTypeXAutoClaimJustIDValue struct {
		ids   []string
		start string
	}

	CmdTypeScanValue struct {
		keys   []string
		cursor uint64
	}

	CmdTypeKeyValuesValue struct {
		key    string
		values []string
	}

	CmdTypeZSliceWithKeyValue struct {
		key    string
		zSlice []Z
	}
)

type Cmder interface {
	// command name.
	// e.g. "set k v ex 10" -> "set", "cluster info" -> "cluster".
	Name() string

	// full command name.
	// e.g. "set k v ex 10" -> "set", "cluster info" -> "cluster info".
	FullName() string

	// all args of the command.
	// e.g. "set k v ex 10" -> "[set k v ex 10]".
	Args() []interface{}

	// format request and response string.
	// e.g. "set k v ex 10" -> "set k v ex 10: OK", "get k" -> "get k: v".
	String() string

	// Clone creates a copy of the command.
	Clone() Cmder

	stringArg(int) string
	firstKeyPos() int8
	SetFirstKeyPos(int8)
	stepCount() int8
	SetStepCount(int8)

	readTimeout() *time.Duration
	readReply(rd *proto.Reader) error
	readRawReply(rd *proto.Reader) error
	SetErr(error)
	Err() error

	// GetCmdType returns the command type for fast value extraction
	GetCmdType() CmdType
}

func setCmdsErr(cmds []Cmder, e error) {
	for _, cmd := range cmds {
		if cmd.Err() == nil {
			cmd.SetErr(e)
		}
	}
}

func cmdsFirstErr(cmds []Cmder) error {
	for _, cmd := range cmds {
		if err := cmd.Err(); err != nil {
			return err
		}
	}
	return nil
}

func writeCmds(wr *proto.Writer, cmds []Cmder) error {
	for _, cmd := range cmds {
		if err := writeCmd(wr, cmd); err != nil {
			return err
		}
	}
	return nil
}

func writeCmd(wr *proto.Writer, cmd Cmder) error {
	return wr.WriteArgs(cmd.Args())
}

// cmdFirstKeyPos returns the position of the first key in the command's arguments.
// If the command does not have a key, it returns 0.
// TODO: Use the data in CommandInfo to determine the first key position.
func cmdFirstKeyPos(cmd Cmder) int {
	if pos := cmd.firstKeyPos(); pos != 0 {
		return int(pos)
	}

	name := cmd.Name()

	// first check if the command is keyless
	if _, ok := keylessCommands[name]; ok {
		return 0
	}

	switch name {
	case "eval", "evalsha", "eval_ro", "evalsha_ro":
		if cmd.stringArg(2) != "0" {
			return 3
		}

		return 0
	case "publish":
		return 1
	case "memory":
		// https://github.com/redis/redis/issues/7493
		if cmd.stringArg(1) == "usage" {
			return 2
		}
	}
	return 1
}

func cmdString(cmd Cmder, val interface{}) string {
	b := make([]byte, 0, 64)

	for i, arg := range cmd.Args() {
		if i > 0 {
			b = append(b, ' ')
		}
		b = internal.AppendArg(b, arg)
	}

	if err := cmd.Err(); err != nil {
		b = append(b, ": "...)
		b = append(b, err.Error()...)
	} else if val != nil {
		b = append(b, ": "...)
		b = internal.AppendArg(b, val)
	}

	return util.BytesToString(b)
}

//------------------------------------------------------------------------------

type baseCmd struct {
	ctx          context.Context
	args         []interface{}
	err          error
	keyPos       int8
	_stepCount   int8
	rawVal       interface{}
	_readTimeout *time.Duration
	cmdType      CmdType
}

var _ Cmder = (*Cmd)(nil)

func (cmd *baseCmd) Name() string {
	if len(cmd.args) == 0 {
		return ""
	}
	// Cmd name must be lower cased.
	return internal.ToLower(cmd.stringArg(0))
}

func (cmd *baseCmd) FullName() string {
	switch name := cmd.Name(); name {
	case "cluster", "command":
		if len(cmd.args) == 1 {
			return name
		}
		if s2, ok := cmd.args[1].(string); ok {
			return name + " " + s2
		}
		return name
	default:
		return name
	}
}

func (cmd *baseCmd) Args() []interface{} {
	return cmd.args
}

func (cmd *baseCmd) stringArg(pos int) string {
	if pos < 0 || pos >= len(cmd.args) {
		return ""
	}
	arg := cmd.args[pos]
	switch v := arg.(type) {
	case string:
		return v
	case []byte:
		return string(v)
	default:
		// TODO: consider using appendArg
		return fmt.Sprint(v)
	}
}

func (cmd *baseCmd) firstKeyPos() int8 {
	return cmd.keyPos
}

func (cmd *baseCmd) SetFirstKeyPos(keyPos int8) {
	cmd.keyPos = keyPos
}

func (cmd *baseCmd) stepCount() int8 {
	return cmd._stepCount
}

func (cmd *baseCmd) SetStepCount(stepCount int8) {
	cmd._stepCount = stepCount
}

func (cmd *baseCmd) SetErr(e error) {
	cmd.err = e
}

func (cmd *baseCmd) Err() error {
	return cmd.err
}

func (cmd *baseCmd) readTimeout() *time.Duration {
	return cmd._readTimeout
}

func (cmd *baseCmd) setReadTimeout(d time.Duration) {
	cmd._readTimeout = &d
}

func (cmd *baseCmd) readRawReply(rd *proto.Reader) (err error) {
	cmd.rawVal, err = rd.ReadReply()
	return err
}

func (cmd *baseCmd) GetCmdType() CmdType {
	return cmd.cmdType
}

func (cmd *baseCmd) cloneBaseCmd() baseCmd {
	var readTimeout *time.Duration
	if cmd._readTimeout != nil {
		timeout := *cmd._readTimeout
		readTimeout = &timeout
	}

	// Create a copy of args slice
	args := make([]interface{}, len(cmd.args))
	copy(args, cmd.args)

	return baseCmd{
		ctx:          cmd.ctx,
		args:         args,
		err:          cmd.err,
		keyPos:       cmd.keyPos,
		_stepCount:   cmd._stepCount,
		rawVal:       cmd.rawVal,
		_readTimeout: readTimeout,
		cmdType:      cmd.cmdType,
	}
}

//------------------------------------------------------------------------------

type Cmd struct {
	baseCmd

	val interface{}
}

func NewCmd(ctx context.Context, args ...interface{}) *Cmd {
	return &Cmd{
		baseCmd: baseCmd{
			ctx:     ctx,
			args:    args,
			cmdType: CmdTypeGeneric,
		},
	}
}

func (cmd *Cmd) String() string {
	return cmdString(cmd, cmd.val)
}

func (cmd *Cmd) SetVal(val interface{}) {
	cmd.val = val
}

func (cmd *Cmd) Val() interface{} {
	return cmd.val
}

func (cmd *Cmd) Result() (interface{}, error) {
	return cmd.val, cmd.err
}

func (cmd *Cmd) Text() (string, error) {
	if cmd.err != nil {
		return "", cmd.err
	}
	return toString(cmd.val)
}

func toString(val interface{}) (string, error) {
	switch val := val.(type) {
	case string:
		return val, nil
	default:
		err := fmt.Errorf("redis: unexpected type=%T for String", val)
		return "", err
	}
}

func (cmd *Cmd) Int() (int, error) {
	if cmd.err != nil {
		return 0, cmd.err
	}
	switch val := cmd.val.(type) {
	case int64:
		return int(val), nil
	case string:
		return strconv.Atoi(val)
	default:
		err := fmt.Errorf("redis: unexpected type=%T for Int", val)
		return 0, err
	}
}

func (cmd *Cmd) Int64() (int64, error) {
	if cmd.err != nil {
		return 0, cmd.err
	}
	return toInt64(cmd.val)
}

func toInt64(val interface{}) (int64, error) {
	switch val := val.(type) {
	case int64:
		return val, nil
	case string:
		return strconv.ParseInt(val, 10, 64)
	default:
		err := fmt.Errorf("redis: unexpected type=%T for Int64", val)
		return 0, err
	}
}

func (cmd *Cmd) Uint64() (uint64, error) {
	if cmd.err != nil {
		return 0, cmd.err
	}
	return toUint64(cmd.val)
}

func toUint64(val interface{}) (uint64, error) {
	switch val := val.(type) {
	case int64:
		return uint64(val), nil
	case string:
		return strconv.ParseUint(val, 10, 64)
	default:
		err := fmt.Errorf("redis: unexpected type=%T for Uint64", val)
		return 0, err
	}
}

func (cmd *Cmd) Float32() (float32, error) {
	if cmd.err != nil {
		return 0, cmd.err
	}
	return toFloat32(cmd.val)
}

func toFloat32(val interface{}) (float32, error) {
	switch val := val.(type) {
	case int64:
		return float32(val), nil
	case string:
		f, err := strconv.ParseFloat(val, 32)
		if err != nil {
			return 0, err
		}
		return float32(f), nil
	default:
		err := fmt.Errorf("redis: unexpected type=%T for Float32", val)
		return 0, err
	}
}

func (cmd *Cmd) Float64() (float64, error) {
	if cmd.err != nil {
		return 0, cmd.err
	}
	return toFloat64(cmd.val)
}

func toFloat64(val interface{}) (float64, error) {
	switch val := val.(type) {
	case int64:
		return float64(val), nil
	case string:
		return strconv.ParseFloat(val, 64)
	default:
		err := fmt.Errorf("redis: unexpected type=%T for Float64", val)
		return 0, err
	}
}

func (cmd *Cmd) Bool() (bool, error) {
	if cmd.err != nil {
		return false, cmd.err
	}
	return toBool(cmd.val)
}

func toBool(val interface{}) (bool, error) {
	switch val := val.(type) {
	case bool:
		return val, nil
	case int64:
		return val != 0, nil
	case string:
		return strconv.ParseBool(val)
	default:
		err := fmt.Errorf("redis: unexpected type=%T for Bool", val)
		return false, err
	}
}

func (cmd *Cmd) Slice() ([]interface{}, error) {
	if cmd.err != nil {
		return nil, cmd.err
	}
	switch val := cmd.val.(type) {
	case []interface{}:
		return val, nil
	default:
		return nil, fmt.Errorf("redis: unexpected type=%T for Slice", val)
	}
}

func (cmd *Cmd) StringSlice() ([]string, error) {
	slice, err := cmd.Slice()
	if err != nil {
		return nil, err
	}

	ss := make([]string, len(slice))
	for i, iface := range slice {
		val, err := toString(iface)
		if err != nil {
			return nil, err
		}
		ss[i] = val
	}
	return ss, nil
}

func (cmd *Cmd) Int64Slice() ([]int64, error) {
	slice, err := cmd.Slice()
	if err != nil {
		return nil, err
	}

	nums := make([]int64, len(slice))
	for i, if
Download .txt
gitextract_z25o6z9o/

├── .github/
│   ├── CODEOWNERS
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── config.yml
│   ├── RELEASE_NOTES_TEMPLATE.md
│   ├── actions/
│   │   └── run-tests/
│   │       └── action.yml
│   ├── dependabot.yml
│   ├── release-drafter-config.yml
│   ├── spellcheck-settings.yml
│   ├── wordlist.txt
│   └── workflows/
│       ├── build.yml
│       ├── codeql-analysis.yml
│       ├── doctests.yaml
│       ├── golangci-lint.yml
│       ├── release-drafter.yml
│       ├── spellcheck.yml
│       ├── stale-issues.yml
│       ├── test-e2e.yml
│       └── test-redis-enterprise.yml
├── .gitignore
├── .golangci.yml
├── .prettierrc.yml
├── CONTRIBUTING.md
├── LICENSE
├── Makefile
├── README.md
├── RELEASE-NOTES.md
├── RELEASING.md
├── acl_commands.go
├── acl_commands_test.go
├── adapters.go
├── async_handoff_integration_test.go
├── auth/
│   ├── auth.go
│   ├── auth_test.go
│   └── reauth_credentials_listener.go
├── bench_test.go
├── bitmap_commands.go
├── bitmap_commands_test.go
├── cluster_commands.go
├── command.go
├── command_digest_test.go
├── command_policy_resolver.go
├── command_recorder_test.go
├── command_test.go
├── commands.go
├── commands_test.go
├── dial_retry_backoff.go
├── digest_test.go
├── doc.go
├── docker-compose.yml
├── dockers/
│   ├── .gitignore
│   └── sentinel.conf
├── doctests/
│   ├── Makefile
│   ├── README.md
│   ├── bf_tutorial_test.go
│   ├── bitfield_tutorial_test.go
│   ├── bitmap_tutorial_test.go
│   ├── cmds_generic_test.go
│   ├── cmds_hash_test.go
│   ├── cmds_list_test.go
│   ├── cmds_servermgmt_test.go
│   ├── cmds_set_test.go
│   ├── cmds_sorted_set_test.go
│   ├── cmds_string_test.go
│   ├── cms_tutorial_test.go
│   ├── cuckoo_tutorial_test.go
│   ├── geo_index_test.go
│   ├── geo_tutorial_test.go
│   ├── hash_tutorial_test.go
│   ├── hll_tutorial_test.go
│   ├── home_json_example_test.go
│   ├── home_prob_dts_test.go
│   ├── json_tutorial_test.go
│   ├── list_tutorial_test.go
│   ├── lpush_lrange_test.go
│   ├── main_test.go
│   ├── pipe_trans_example_test.go
│   ├── query_agg_test.go
│   ├── query_em_test.go
│   ├── query_ft_test.go
│   ├── query_geo_test.go
│   ├── query_range_test.go
│   ├── search_quickstart_test.go
│   ├── set_get_test.go
│   ├── sets_example_test.go
│   ├── ss_tutorial_test.go
│   ├── stream_tutorial_test.go
│   ├── string_example_test.go
│   ├── tdigest_tutorial_test.go
│   ├── timeseries_tut_test.go
│   ├── topk_tutorial_test.go
│   └── vec_set_test.go
├── error.go
├── error_test.go
├── error_wrapping_test.go
├── example/
│   ├── cluster-mget/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── del-keys-without-ttl/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── digest-optimistic-locking/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── disable-maintnotifications/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── hll/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── hset-struct/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── lua-scripting/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── maintnotifiations-pubsub/
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── otel/
│   │   ├── README.md
│   │   ├── client.go
│   │   ├── config/
│   │   │   ├── otel-collector.yaml
│   │   │   └── vector.toml
│   │   ├── docker-compose.yml
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── uptrace.yml
│   ├── otel-metrics/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── redis-bloom/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── scan-struct/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── tls-cert-auth/
│   │   ├── README.md
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   └── tls-connection/
│       ├── README.md
│       ├── go.mod
│       ├── go.sum
│       └── main.go
├── example_instrumentation_test.go
├── example_test.go
├── export_test.go
├── extra/
│   ├── rediscensus/
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── rediscensus.go
│   ├── rediscmd/
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── rediscmd.go
│   │   ├── rediscmd_test.go
│   │   ├── safe.go
│   │   └── unsafe.go
│   ├── redisotel/
│   │   ├── README.md
│   │   ├── config.go
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── metrics.go
│   │   ├── metrics_test.go
│   │   ├── tracing.go
│   │   └── tracing_test.go
│   ├── redisotel-native/
│   │   ├── attributes.go
│   │   ├── config.go
│   │   ├── go.mod
│   │   ├── go.sum
│   │   ├── metrics.go
│   │   ├── metrics_definitions_test.go
│   │   ├── metrics_stress_test.go
│   │   └── redisotel.go
│   └── redisprometheus/
│       ├── README.md
│       ├── collector.go
│       ├── go.mod
│       └── go.sum
├── fuzz/
│   └── fuzz.go
├── generic_commands.go
├── geo_commands.go
├── go.mod
├── go.sum
├── hash_commands.go
├── helper/
│   ├── helper.go
│   └── helper_test.go
├── hotkeys_commands.go
├── hotkeys_commands_test.go
├── hset_benchmark_test.go
├── hyperloglog_commands.go
├── internal/
│   ├── arg.go
│   ├── auth/
│   │   └── streaming/
│   │       ├── conn_reauth_credentials_listener.go
│   │       ├── cred_listeners.go
│   │       ├── manager.go
│   │       ├── manager_test.go
│   │       ├── pool_hook.go
│   │       └── pool_hook_state_test.go
│   ├── customvet/
│   │   ├── .gitignore
│   │   ├── checks/
│   │   │   └── setval/
│   │   │       ├── setval.go
│   │   │       ├── setval_test.go
│   │   │       └── testdata/
│   │   │           └── src/
│   │   │               └── a/
│   │   │                   └── a.go
│   │   ├── go.mod
│   │   ├── go.sum
│   │   └── main.go
│   ├── hashtag/
│   │   ├── hashtag.go
│   │   └── hashtag_test.go
│   ├── hscan/
│   │   ├── hscan.go
│   │   ├── hscan_test.go
│   │   └── structmap.go
│   ├── interfaces/
│   │   └── interfaces.go
│   ├── internal.go
│   ├── internal_test.go
│   ├── log.go
│   ├── maintnotifications/
│   │   └── logs/
│   │       └── log_messages.go
│   ├── once.go
│   ├── otel/
│   │   └── metrics.go
│   ├── pool/
│   │   ├── bench_test.go
│   │   ├── buffer_size_test.go
│   │   ├── conn.go
│   │   ├── conn_check.go
│   │   ├── conn_check_dummy.go
│   │   ├── conn_check_test.go
│   │   ├── conn_relaxed_timeout_test.go
│   │   ├── conn_state.go
│   │   ├── conn_state_alloc_test.go
│   │   ├── conn_state_test.go
│   │   ├── conn_used_at_test.go
│   │   ├── dial_conn_retry_test.go
│   │   ├── dial_context_timeout_test.go
│   │   ├── dial_retry_backoff_test.go
│   │   ├── double_freeturn_simple_test.go
│   │   ├── double_freeturn_test.go
│   │   ├── export_test.go
│   │   ├── hooks.go
│   │   ├── hooks_test.go
│   │   ├── main_test.go
│   │   ├── pool.go
│   │   ├── pool_single.go
│   │   ├── pool_sticky.go
│   │   ├── pool_test.go
│   │   ├── pubsub.go
│   │   ├── try_dial_test.go
│   │   ├── want_conn.go
│   │   └── want_conn_test.go
│   ├── proto/
│   │   ├── peek_push_notification_test.go
│   │   ├── proto_test.go
│   │   ├── reader.go
│   │   ├── reader_test.go
│   │   ├── redis_errors.go
│   │   ├── redis_errors_test.go
│   │   ├── scan.go
│   │   ├── scan_test.go
│   │   ├── writer.go
│   │   └── writer_test.go
│   ├── rand/
│   │   └── rand.go
│   ├── redis.go
│   ├── routing/
│   │   ├── aggregator.go
│   │   ├── aggregator_test.go
│   │   ├── policy.go
│   │   └── shard_picker.go
│   ├── semaphore.go
│   ├── util/
│   │   ├── atomic_max.go
│   │   ├── atomic_min.go
│   │   ├── convert.go
│   │   ├── convert_test.go
│   │   ├── safe.go
│   │   ├── strconv.go
│   │   ├── strconv_test.go
│   │   ├── type.go
│   │   ├── unsafe.go
│   │   └── unsafe_test.go
│   ├── util.go
│   └── util_test.go
├── internal_maint_notif_test.go
├── internal_test.go
├── iterator.go
├── iterator_test.go
├── json.go
├── json_test.go
├── list_commands.go
├── logging/
│   ├── logging.go
│   └── logging_test.go
├── main_test.go
├── maintnotifications/
│   ├── FEATURES.md
│   ├── README.md
│   ├── circuit_breaker.go
│   ├── circuit_breaker_test.go
│   ├── config.go
│   ├── config_test.go
│   ├── e2e/
│   │   ├── .gitignore
│   │   ├── DATABASE_MANAGEMENT.md
│   │   ├── README_SCENARIOS.md
│   │   ├── cluster_maintnotif_test.go
│   │   ├── cmd/
│   │   │   └── proxy-fi-server/
│   │   │       ├── Dockerfile
│   │   │       └── main.go
│   │   ├── command_runner_test.go
│   │   ├── config_autostart_logic_test.go
│   │   ├── config_parser_test.go
│   │   ├── doc.go
│   │   ├── examples/
│   │   │   └── endpoints.json
│   │   ├── fault_injector.go
│   │   ├── logcollector_test.go
│   │   ├── main_test.go
│   │   ├── notification_injector_test.go
│   │   ├── notiftracker_test.go
│   │   ├── proxy_fault_injector_server.go
│   │   ├── scenario_endpoint_types_test.go
│   │   ├── scenario_push_notifications_test.go
│   │   ├── scenario_stress_test.go
│   │   ├── scenario_template.go.example
│   │   ├── scenario_timeout_configs_test.go
│   │   ├── scenario_tls_configs_test.go
│   │   ├── scenario_unified_injector_test.go
│   │   ├── scripts/
│   │   │   └── run-e2e-tests.sh
│   │   ├── slot_keys_test.go
│   │   ├── test_mode_test.go
│   │   └── utils_test.go
│   ├── errors.go
│   ├── example_hooks.go
│   ├── handoff_worker.go
│   ├── hooks.go
│   ├── manager.go
│   ├── manager_test.go
│   ├── pool_hook.go
│   ├── pool_hook_test.go
│   ├── push_notification_handler.go
│   ├── push_notification_handler_test.go
│   └── state.go
├── monitor_test.go
├── options.go
├── options_test.go
├── osscluster.go
├── osscluster_commands.go
├── osscluster_lazy_reload_test.go
├── osscluster_maintnotifications_test.go
├── osscluster_maintnotifications_unit_test.go
├── osscluster_router.go
├── osscluster_test.go
├── otel.go
├── pipeline.go
├── pipeline_test.go
├── pool_pubsub_bench_test.go
├── pool_test.go
├── probabilistic.go
├── probabilistic_test.go
├── pubsub.go
├── pubsub_commands.go
├── pubsub_test.go
├── push/
│   ├── errors.go
│   ├── handler.go
│   ├── handler_context.go
│   ├── processor.go
│   ├── processor_unit_test.go
│   ├── push.go
│   ├── push_test.go
│   └── registry.go
├── push_notifications.go
├── race_test.go
├── redis.go
├── redis_test.go
├── result.go
├── ring.go
├── ring_test.go
├── script.go
├── scripting_commands.go
├── scripts/
│   ├── bump_deps.sh
│   ├── release.sh
│   └── tag.sh
├── search_builders.go
├── search_builders_test.go
├── search_commands.go
├── search_commands_parse_test.go
├── search_test.go
├── sentinel.go
├── sentinel_test.go
├── set_commands.go
├── sortedset_commands.go
├── stream_commands.go
├── string_commands.go
├── timeseries_commands.go
├── timeseries_commands_test.go
├── tls_cert_auth_test.go
├── tls_cluster_test.go
├── tls_standalone_test.go
├── tls_test.go
├── tx.go
├── tx_test.go
├── unit_test.go
├── universal.go
├── universal_test.go
├── vectorset_commands.go
├── vectorset_commands_integration_test.go
├── vectorset_commands_test.go
└── version.go
Download .txt
Showing preview only (450K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (4857 symbols across 276 files)

FILE: acl_commands.go
  type ACLCmdable (line 5) | type ACLCmdable interface
  type ACLCatArgs (line 23) | type ACLCatArgs struct
  method ACLDryRun (line 27) | func (c cmdable) ACLDryRun(ctx context.Context, username string, command...
  method ACLLog (line 36) | func (c cmdable) ACLLog(ctx context.Context, count int64) *ACLLogCmd {
  method ACLLogReset (line 47) | func (c cmdable) ACLLogReset(ctx context.Context) *StatusCmd {
  method ACLDelUser (line 53) | func (c cmdable) ACLDelUser(ctx context.Context, username string) *IntCmd {
  method ACLSetUser (line 59) | func (c cmdable) ACLSetUser(ctx context.Context, username string, rules ...
  method ACLGenPass (line 72) | func (c cmdable) ACLGenPass(ctx context.Context, bit int) *StringCmd {
  method ACLUsers (line 83) | func (c cmdable) ACLUsers(ctx context.Context) *StringSliceCmd {
  method ACLWhoAmI (line 89) | func (c cmdable) ACLWhoAmI(ctx context.Context) *StringCmd {
  method ACLList (line 95) | func (c cmdable) ACLList(ctx context.Context) *StringSliceCmd {
  method ACLCat (line 101) | func (c cmdable) ACLCat(ctx context.Context) *StringSliceCmd {
  method ACLCatArgs (line 107) | func (c cmdable) ACLCatArgs(ctx context.Context, options *ACLCatArgs) *S...

FILE: adapters.go
  function newClientAdapter (line 20) | func newClientAdapter(client *baseClient) interfaces.ClientInterface {
  type clientAdapter (line 25) | type clientAdapter struct
    method GetOptions (line 30) | func (ca *clientAdapter) GetOptions() interfaces.OptionsInterface {
    method GetPushProcessor (line 35) | func (ca *clientAdapter) GetPushProcessor() interfaces.NotificationPro...
  type optionsAdapter (line 40) | type optionsAdapter struct
    method GetReadTimeout (line 45) | func (oa *optionsAdapter) GetReadTimeout() time.Duration {
    method GetWriteTimeout (line 50) | func (oa *optionsAdapter) GetWriteTimeout() time.Duration {
    method GetNetwork (line 55) | func (oa *optionsAdapter) GetNetwork() string {
    method GetAddr (line 60) | func (oa *optionsAdapter) GetAddr() string {
    method GetNodeAddress (line 67) | func (oa *optionsAdapter) GetNodeAddress() string {
    method IsTLSEnabled (line 72) | func (oa *optionsAdapter) IsTLSEnabled() bool {
    method GetProtocol (line 77) | func (oa *optionsAdapter) GetProtocol() int {
    method GetPoolSize (line 82) | func (oa *optionsAdapter) GetPoolSize() int {
    method NewDialer (line 87) | func (oa *optionsAdapter) NewDialer() func(context.Context) (net.Conn,...
  type pushProcessorAdapter (line 98) | type pushProcessorAdapter struct
    method RegisterHandler (line 103) | func (ppa *pushProcessorAdapter) RegisterHandler(pushNotificationName ...
    method UnregisterHandler (line 111) | func (ppa *pushProcessorAdapter) UnregisterHandler(pushNotificationNam...
    method GetHandler (line 116) | func (ppa *pushProcessorAdapter) GetHandler(pushNotificationName strin...

FILE: async_handoff_integration_test.go
  type mockNetConn (line 17) | type mockNetConn struct
    method Read (line 21) | func (m *mockNetConn) Read(b []byte) (n int, err error)   { return 0, ...
    method Write (line 22) | func (m *mockNetConn) Write(b []byte) (n int, err error)  { return len...
    method Close (line 23) | func (m *mockNetConn) Close() error                       { return nil }
    method LocalAddr (line 24) | func (m *mockNetConn) LocalAddr() net.Addr                { return &mo...
    method RemoteAddr (line 25) | func (m *mockNetConn) RemoteAddr() net.Addr               { return &mo...
    method SetDeadline (line 26) | func (m *mockNetConn) SetDeadline(t time.Time) error      { return nil }
    method SetReadDeadline (line 27) | func (m *mockNetConn) SetReadDeadline(t time.Time) error  { return nil }
    method SetWriteDeadline (line 28) | func (m *mockNetConn) SetWriteDeadline(t time.Time) error { return nil }
  type mockAddr (line 30) | type mockAddr struct
    method Network (line 34) | func (m *mockAddr) Network() string { return "tcp" }
    method String (line 35) | func (m *mockAddr) String() string  { return m.addr }
  function TestEventDrivenHandoffIntegration (line 38) | func TestEventDrivenHandoffIntegration(t *testing.T) {
  function init (line 400) | func init() {

FILE: auth/auth.go
  type StreamingCredentialsProvider (line 8) | type StreamingCredentialsProvider interface
  type UnsubscribeFunc (line 18) | type UnsubscribeFunc
  type CredentialsListener (line 24) | type CredentialsListener interface
  type Credentials (line 31) | type Credentials interface
  type basicAuth (line 40) | type basicAuth struct
    method RawCredentials (line 46) | func (b *basicAuth) RawCredentials() string {
    method BasicAuth (line 51) | func (b *basicAuth) BasicAuth() (username string, password string) {
  function NewBasicCredentials (line 56) | func NewBasicCredentials(username, password string) Credentials {

FILE: auth/auth_test.go
  type mockStreamingProvider (line 11) | type mockStreamingProvider struct
    method Subscribe (line 24) | func (m *mockStreamingProvider) Subscribe(listener CredentialsListener...
  function newMockStreamingProvider (line 17) | func newMockStreamingProvider(initialCreds Credentials) *mockStreamingPr...
  function TestStreamingCredentialsProvider (line 45) | func TestStreamingCredentialsProvider(t *testing.T) {
  function TestBasicCredentials (line 182) | func TestBasicCredentials(t *testing.T) {
  function TestReAuthCredentialsListener (line 269) | func TestReAuthCredentialsListener(t *testing.T) {

FILE: auth/reauth_credentials_listener.go
  type ReAuthCredentialsListener (line 8) | type ReAuthCredentialsListener struct
    method OnNext (line 16) | func (c *ReAuthCredentialsListener) OnNext(credentials Credentials) {
    method OnError (line 29) | func (c *ReAuthCredentialsListener) OnError(err error) {
  function NewReAuthCredentialsListener (line 39) | func NewReAuthCredentialsListener(reAuth func(credentials Credentials) e...

FILE: bench_test.go
  function benchmarkRedisClient (line 16) | func benchmarkRedisClient(ctx context.Context, poolSize int) *redis.Clie...
  function BenchmarkRedisPing (line 30) | func BenchmarkRedisPing(b *testing.B) {
  function BenchmarkSetGoroutines (line 46) | func BenchmarkSetGoroutines(b *testing.B) {
  function BenchmarkRedisGetNil (line 70) | func BenchmarkRedisGetNil(b *testing.B) {
  type setStringBenchmark (line 86) | type setStringBenchmark struct
    method String (line 91) | func (bm setStringBenchmark) String() string {
  function BenchmarkRedisSetString (line 95) | func BenchmarkRedisSetString(b *testing.B) {
  function BenchmarkRedisSetGetBytes (line 131) | func BenchmarkRedisSetGetBytes(b *testing.B) {
  function BenchmarkRedisMGet (line 157) | func BenchmarkRedisMGet(b *testing.B) {
  function BenchmarkSetExpire (line 177) | func BenchmarkSetExpire(b *testing.B) {
  function BenchmarkPipeline (line 196) | func BenchmarkPipeline(b *testing.B) {
  function BenchmarkZAdd (line 217) | func BenchmarkZAdd(b *testing.B) {
  function BenchmarkXRead (line 237) | func BenchmarkXRead(b *testing.B) {
  function newClusterScenario (line 278) | func newClusterScenario() *clusterScenario {
  function BenchmarkClusterPing (line 288) | func BenchmarkClusterPing(b *testing.B) {
  function BenchmarkClusterDoInt (line 318) | func BenchmarkClusterDoInt(b *testing.B) {
  function BenchmarkClusterSetString (line 347) | func BenchmarkClusterSetString(b *testing.B) {
  function BenchmarkExecRingSetAddrsCmd (line 379) | func BenchmarkExecRingSetAddrsCmd(b *testing.B) {

FILE: bitmap_commands.go
  type BitMapCmdable (line 8) | type BitMapCmdable interface
  method GetBit (line 26) | func (c cmdable) GetBit(ctx context.Context, key string, offset int64) *...
  method SetBit (line 32) | func (c cmdable) SetBit(ctx context.Context, key string, offset int64, v...
  type BitCount (line 44) | type BitCount struct
  constant BitCountIndexByte (line 49) | BitCountIndexByte string = "BYTE"
  constant BitCountIndexBit (line 50) | BitCountIndexBit string = "BIT"
  method BitCount (line 52) | func (c cmdable) BitCount(ctx context.Context, key string, bitCount *Bit...
  method bitOp (line 72) | func (c cmdable) bitOp(ctx context.Context, op, destKey string, keys ......
  method BitOpAnd (line 86) | func (c cmdable) BitOpAnd(ctx context.Context, destKey string, keys ...s...
  method BitOpOr (line 91) | func (c cmdable) BitOpOr(ctx context.Context, destKey string, keys ...st...
  method BitOpXor (line 96) | func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...s...
  method BitOpNot (line 101) | func (c cmdable) BitOpNot(ctx context.Context, destKey string, key strin...
  method BitOpDiff (line 107) | func (c cmdable) BitOpDiff(ctx context.Context, destKey string, keys ......
  method BitOpDiff1 (line 113) | func (c cmdable) BitOpDiff1(ctx context.Context, destKey string, keys .....
  method BitOpAndOr (line 119) | func (c cmdable) BitOpAndOr(ctx context.Context, destKey string, keys .....
  method BitOpOne (line 125) | func (c cmdable) BitOpOne(ctx context.Context, destKey string, keys ...s...
  method BitPos (line 131) | func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...
  method BitPosSpan (line 159) | func (c cmdable) BitPosSpan(ctx context.Context, key string, bit int8, s...
  method BitField (line 169) | func (c cmdable) BitField(ctx context.Context, key string, values ...int...
  method BitFieldRO (line 182) | func (c cmdable) BitFieldRO(ctx context.Context, key string, values ...i...

FILE: bitmap_commands_test.go
  type bitCountExpected (line 9) | type bitCountExpected struct

FILE: cluster_commands.go
  type ClusterCmdable (line 5) | type ClusterCmdable interface
  method ClusterMyShardID (line 33) | func (c cmdable) ClusterMyShardID(ctx context.Context) *StringCmd {
  method ClusterMyID (line 39) | func (c cmdable) ClusterMyID(ctx context.Context) *StringCmd {
  method ClusterSlots (line 48) | func (c cmdable) ClusterSlots(ctx context.Context) *ClusterSlotsCmd {
  method ClusterShards (line 54) | func (c cmdable) ClusterShards(ctx context.Context) *ClusterShardsCmd {
  method ClusterLinks (line 60) | func (c cmdable) ClusterLinks(ctx context.Context) *ClusterLinksCmd {
  method ClusterNodes (line 66) | func (c cmdable) ClusterNodes(ctx context.Context) *StringCmd {
  method ClusterMeet (line 72) | func (c cmdable) ClusterMeet(ctx context.Context, host, port string) *St...
  method ClusterForget (line 78) | func (c cmdable) ClusterForget(ctx context.Context, nodeID string) *Stat...
  method ClusterReplicate (line 84) | func (c cmdable) ClusterReplicate(ctx context.Context, nodeID string) *S...
  method ClusterResetSoft (line 90) | func (c cmdable) ClusterResetSoft(ctx context.Context) *StatusCmd {
  method ClusterResetHard (line 96) | func (c cmdable) ClusterResetHard(ctx context.Context) *StatusCmd {
  method ClusterInfo (line 102) | func (c cmdable) ClusterInfo(ctx context.Context) *StringCmd {
  method ClusterKeySlot (line 108) | func (c cmdable) ClusterKeySlot(ctx context.Context, key string) *IntCmd {
  method ClusterGetKeysInSlot (line 114) | func (c cmdable) ClusterGetKeysInSlot(ctx context.Context, slot int, cou...
  method ClusterCountFailureReports (line 120) | func (c cmdable) ClusterCountFailureReports(ctx context.Context, nodeID ...
  method ClusterCountKeysInSlot (line 126) | func (c cmdable) ClusterCountKeysInSlot(ctx context.Context, slot int) *...
  method ClusterDelSlots (line 132) | func (c cmdable) ClusterDelSlots(ctx context.Context, slots ...int) *Sta...
  method ClusterDelSlotsRange (line 144) | func (c cmdable) ClusterDelSlotsRange(ctx context.Context, min, max int)...
  method ClusterSaveConfig (line 153) | func (c cmdable) ClusterSaveConfig(ctx context.Context) *StatusCmd {
  method ClusterSlaves (line 162) | func (c cmdable) ClusterSlaves(ctx context.Context, nodeID string) *Stri...
  method ClusterFailover (line 168) | func (c cmdable) ClusterFailover(ctx context.Context) *StatusCmd {
  method ClusterAddSlots (line 174) | func (c cmdable) ClusterAddSlots(ctx context.Context, slots ...int) *Sta...
  method ClusterAddSlotsRange (line 186) | func (c cmdable) ClusterAddSlotsRange(ctx context.Context, min, max int)...
  method ReadOnly (line 195) | func (c cmdable) ReadOnly(ctx context.Context) *StatusCmd {
  method ReadWrite (line 201) | func (c cmdable) ReadWrite(ctx context.Context) *StatusCmd {

FILE: command.go
  type CmdTyper (line 75) | type CmdTyper interface
  type CmdTypeGetter (line 80) | type CmdTypeGetter interface
  type CmdType (line 84) | type CmdType
  constant CmdTypeGeneric (line 87) | CmdTypeGeneric CmdType = iota
  constant CmdTypeString (line 88) | CmdTypeString
  constant CmdTypeInt (line 89) | CmdTypeInt
  constant CmdTypeBool (line 90) | CmdTypeBool
  constant CmdTypeFloat (line 91) | CmdTypeFloat
  constant CmdTypeStringSlice (line 92) | CmdTypeStringSlice
  constant CmdTypeIntSlice (line 93) | CmdTypeIntSlice
  constant CmdTypeFloatSlice (line 94) | CmdTypeFloatSlice
  constant CmdTypeBoolSlice (line 95) | CmdTypeBoolSlice
  constant CmdTypeMapStringString (line 96) | CmdTypeMapStringString
  constant CmdTypeMapStringInt (line 97) | CmdTypeMapStringInt
  constant CmdTypeMapStringInterface (line 98) | CmdTypeMapStringInterface
  constant CmdTypeMapStringInterfaceSlice (line 99) | CmdTypeMapStringInterfaceSlice
  constant CmdTypeSlice (line 100) | CmdTypeSlice
  constant CmdTypeStatus (line 101) | CmdTypeStatus
  constant CmdTypeDuration (line 102) | CmdTypeDuration
  constant CmdTypeTime (line 103) | CmdTypeTime
  constant CmdTypeKeyValueSlice (line 104) | CmdTypeKeyValueSlice
  constant CmdTypeStringStructMap (line 105) | CmdTypeStringStructMap
  constant CmdTypeXMessageSlice (line 106) | CmdTypeXMessageSlice
  constant CmdTypeXStreamSlice (line 107) | CmdTypeXStreamSlice
  constant CmdTypeXPending (line 108) | CmdTypeXPending
  constant CmdTypeXPendingExt (line 109) | CmdTypeXPendingExt
  constant CmdTypeXAutoClaim (line 110) | CmdTypeXAutoClaim
  constant CmdTypeXAutoClaimJustID (line 111) | CmdTypeXAutoClaimJustID
  constant CmdTypeXInfoConsumers (line 112) | CmdTypeXInfoConsumers
  constant CmdTypeXInfoGroups (line 113) | CmdTypeXInfoGroups
  constant CmdTypeXInfoStream (line 114) | CmdTypeXInfoStream
  constant CmdTypeXInfoStreamFull (line 115) | CmdTypeXInfoStreamFull
  constant CmdTypeZSlice (line 116) | CmdTypeZSlice
  constant CmdTypeZWithKey (line 117) | CmdTypeZWithKey
  constant CmdTypeScan (line 118) | CmdTypeScan
  constant CmdTypeClusterSlots (line 119) | CmdTypeClusterSlots
  constant CmdTypeGeoLocation (line 120) | CmdTypeGeoLocation
  constant CmdTypeGeoSearchLocation (line 121) | CmdTypeGeoSearchLocation
  constant CmdTypeGeoPos (line 122) | CmdTypeGeoPos
  constant CmdTypeCommandsInfo (line 123) | CmdTypeCommandsInfo
  constant CmdTypeSlowLog (line 124) | CmdTypeSlowLog
  constant CmdTypeMapStringStringSlice (line 125) | CmdTypeMapStringStringSlice
  constant CmdTypeMapMapStringInterface (line 126) | CmdTypeMapMapStringInterface
  constant CmdTypeKeyValues (line 127) | CmdTypeKeyValues
  constant CmdTypeZSliceWithKey (line 128) | CmdTypeZSliceWithKey
  constant CmdTypeFunctionList (line 129) | CmdTypeFunctionList
  constant CmdTypeFunctionStats (line 130) | CmdTypeFunctionStats
  constant CmdTypeLCS (line 131) | CmdTypeLCS
  constant CmdTypeKeyFlags (line 132) | CmdTypeKeyFlags
  constant CmdTypeClusterLinks (line 133) | CmdTypeClusterLinks
  constant CmdTypeClusterShards (line 134) | CmdTypeClusterShards
  constant CmdTypeRankWithScore (line 135) | CmdTypeRankWithScore
  constant CmdTypeClientInfo (line 136) | CmdTypeClientInfo
  constant CmdTypeACLLog (line 137) | CmdTypeACLLog
  constant CmdTypeInfo (line 138) | CmdTypeInfo
  constant CmdTypeMonitor (line 139) | CmdTypeMonitor
  constant CmdTypeJSON (line 140) | CmdTypeJSON
  constant CmdTypeJSONSlice (line 141) | CmdTypeJSONSlice
  constant CmdTypeIntPointerSlice (line 142) | CmdTypeIntPointerSlice
  constant CmdTypeScanDump (line 143) | CmdTypeScanDump
  constant CmdTypeBFInfo (line 144) | CmdTypeBFInfo
  constant CmdTypeCFInfo (line 145) | CmdTypeCFInfo
  constant CmdTypeCMSInfo (line 146) | CmdTypeCMSInfo
  constant CmdTypeTopKInfo (line 147) | CmdTypeTopKInfo
  constant CmdTypeTDigestInfo (line 148) | CmdTypeTDigestInfo
  constant CmdTypeFTSynDump (line 149) | CmdTypeFTSynDump
  constant CmdTypeAggregate (line 150) | CmdTypeAggregate
  constant CmdTypeFTInfo (line 151) | CmdTypeFTInfo
  constant CmdTypeFTSpellCheck (line 152) | CmdTypeFTSpellCheck
  constant CmdTypeFTSearch (line 153) | CmdTypeFTSearch
  constant CmdTypeTSTimestampValue (line 154) | CmdTypeTSTimestampValue
  constant CmdTypeTSTimestampValueSlice (line 155) | CmdTypeTSTimestampValueSlice
  constant CmdTypeHotKeys (line 156) | CmdTypeHotKeys
  type CmdTypeXAutoClaimValue (line 160) | type CmdTypeXAutoClaimValue struct
  type CmdTypeXAutoClaimJustIDValue (line 165) | type CmdTypeXAutoClaimJustIDValue struct
  type CmdTypeScanValue (line 170) | type CmdTypeScanValue struct
  type CmdTypeKeyValuesValue (line 175) | type CmdTypeKeyValuesValue struct
  type CmdTypeZSliceWithKeyValue (line 180) | type CmdTypeZSliceWithKeyValue struct
  type Cmder (line 186) | type Cmder interface
  function setCmdsErr (line 222) | func setCmdsErr(cmds []Cmder, e error) {
  function cmdsFirstErr (line 230) | func cmdsFirstErr(cmds []Cmder) error {
  function writeCmds (line 239) | func writeCmds(wr *proto.Writer, cmds []Cmder) error {
  function writeCmd (line 248) | func writeCmd(wr *proto.Writer, cmd Cmder) error {
  function cmdFirstKeyPos (line 255) | func cmdFirstKeyPos(cmd Cmder) int {
  function cmdString (line 285) | func cmdString(cmd Cmder, val interface{}) string {
  type baseCmd (line 308) | type baseCmd struct
    method Name (line 321) | func (cmd *baseCmd) Name() string {
    method FullName (line 329) | func (cmd *baseCmd) FullName() string {
    method Args (line 344) | func (cmd *baseCmd) Args() []interface{} {
    method stringArg (line 348) | func (cmd *baseCmd) stringArg(pos int) string {
    method firstKeyPos (line 364) | func (cmd *baseCmd) firstKeyPos() int8 {
    method SetFirstKeyPos (line 368) | func (cmd *baseCmd) SetFirstKeyPos(keyPos int8) {
    method stepCount (line 372) | func (cmd *baseCmd) stepCount() int8 {
    method SetStepCount (line 376) | func (cmd *baseCmd) SetStepCount(stepCount int8) {
    method SetErr (line 380) | func (cmd *baseCmd) SetErr(e error) {
    method Err (line 384) | func (cmd *baseCmd) Err() error {
    method readTimeout (line 388) | func (cmd *baseCmd) readTimeout() *time.Duration {
    method setReadTimeout (line 392) | func (cmd *baseCmd) setReadTimeout(d time.Duration) {
    method readRawReply (line 396) | func (cmd *baseCmd) readRawReply(rd *proto.Reader) (err error) {
    method GetCmdType (line 401) | func (cmd *baseCmd) GetCmdType() CmdType {
    method cloneBaseCmd (line 405) | func (cmd *baseCmd) cloneBaseCmd() baseCmd {
  type Cmd (line 430) | type Cmd struct
    method String (line 446) | func (cmd *Cmd) String() string {
    method SetVal (line 450) | func (cmd *Cmd) SetVal(val interface{}) {
    method Val (line 454) | func (cmd *Cmd) Val() interface{} {
    method Result (line 458) | func (cmd *Cmd) Result() (interface{}, error) {
    method Text (line 462) | func (cmd *Cmd) Text() (string, error) {
    method Int (line 479) | func (cmd *Cmd) Int() (int, error) {
    method Int64 (line 494) | func (cmd *Cmd) Int64() (int64, error) {
    method Uint64 (line 513) | func (cmd *Cmd) Uint64() (uint64, error) {
    method Float32 (line 532) | func (cmd *Cmd) Float32() (float32, error) {
    method Float64 (line 555) | func (cmd *Cmd) Float64() (float64, error) {
    method Bool (line 574) | func (cmd *Cmd) Bool() (bool, error) {
    method Slice (line 595) | func (cmd *Cmd) Slice() ([]interface{}, error) {
    method StringSlice (line 607) | func (cmd *Cmd) StringSlice() ([]string, error) {
    method Int64Slice (line 624) | func (cmd *Cmd) Int64Slice() ([]int64, error) {
    method Uint64Slice (line 641) | func (cmd *Cmd) Uint64Slice() ([]uint64, error) {
    method Float32Slice (line 658) | func (cmd *Cmd) Float32Slice() ([]float32, error) {
    method Float64Slice (line 675) | func (cmd *Cmd) Float64Slice() ([]float64, error) {
    method BoolSlice (line 692) | func (cmd *Cmd) BoolSlice() ([]bool, error) {
    method readReply (line 709) | func (cmd *Cmd) readReply(rd *proto.Reader) (err error) {
    method Clone (line 714) | func (cmd *Cmd) Clone() Cmder {
  function NewCmd (line 436) | func NewCmd(ctx context.Context, args ...interface{}) *Cmd {
  function toString (line 469) | func toString(val interface{}) (string, error) {
  function toInt64 (line 501) | func toInt64(val interface{}) (int64, error) {
  function toUint64 (line 520) | func toUint64(val interface{}) (uint64, error) {
  function toFloat32 (line 539) | func toFloat32(val interface{}) (float32, error) {
  function toFloat64 (line 562) | func toFloat64(val interface{}) (float64, error) {
  function toBool (line 581) | func toBool(val interface{}) (bool, error) {
  type SliceCmd (line 723) | type SliceCmd struct
    method SetVal (line 741) | func (cmd *SliceCmd) SetVal(val []interface{}) {
    method Val (line 745) | func (cmd *SliceCmd) Val() []interface{} {
    method Result (line 749) | func (cmd *SliceCmd) Result() ([]interface{}, error) {
    method String (line 753) | func (cmd *SliceCmd) String() string {
    method Scan (line 759) | func (cmd *SliceCmd) Scan(dst interface{}) error {
    method readReply (line 777) | func (cmd *SliceCmd) readReply(rd *proto.Reader) (err error) {
    method Clone (line 782) | func (cmd *SliceCmd) Clone() Cmder {
  function NewSliceCmd (line 731) | func NewSliceCmd(ctx context.Context, args ...interface{}) *SliceCmd {
  type StatusCmd (line 796) | type StatusCmd struct
    method SetVal (line 814) | func (cmd *StatusCmd) SetVal(val string) {
    method Val (line 818) | func (cmd *StatusCmd) Val() string {
    method Result (line 822) | func (cmd *StatusCmd) Result() (string, error) {
    method Bytes (line 826) | func (cmd *StatusCmd) Bytes() ([]byte, error) {
    method String (line 830) | func (cmd *StatusCmd) String() string {
    method readReply (line 834) | func (cmd *StatusCmd) readReply(rd *proto.Reader) (err error) {
    method Clone (line 839) | func (cmd *StatusCmd) Clone() Cmder {
  function NewStatusCmd (line 804) | func NewStatusCmd(ctx context.Context, args ...interface{}) *StatusCmd {
  type IntCmd (line 848) | type IntCmd struct
    method SetVal (line 866) | func (cmd *IntCmd) SetVal(val int64) {
    method Val (line 870) | func (cmd *IntCmd) Val() int64 {
    method Result (line 874) | func (cmd *IntCmd) Result() (int64, error) {
    method Uint64 (line 878) | func (cmd *IntCmd) Uint64() (uint64, error) {
    method String (line 882) | func (cmd *IntCmd) String() string {
    method readReply (line 886) | func (cmd *IntCmd) readReply(rd *proto.Reader) (err error) {
    method Clone (line 891) | func (cmd *IntCmd) Clone() Cmder {
  function NewIntCmd (line 856) | func NewIntCmd(ctx context.Context, args ...interface{}) *IntCmd {
  type DigestCmd (line 913) | type DigestCmd struct
    method SetVal (line 930) | func (cmd *DigestCmd) SetVal(val uint64) {
    method Val (line 934) | func (cmd *DigestCmd) Val() uint64 {
    method Result (line 938) | func (cmd *DigestCmd) Result() (uint64, error) {
    method String (line 942) | func (cmd *DigestCmd) String() string {
    method Clone (line 946) | func (cmd *DigestCmd) Clone() Cmder {
    method readReply (line 953) | func (cmd *DigestCmd) readReply(rd *proto.Reader) (err error) {
  function NewDigestCmd (line 921) | func NewDigestCmd(ctx context.Context, args ...interface{}) *DigestCmd {
  type IntSliceCmd (line 969) | type IntSliceCmd struct
    method SetVal (line 987) | func (cmd *IntSliceCmd) SetVal(val []int64) {
    method Val (line 991) | func (cmd *IntSliceCmd) Val() []int64 {
    method Result (line 995) | func (cmd *IntSliceCmd) Result() ([]int64, error) {
    method String (line 999) | func (cmd *IntSliceCmd) String() string {
    method readReply (line 1003) | func (cmd *IntSliceCmd) readReply(rd *proto.Reader) error {
    method Clone (line 1017) | func (cmd *IntSliceCmd) Clone() Cmder {
  function NewIntSliceCmd (line 977) | func NewIntSliceCmd(ctx context.Context, args ...interface{}) *IntSliceC...
  type DurationCmd (line 1031) | type DurationCmd struct
    method SetVal (line 1051) | func (cmd *DurationCmd) SetVal(val time.Duration) {
    method Val (line 1055) | func (cmd *DurationCmd) Val() time.Duration {
    method Result (line 1059) | func (cmd *DurationCmd) Result() (time.Duration, error) {
    method String (line 1063) | func (cmd *DurationCmd) String() string {
    method readReply (line 1067) | func (cmd *DurationCmd) readReply(rd *proto.Reader) error {
    method Clone (line 1083) | func (cmd *DurationCmd) Clone() Cmder {
  function NewDurationCmd (line 1040) | func NewDurationCmd(ctx context.Context, precision time.Duration, args ....
  type TimeCmd (line 1093) | type TimeCmd struct
    method SetVal (line 1111) | func (cmd *TimeCmd) SetVal(val time.Time) {
    method Val (line 1115) | func (cmd *TimeCmd) Val() time.Time {
    method Result (line 1119) | func (cmd *TimeCmd) Result() (time.Time, error) {
    method String (line 1123) | func (cmd *TimeCmd) String() string {
    method readReply (line 1127) | func (cmd *TimeCmd) readReply(rd *proto.Reader) error {
    method Clone (line 1143) | func (cmd *TimeCmd) Clone() Cmder {
  function NewTimeCmd (line 1101) | func NewTimeCmd(ctx context.Context, args ...interface{}) *TimeCmd {
  type BoolCmd (line 1152) | type BoolCmd struct
    method SetVal (line 1170) | func (cmd *BoolCmd) SetVal(val bool) {
    method Val (line 1174) | func (cmd *BoolCmd) Val() bool {
    method Result (line 1178) | func (cmd *BoolCmd) Result() (bool, error) {
    method String (line 1182) | func (cmd *BoolCmd) String() string {
    method readReply (line 1186) | func (cmd *BoolCmd) readReply(rd *proto.Reader) (err error) {
    method Clone (line 1198) | func (cmd *BoolCmd) Clone() Cmder {
  function NewBoolCmd (line 1160) | func NewBoolCmd(ctx context.Context, args ...interface{}) *BoolCmd {
  type StringCmd (line 1207) | type StringCmd struct
    method SetVal (line 1225) | func (cmd *StringCmd) SetVal(val string) {
    method Val (line 1229) | func (cmd *StringCmd) Val() string {
    method Result (line 1233) | func (cmd *StringCmd) Result() (string, error) {
    method Bytes (line 1237) | func (cmd *StringCmd) Bytes() ([]byte, error) {
    method Bool (line 1241) | func (cmd *StringCmd) Bool() (bool, error) {
    method Int (line 1248) | func (cmd *StringCmd) Int() (int, error) {
    method Int64 (line 1255) | func (cmd *StringCmd) Int64() (int64, error) {
    method Uint64 (line 1262) | func (cmd *StringCmd) Uint64() (uint64, error) {
    method Float32 (line 1269) | func (cmd *StringCmd) Float32() (float32, error) {
    method Float64 (line 1280) | func (cmd *StringCmd) Float64() (float64, error) {
    method Time (line 1287) | func (cmd *StringCmd) Time() (time.Time, error) {
    method Scan (line 1294) | func (cmd *StringCmd) Scan(val interface{}) error {
    method String (line 1301) | func (cmd *StringCmd) String() string {
    method readReply (line 1305) | func (cmd *StringCmd) readReply(rd *proto.Reader) (err error) {
    method Clone (line 1310) | func (cmd *StringCmd) Clone() Cmder {
  function NewStringCmd (line 1215) | func NewStringCmd(ctx context.Context, args ...interface{}) *StringCmd {
  type FloatCmd (line 1319) | type FloatCmd struct
    method SetVal (line 1337) | func (cmd *FloatCmd) SetVal(val float64) {
    method Val (line 1341) | func (cmd *FloatCmd) Val() float64 {
    method Result (line 1345) | func (cmd *FloatCmd) Result() (float64, error) {
    method String (line 1349) | func (cmd *FloatCmd) String() string {
    method readReply (line 1353) | func (cmd *FloatCmd) readReply(rd *proto.Reader) (err error) {
    method Clone (line 1358) | func (cmd *FloatCmd) Clone() Cmder {
  function NewFloatCmd (line 1327) | func NewFloatCmd(ctx context.Context, args ...interface{}) *FloatCmd {
  type FloatSliceCmd (line 1367) | type FloatSliceCmd struct
    method SetVal (line 1385) | func (cmd *FloatSliceCmd) SetVal(val []float64) {
    method Val (line 1389) | func (cmd *FloatSliceCmd) Val() []float64 {
    method Result (line 1393) | func (cmd *FloatSliceCmd) Result() ([]float64, error) {
    method String (line 1397) | func (cmd *FloatSliceCmd) String() string {
    method readReply (line 1401) | func (cmd *FloatSliceCmd) readReply(rd *proto.Reader) error {
    method Clone (line 1421) | func (cmd *FloatSliceCmd) Clone() Cmder {
  function NewFloatSliceCmd (line 1375) | func NewFloatSliceCmd(ctx context.Context, args ...interface{}) *FloatSl...
  type StringSliceCmd (line 1435) | type StringSliceCmd struct
    method SetVal (line 1453) | func (cmd *StringSliceCmd) SetVal(val []string) {
    method Val (line 1457) | func (cmd *StringSliceCmd) Val() []string {
    method Result (line 1461) | func (cmd *StringSliceCmd) Result() ([]string, error) {
    method String (line 1465) | func (cmd *StringSliceCmd) String() string {
    method ScanSlice (line 1469) | func (cmd *StringSliceCmd) ScanSlice(container interface{}) error {
    method readReply (line 1473) | func (cmd *StringSliceCmd) readReply(rd *proto.Reader) error {
    method Clone (line 1492) | func (cmd *StringSliceCmd) Clone() Cmder {
  function NewStringSliceCmd (line 1443) | func NewStringSliceCmd(ctx context.Context, args ...interface{}) *String...
  type KeyValue (line 1506) | type KeyValue struct
  type KeyValueSliceCmd (line 1511) | type KeyValueSliceCmd struct
    method SetVal (line 1529) | func (cmd *KeyValueSliceCmd) SetVal(val []KeyValue) {
    method Val (line 1533) | func (cmd *KeyValueSliceCmd) Val() []KeyValue {
    method Result (line 1537) | func (cmd *KeyValueSliceCmd) Result() ([]KeyValue, error) {
    method String (line 1541) | func (cmd *KeyValueSliceCmd) String() string {
    method readReply (line 1556) | func (cmd *KeyValueSliceCmd) readReply(rd *proto.Reader) error { // no...
    method Clone (line 1599) | func (cmd *KeyValueSliceCmd) Clone() Cmder {
  function NewKeyValueSliceCmd (line 1519) | func NewKeyValueSliceCmd(ctx context.Context, args ...interface{}) *KeyV...
  type BoolSliceCmd (line 1613) | type BoolSliceCmd struct
    method SetVal (line 1631) | func (cmd *BoolSliceCmd) SetVal(val []bool) {
    method Val (line 1635) | func (cmd *BoolSliceCmd) Val() []bool {
    method Result (line 1639) | func (cmd *BoolSliceCmd) Result() ([]bool, error) {
    method String (line 1643) | func (cmd *BoolSliceCmd) String() string {
    method readReply (line 1647) | func (cmd *BoolSliceCmd) readReply(rd *proto.Reader) error {
    method Clone (line 1661) | func (cmd *BoolSliceCmd) Clone() Cmder {
  function NewBoolSliceCmd (line 1621) | func NewBoolSliceCmd(ctx context.Context, args ...interface{}) *BoolSlic...
  type MapStringStringCmd (line 1675) | type MapStringStringCmd struct
    method Val (line 1693) | func (cmd *MapStringStringCmd) Val() map[string]string {
    method SetVal (line 1697) | func (cmd *MapStringStringCmd) SetVal(val map[string]string) {
    method Result (line 1701) | func (cmd *MapStringStringCmd) Result() (map[string]string, error) {
    method String (line 1705) | func (cmd *MapStringStringCmd) String() string {
    method Scan (line 1711) | func (cmd *MapStringStringCmd) Scan(dest interface{}) error {
    method readReply (line 1730) | func (cmd *MapStringStringCmd) readReply(rd *proto.Reader) error {
    method Clone (line 1753) | func (cmd *MapStringStringCmd) Clone() Cmder {
  function NewMapStringStringCmd (line 1683) | func NewMapStringStringCmd(ctx context.Context, args ...interface{}) *Ma...
  type MapStringIntCmd (line 1769) | type MapStringIntCmd struct
    method SetVal (line 1787) | func (cmd *MapStringIntCmd) SetVal(val map[string]int64) {
    method Val (line 1791) | func (cmd *MapStringIntCmd) Val() map[string]int64 {
    method Result (line 1795) | func (cmd *MapStringIntCmd) Result() (map[string]int64, error) {
    method String (line 1799) | func (cmd *MapStringIntCmd) String() string {
    method readReply (line 1803) | func (cmd *MapStringIntCmd) readReply(rd *proto.Reader) error {
    method Clone (line 1825) | func (cmd *MapStringIntCmd) Clone() Cmder {
  function NewMapStringIntCmd (line 1777) | func NewMapStringIntCmd(ctx context.Context, args ...interface{}) *MapSt...
  type MapStringSliceInterfaceCmd (line 1840) | type MapStringSliceInterfaceCmd struct
    method String (line 1855) | func (cmd *MapStringSliceInterfaceCmd) String() string {
    method SetVal (line 1859) | func (cmd *MapStringSliceInterfaceCmd) SetVal(val map[string][]interfa...
    method Result (line 1863) | func (cmd *MapStringSliceInterfaceCmd) Result() (map[string][]interfac...
    method Val (line 1867) | func (cmd *MapStringSliceInterfaceCmd) Val() map[string][]interface{} {
    method readReply (line 1871) | func (cmd *MapStringSliceInterfaceCmd) readReply(rd *proto.Reader) (er...
    method Clone (line 1936) | func (cmd *MapStringSliceInterfaceCmd) Clone() Cmder {
  function NewMapStringSliceInterfaceCmd (line 1845) | func NewMapStringSliceInterfaceCmd(ctx context.Context, args ...interfac...
  type StringStructMapCmd (line 1956) | type StringStructMapCmd struct
    method SetVal (line 1974) | func (cmd *StringStructMapCmd) SetVal(val map[string]struct{}) {
    method Val (line 1978) | func (cmd *StringStructMapCmd) Val() map[string]struct{} {
    method Result (line 1982) | func (cmd *StringStructMapCmd) Result() (map[string]struct{}, error) {
    method String (line 1986) | func (cmd *StringStructMapCmd) String() string {
    method readReply (line 1990) | func (cmd *StringStructMapCmd) readReply(rd *proto.Reader) error {
    method Clone (line 2007) | func (cmd *StringStructMapCmd) Clone() Cmder {
  function NewStringStructMapCmd (line 1964) | func NewStringStructMapCmd(ctx context.Context, args ...interface{}) *St...
  type XMessage (line 2020) | type XMessage struct
  type XMessageSliceCmd (line 2031) | type XMessageSliceCmd struct
    method SetVal (line 2049) | func (cmd *XMessageSliceCmd) SetVal(val []XMessage) {
    method Val (line 2053) | func (cmd *XMessageSliceCmd) Val() []XMessage {
    method Result (line 2057) | func (cmd *XMessageSliceCmd) Result() ([]XMessage, error) {
    method String (line 2061) | func (cmd *XMessageSliceCmd) String() string {
    method readReply (line 2065) | func (cmd *XMessageSliceCmd) readReply(rd *proto.Reader) (err error) {
    method Clone (line 2070) | func (cmd *XMessageSliceCmd) Clone() Cmder {
  function NewXMessageSliceCmd (line 2039) | func NewXMessageSliceCmd(ctx context.Context, args ...interface{}) *XMes...
  function readXMessageSlice (line 2092) | func readXMessageSlice(rd *proto.Reader) ([]XMessage, error) {
  function readXMessage (line 2107) | func readXMessage(rd *proto.Reader) (XMessage, error) {
  function stringInterfaceMapParser (line 2150) | func stringInterfaceMapParser(rd *proto.Reader) (map[string]interface{},...
  type XStream (line 2175) | type XStream struct
  type XStreamSliceCmd (line 2180) | type XStreamSliceCmd struct
    method SetVal (line 2198) | func (cmd *XStreamSliceCmd) SetVal(val []XStream) {
    method Val (line 2202) | func (cmd *XStreamSliceCmd) Val() []XStream {
    method Result (line 2206) | func (cmd *XStreamSliceCmd) Result() ([]XStream, error) {
    method String (line 2210) | func (cmd *XStreamSliceCmd) String() string {
    method readReply (line 2214) | func (cmd *XStreamSliceCmd) readReply(rd *proto.Reader) error {
    method Clone (line 2246) | func (cmd *XStreamSliceCmd) Clone() Cmder {
  function NewXStreamSliceCmd (line 2188) | func NewXStreamSliceCmd(ctx context.Context, args ...interface{}) *XStre...
  type XPending (line 2278) | type XPending struct
  type XPendingCmd (line 2285) | type XPendingCmd struct
    method SetVal (line 2302) | func (cmd *XPendingCmd) SetVal(val *XPending) {
    method Val (line 2306) | func (cmd *XPendingCmd) Val() *XPending {
    method Result (line 2310) | func (cmd *XPendingCmd) Result() (*XPending, error) {
    method String (line 2314) | func (cmd *XPendingCmd) String() string {
    method readReply (line 2318) | func (cmd *XPendingCmd) readReply(rd *proto.Reader) error {
    method Clone (line 2360) | func (cmd *XPendingCmd) Clone() Cmder {
  function NewXPendingCmd (line 2292) | func NewXPendingCmd(ctx context.Context, args ...interface{}) *XPendingC...
  type XPendingExt (line 2383) | type XPendingExt struct
  type XPendingExtCmd (line 2390) | type XPendingExtCmd struct
    method SetVal (line 2407) | func (cmd *XPendingExtCmd) SetVal(val []XPendingExt) {
    method Val (line 2411) | func (cmd *XPendingExtCmd) Val() []XPendingExt {
    method Result (line 2415) | func (cmd *XPendingExtCmd) Result() ([]XPendingExt, error) {
    method String (line 2419) | func (cmd *XPendingExtCmd) String() string {
    method readReply (line 2423) | func (cmd *XPendingExtCmd) readReply(rd *proto.Reader) error {
    method Clone (line 2457) | func (cmd *XPendingExtCmd) Clone() Cmder {
  function NewXPendingExtCmd (line 2397) | func NewXPendingExtCmd(ctx context.Context, args ...interface{}) *XPendi...
  type XAutoClaimCmd (line 2471) | type XAutoClaimCmd struct
    method SetVal (line 2490) | func (cmd *XAutoClaimCmd) SetVal(val []XMessage, start string) {
    method Val (line 2495) | func (cmd *XAutoClaimCmd) Val() (messages []XMessage, start string) {
    method Result (line 2499) | func (cmd *XAutoClaimCmd) Result() (messages []XMessage, start string,...
    method String (line 2503) | func (cmd *XAutoClaimCmd) String() string {
    method readReply (line 2507) | func (cmd *XAutoClaimCmd) readReply(rd *proto.Reader) error {
    method Clone (line 2540) | func (cmd *XAutoClaimCmd) Clone() Cmder {
  function NewXAutoClaimCmd (line 2480) | func NewXAutoClaimCmd(ctx context.Context, args ...interface{}) *XAutoCl...
  type XAutoClaimJustIDCmd (line 2565) | type XAutoClaimJustIDCmd struct
    method SetVal (line 2584) | func (cmd *XAutoClaimJustIDCmd) SetVal(val []string, start string) {
    method Val (line 2589) | func (cmd *XAutoClaimJustIDCmd) Val() (ids []string, start string) {
    method Result (line 2593) | func (cmd *XAutoClaimJustIDCmd) Result() (ids []string, start string, ...
    method String (line 2597) | func (cmd *XAutoClaimJustIDCmd) String() string {
    method readReply (line 2601) | func (cmd *XAutoClaimJustIDCmd) readReply(rd *proto.Reader) error {
    method Clone (line 2642) | func (cmd *XAutoClaimJustIDCmd) Clone() Cmder {
  function NewXAutoClaimJustIDCmd (line 2574) | func NewXAutoClaimJustIDCmd(ctx context.Context, args ...interface{}) *X...
  type XInfoConsumersCmd (line 2657) | type XInfoConsumersCmd struct
    method SetVal (line 2681) | func (cmd *XInfoConsumersCmd) SetVal(val []XInfoConsumer) {
    method Val (line 2685) | func (cmd *XInfoConsumersCmd) Val() []XInfoConsumer {
    method Result (line 2689) | func (cmd *XInfoConsumersCmd) Result() ([]XInfoConsumer, error) {
    method String (line 2693) | func (cmd *XInfoConsumersCmd) String() string {
    method readReply (line 2697) | func (cmd *XInfoConsumersCmd) readReply(rd *proto.Reader) error {
    method Clone (line 2742) | func (cmd *XInfoConsumersCmd) Clone() Cmder {
  type XInfoConsumer (line 2662) | type XInfoConsumer struct
  function NewXInfoConsumersCmd (line 2671) | func NewXInfoConsumersCmd(ctx context.Context, stream string, group stri...
  type XInfoGroupsCmd (line 2756) | type XInfoGroupsCmd struct
    method SetVal (line 2784) | func (cmd *XInfoGroupsCmd) SetVal(val []XInfoGroup) {
    method Val (line 2788) | func (cmd *XInfoGroupsCmd) Val() []XInfoGroup {
    method Result (line 2792) | func (cmd *XInfoGroupsCmd) Result() ([]XInfoGroup, error) {
    method String (line 2796) | func (cmd *XInfoGroupsCmd) String() string {
    method readReply (line 2800) | func (cmd *XInfoGroupsCmd) readReply(rd *proto.Reader) error {
    method Clone (line 2868) | func (cmd *XInfoGroupsCmd) Clone() Cmder {
  type XInfoGroup (line 2761) | type XInfoGroup struct
  function NewXInfoGroupsCmd (line 2774) | func NewXInfoGroupsCmd(ctx context.Context, stream string) *XInfoGroupsC...
  type XInfoStreamCmd (line 2882) | type XInfoStreamCmd struct
    method SetVal (line 2919) | func (cmd *XInfoStreamCmd) SetVal(val *XInfoStream) {
    method Val (line 2923) | func (cmd *XInfoStreamCmd) Val() *XInfoStream {
    method Result (line 2927) | func (cmd *XInfoStreamCmd) Result() (*XInfoStream, error) {
    method String (line 2931) | func (cmd *XInfoStreamCmd) String() string {
    method readReply (line 2935) | func (cmd *XInfoStreamCmd) readReply(rd *proto.Reader) error {
    method Clone (line 3035) | func (cmd *XInfoStreamCmd) Clone() Cmder {
  type XInfoStream (line 2887) | type XInfoStream struct
  function NewXInfoStreamCmd (line 2909) | func NewXInfoStreamCmd(ctx context.Context, stream string) *XInfoStreamC...
  type XInfoStreamFullCmd (line 3076) | type XInfoStreamFullCmd struct
    method SetVal (line 3142) | func (cmd *XInfoStreamFullCmd) SetVal(val *XInfoStreamFull) {
    method Val (line 3146) | func (cmd *XInfoStreamFullCmd) Val() *XInfoStreamFull {
    method Result (line 3150) | func (cmd *XInfoStreamFullCmd) Result() (*XInfoStreamFull, error) {
    method String (line 3154) | func (cmd *XInfoStreamFullCmd) String() string {
    method readReply (line 3158) | func (cmd *XInfoStreamFullCmd) readReply(rd *proto.Reader) error {
    method Clone (line 3452) | func (cmd *XInfoStreamFullCmd) Clone() Cmder {
  type XInfoStreamFull (line 3081) | type XInfoStreamFull struct
  type XInfoStreamGroup (line 3099) | type XInfoStreamGroup struct
  type XInfoStreamGroupPending (line 3109) | type XInfoStreamGroupPending struct
  type XInfoStreamConsumer (line 3116) | type XInfoStreamConsumer struct
  type XInfoStreamConsumerPending (line 3124) | type XInfoStreamConsumerPending struct
  function NewXInfoStreamFullCmd (line 3132) | func NewXInfoStreamFullCmd(ctx context.Context, args ...interface{}) *XI...
  function readStreamGroups (line 3255) | func readStreamGroups(rd *proto.Reader) ([]XInfoStreamGroup, error) {
  function readXInfoStreamGroupPending (line 3324) | func readXInfoStreamGroupPending(rd *proto.Reader) ([]XInfoStreamGroupPe...
  function readXInfoStreamConsumers (line 3366) | func readXInfoStreamConsumers(rd *proto.Reader) ([]XInfoStreamConsumer, ...
  type ZSliceCmd (line 3493) | type ZSliceCmd struct
    method SetVal (line 3511) | func (cmd *ZSliceCmd) SetVal(val []Z) {
    method Val (line 3515) | func (cmd *ZSliceCmd) Val() []Z {
    method Result (line 3519) | func (cmd *ZSliceCmd) Result() ([]Z, error) {
    method String (line 3523) | func (cmd *ZSliceCmd) String() string {
    method readReply (line 3527) | func (cmd *ZSliceCmd) readReply(rd *proto.Reader) error { // nolint:dupl
    method Clone (line 3570) | func (cmd *ZSliceCmd) Clone() Cmder {
  function NewZSliceCmd (line 3501) | func NewZSliceCmd(ctx context.Context, args ...interface{}) *ZSliceCmd {
  type ZWithKeyCmd (line 3584) | type ZWithKeyCmd struct
    method SetVal (line 3602) | func (cmd *ZWithKeyCmd) SetVal(val *ZWithKey) {
    method Val (line 3606) | func (cmd *ZWithKeyCmd) Val() *ZWithKey {
    method Result (line 3610) | func (cmd *ZWithKeyCmd) Result() (*ZWithKey, error) {
    method String (line 3614) | func (cmd *ZWithKeyCmd) String() string {
    method readReply (line 3618) | func (cmd *ZWithKeyCmd) readReply(rd *proto.Reader) (err error) {
    method Clone (line 3637) | func (cmd *ZWithKeyCmd) Clone() Cmder {
  function NewZWithKeyCmd (line 3592) | func NewZWithKeyCmd(ctx context.Context, args ...interface{}) *ZWithKeyC...
  type ScanCmd (line 3656) | type ScanCmd struct
    method SetVal (line 3678) | func (cmd *ScanCmd) SetVal(page []string, cursor uint64) {
    method Val (line 3683) | func (cmd *ScanCmd) Val() (keys []string, cursor uint64) {
    method Result (line 3687) | func (cmd *ScanCmd) Result() (keys []string, cursor uint64, err error) {
    method String (line 3691) | func (cmd *ScanCmd) String() string {
    method readReply (line 3695) | func (cmd *ScanCmd) readReply(rd *proto.Reader) error {
    method Clone (line 3720) | func (cmd *ScanCmd) Clone() Cmder {
    method Iterator (line 3735) | func (cmd *ScanCmd) Iterator() *ScanIterator {
  function NewScanCmd (line 3667) | func NewScanCmd(ctx context.Context, process cmdable, args ...interface{...
  type ClusterNode (line 3743) | type ClusterNode struct
  type ClusterSlot (line 3749) | type ClusterSlot struct
  type ClusterSlotsCmd (line 3755) | type ClusterSlotsCmd struct
    method SetVal (line 3773) | func (cmd *ClusterSlotsCmd) SetVal(val []ClusterSlot) {
    method Val (line 3777) | func (cmd *ClusterSlotsCmd) Val() []ClusterSlot {
    method Result (line 3781) | func (cmd *ClusterSlotsCmd) Result() ([]ClusterSlot, error) {
    method String (line 3785) | func (cmd *ClusterSlotsCmd) String() string {
    method readReply (line 3789) | func (cmd *ClusterSlotsCmd) readReply(rd *proto.Reader) error {
    method Clone (line 3881) | func (cmd *ClusterSlotsCmd) Clone() Cmder {
  function NewClusterSlotsCmd (line 3763) | func NewClusterSlotsCmd(ctx context.Context, args ...interface{}) *Clust...
  type GeoLocation (line 3916) | type GeoLocation struct
  type GeoRadiusQuery (line 3923) | type GeoRadiusQuery struct
  type GeoLocationCmd (line 3940) | type GeoLocationCmd struct
    method SetVal (line 3996) | func (cmd *GeoLocationCmd) SetVal(locations []GeoLocation) {
    method Val (line 4000) | func (cmd *GeoLocationCmd) Val() []GeoLocation {
    method Result (line 4004) | func (cmd *GeoLocationCmd) Result() ([]GeoLocation, error) {
    method String (line 4008) | func (cmd *GeoLocationCmd) String() string {
    method readReply (line 4012) | func (cmd *GeoLocationCmd) readReply(rd *proto.Reader) error {
    method Clone (line 4062) | func (cmd *GeoLocationCmd) Clone() Cmder {
  function NewGeoLocationCmd (line 3949) | func NewGeoLocationCmd(ctx context.Context, q *GeoRadiusQuery, args ...i...
  function geoLocationArgs (line 3960) | func geoLocationArgs(q *GeoRadiusQuery, args ...interface{}) []interface...
  type GeoSearchQuery (line 4093) | type GeoSearchQuery struct
  type GeoSearchLocationQuery (line 4117) | type GeoSearchLocationQuery struct
  type GeoSearchStoreQuery (line 4125) | type GeoSearchStoreQuery struct
  function geoSearchLocationArgs (line 4134) | func geoSearchLocationArgs(q *GeoSearchLocationQuery, args []interface{}...
  function geoSearchArgs (line 4150) | func geoSearchArgs(q *GeoSearchQuery, args []interface{}) []interface{} {
  type GeoSearchLocationCmd (line 4183) | type GeoSearchLocationCmd struct
    method SetVal (line 4205) | func (cmd *GeoSearchLocationCmd) SetVal(val []GeoLocation) {
    method Val (line 4209) | func (cmd *GeoSearchLocationCmd) Val() []GeoLocation {
    method Result (line 4213) | func (cmd *GeoSearchLocationCmd) Result() ([]GeoLocation, error) {
    method String (line 4217) | func (cmd *GeoSearchLocationCmd) String() string {
    method readReply (line 4221) | func (cmd *GeoSearchLocationCmd) readReply(rd *proto.Reader) error {
    method Clone (line 4272) | func (cmd *GeoSearchLocationCmd) Clone() Cmder {
  function NewGeoSearchLocationCmd (line 4192) | func NewGeoSearchLocationCmd(
  type GeoPos (line 4308) | type GeoPos struct
  type GeoPosCmd (line 4312) | type GeoPosCmd struct
    method SetVal (line 4330) | func (cmd *GeoPosCmd) SetVal(val []*GeoPos) {
    method Val (line 4334) | func (cmd *GeoPosCmd) Val() []*GeoPos {
    method Result (line 4338) | func (cmd *GeoPosCmd) Result() ([]*GeoPos, error) {
    method String (line 4342) | func (cmd *GeoPosCmd) String() string {
    method readReply (line 4346) | func (cmd *GeoPosCmd) readReply(rd *proto.Reader) error {
    method Clone (line 4381) | func (cmd *GeoPosCmd) Clone() Cmder {
  function NewGeoPosCmd (line 4320) | func NewGeoPosCmd(ctx context.Context, args ...interface{}) *GeoPosCmd {
  type CommandInfo (line 4402) | type CommandInfo struct
  type CommandsInfoCmd (line 4414) | type CommandsInfoCmd struct
    method SetVal (line 4432) | func (cmd *CommandsInfoCmd) SetVal(val map[string]*CommandInfo) {
    method Val (line 4436) | func (cmd *CommandsInfoCmd) Val() map[string]*CommandInfo {
    method Result (line 4440) | func (cmd *CommandsInfoCmd) Result() (map[string]*CommandInfo, error) {
    method String (line 4444) | func (cmd *CommandsInfoCmd) String() string {
    method readReply (line 4448) | func (cmd *CommandsInfoCmd) readReply(rd *proto.Reader) error {
    method Clone (line 4580) | func (cmd *CommandsInfoCmd) Clone() Cmder {
  function NewCommandsInfoCmd (line 4422) | func NewCommandsInfoCmd(ctx context.Context, args ...interface{}) *Comma...
  type cmdsInfoCache (line 4615) | type cmdsInfoCache struct
    method Get (line 4629) | func (c *cmdsInfoCache) Get(ctx context.Context) (map[string]*CommandI...
    method Refresh (line 4652) | func (c *cmdsInfoCache) Refresh() {
  function newCmdsInfoCache (line 4623) | func newCmdsInfoCache(fn func(ctx context.Context) (map[string]*CommandI...
  constant requestPolicy (line 4660) | requestPolicy = "request_policy"
  constant responsePolicy (line 4661) | responsePolicy = "response_policy"
  function parseCommandPolicies (line 4663) | func parseCommandPolicies(commandInfoTips map[string]string, firstKeyPos...
  type SlowLog (line 4692) | type SlowLog struct
  type SlowLogCmd (line 4703) | type SlowLogCmd struct
    method SetVal (line 4721) | func (cmd *SlowLogCmd) SetVal(val []SlowLog) {
    method Val (line 4725) | func (cmd *SlowLogCmd) Val() []SlowLog {
    method Result (line 4729) | func (cmd *SlowLogCmd) Result() ([]SlowLog, error) {
    method String (line 4733) | func (cmd *SlowLogCmd) String() string {
    method readReply (line 4737) | func (cmd *SlowLogCmd) readReply(rd *proto.Reader) error {
    method Clone (line 4801) | func (cmd *SlowLogCmd) Clone() Cmder {
  function NewSlowLogCmd (line 4711) | func NewSlowLogCmd(ctx context.Context, args ...interface{}) *SlowLogCmd {
  type Latency (line 4827) | type Latency struct
  type LatencyCmd (line 4834) | type LatencyCmd struct
    method SetVal (line 4850) | func (cmd *LatencyCmd) SetVal(val []Latency) {
    method Val (line 4854) | func (cmd *LatencyCmd) Val() []Latency {
    method Result (line 4858) | func (cmd *LatencyCmd) Result() ([]Latency, error) {
    method String (line 4862) | func (cmd *LatencyCmd) String() string {
    method readReply (line 4866) | func (cmd *LatencyCmd) readReply(rd *proto.Reader) error {
    method Clone (line 4902) | func (cmd *LatencyCmd) Clone() Cmder {
  function NewLatencyCmd (line 4841) | func NewLatencyCmd(ctx context.Context, args ...interface{}) *LatencyCmd {
  type HotKeysSlotRange (line 4918) | type HotKeysSlotRange
  type HotKeysKeyEntry (line 4921) | type HotKeysKeyEntry struct
  type HotKeysResult (line 4928) | type HotKeysResult struct
  type HotKeysCmd (line 4947) | type HotKeysCmd struct
    method SetVal (line 4965) | func (cmd *HotKeysCmd) SetVal(val *HotKeysResult) {
    method Val (line 4969) | func (cmd *HotKeysCmd) Val() *HotKeysResult {
    method Result (line 4973) | func (cmd *HotKeysCmd) Result() (*HotKeysResult, error) {
    method String (line 4977) | func (cmd *HotKeysCmd) String() string {
    method readReply (line 4981) | func (cmd *HotKeysCmd) readReply(rd *proto.Reader) error {
    method Clone (line 5111) | func (cmd *HotKeysCmd) Clone() Cmder {
  function NewHotKeysCmd (line 4955) | func NewHotKeysCmd(ctx context.Context, args ...interface{}) *HotKeysCmd {
  function parseHotKeysKeyEntries (line 5095) | func parseHotKeysKeyEntries(v []interface{}) []HotKeysKeyEntry {
  type MapStringInterfaceCmd (line 5153) | type MapStringInterfaceCmd struct
    method SetVal (line 5171) | func (cmd *MapStringInterfaceCmd) SetVal(val map[string]interface{}) {
    method Val (line 5175) | func (cmd *MapStringInterfaceCmd) Val() map[string]interface{} {
    method Result (line 5179) | func (cmd *MapStringInterfaceCmd) Result() (map[string]interface{}, er...
    method String (line 5183) | func (cmd *MapStringInterfaceCmd) String() string {
    method readReply (line 5187) | func (cmd *MapStringInterfaceCmd) readReply(rd *proto.Reader) error {
    method Clone (line 5216) | func (cmd *MapStringInterfaceCmd) Clone() Cmder {
  function NewMapStringInterfaceCmd (line 5161) | func NewMapStringInterfaceCmd(ctx context.Context, args ...interface{}) ...
  type MapStringStringSliceCmd (line 5232) | type MapStringStringSliceCmd struct
    method SetVal (line 5250) | func (cmd *MapStringStringSliceCmd) SetVal(val []map[string]string) {
    method Val (line 5254) | func (cmd *MapStringStringSliceCmd) Val() []map[string]string {
    method Result (line 5258) | func (cmd *MapStringStringSliceCmd) Result() ([]map[string]string, err...
    method String (line 5262) | func (cmd *MapStringStringSliceCmd) String() string {
    method readReply (line 5266) | func (cmd *MapStringStringSliceCmd) readReply(rd *proto.Reader) error {
    method Clone (line 5295) | func (cmd *MapStringStringSliceCmd) Clone() Cmder {
  function NewMapStringStringSliceCmd (line 5240) | func NewMapStringStringSliceCmd(ctx context.Context, args ...interface{}...
  type MapMapStringInterfaceCmd (line 5317) | type MapMapStringInterfaceCmd struct
    method String (line 5332) | func (cmd *MapMapStringInterfaceCmd) String() string {
    method SetVal (line 5336) | func (cmd *MapMapStringInterfaceCmd) SetVal(val map[string]interface{}) {
    method Result (line 5340) | func (cmd *MapMapStringInterfaceCmd) Result() (map[string]interface{},...
    method Val (line 5344) | func (cmd *MapMapStringInterfaceCmd) Val() map[string]interface{} {
    method readReply (line 5349) | func (cmd *MapMapStringInterfaceCmd) readReply(rd *proto.Reader) (err ...
    method Clone (line 5393) | func (cmd *MapMapStringInterfaceCmd) Clone() Cmder {
  function NewMapMapStringInterfaceCmd (line 5322) | func NewMapMapStringInterfaceCmd(ctx context.Context, args ...interface{...
  type MapStringInterfaceSliceCmd (line 5409) | type MapStringInterfaceSliceCmd struct
    method SetVal (line 5427) | func (cmd *MapStringInterfaceSliceCmd) SetVal(val []map[string]interfa...
    method Val (line 5431) | func (cmd *MapStringInterfaceSliceCmd) Val() []map[string]interface{} {
    method Result (line 5435) | func (cmd *MapStringInterfaceSliceCmd) Result() ([]map[string]interfac...
    method String (line 5439) | func (cmd *MapStringInterfaceSliceCmd) String() string {
    method readReply (line 5443) | func (cmd *MapStringInterfaceSliceCmd) readReply(rd *proto.Reader) err...
    method Clone (line 5473) | func (cmd *MapStringInterfaceSliceCmd) Clone() Cmder {
  function NewMapStringInterfaceSliceCmd (line 5417) | func NewMapStringInterfaceSliceCmd(ctx context.Context, args ...interfac...
  type KeyValuesCmd (line 5494) | type KeyValuesCmd struct
    method SetVal (line 5513) | func (cmd *KeyValuesCmd) SetVal(key string, val []string) {
    method Val (line 5518) | func (cmd *KeyValuesCmd) Val() (string, []string) {
    method Result (line 5522) | func (cmd *KeyValuesCmd) Result() (string, []string, error) {
    method String (line 5526) | func (cmd *KeyValuesCmd) String() string {
    method readReply (line 5530) | func (cmd *KeyValuesCmd) readReply(rd *proto.Reader) (err error) {
    method Clone (line 5555) | func (cmd *KeyValuesCmd) Clone() Cmder {
  function NewKeyValuesCmd (line 5503) | func NewKeyValuesCmd(ctx context.Context, args ...interface{}) *KeyValue...
  type ZSliceWithKeyCmd (line 5570) | type ZSliceWithKeyCmd struct
    method SetVal (line 5589) | func (cmd *ZSliceWithKeyCmd) SetVal(key string, val []Z) {
    method Val (line 5594) | func (cmd *ZSliceWithKeyCmd) Val() (string, []Z) {
    method Result (line 5598) | func (cmd *ZSliceWithKeyCmd) Result() (string, []Z, error) {
    method String (line 5602) | func (cmd *ZSliceWithKeyCmd) String() string {
    method readReply (line 5606) | func (cmd *ZSliceWithKeyCmd) readReply(rd *proto.Reader) (err error) {
    method Clone (line 5652) | func (cmd *ZSliceWithKeyCmd) Clone() Cmder {
  function NewZSliceWithKeyCmd (line 5579) | func NewZSliceWithKeyCmd(ctx context.Context, args ...interface{}) *ZSli...
  type Function (line 5665) | type Function struct
  type Library (line 5671) | type Library struct
  type FunctionListCmd (line 5678) | type FunctionListCmd struct
    method SetVal (line 5696) | func (cmd *FunctionListCmd) SetVal(val []Library) {
    method String (line 5700) | func (cmd *FunctionListCmd) String() string {
    method Val (line 5704) | func (cmd *FunctionListCmd) Val() []Library {
    method Result (line 5708) | func (cmd *FunctionListCmd) Result() ([]Library, error) {
    method First (line 5712) | func (cmd *FunctionListCmd) First() (*Library, error) {
    method readReply (line 5722) | func (cmd *FunctionListCmd) readReply(rd *proto.Reader) (err error) {
    method readFunctions (line 5766) | func (cmd *FunctionListCmd) readFunctions(rd *proto.Reader) ([]Functio...
    method Clone (line 5818) | func (cmd *FunctionListCmd) Clone() Cmder {
  function NewFunctionListCmd (line 5686) | func NewFunctionListCmd(ctx context.Context, args ...interface{}) *Funct...
  type FunctionStats (line 5859) | type FunctionStats struct
    method Running (line 5866) | func (fs *FunctionStats) Running() bool {
    method RunningScript (line 5870) | func (fs *FunctionStats) RunningScript() (RunningScript, bool) {
    method AllRunningScripts (line 5876) | func (fs *FunctionStats) AllRunningScripts() []RunningScript {
  type RunningScript (line 5880) | type RunningScript struct
  type Engine (line 5886) | type Engine struct
  type FunctionStatsCmd (line 5892) | type FunctionStatsCmd struct
    method SetVal (line 5909) | func (cmd *FunctionStatsCmd) SetVal(val FunctionStats) {
    method String (line 5913) | func (cmd *FunctionStatsCmd) String() string {
    method Val (line 5917) | func (cmd *FunctionStatsCmd) Val() FunctionStats {
    method Result (line 5921) | func (cmd *FunctionStatsCmd) Result() (FunctionStats, error) {
    method readReply (line 5925) | func (cmd *FunctionStatsCmd) readReply(rd *proto.Reader) (err error) {
    method readRunningScript (line 5959) | func (cmd *FunctionStatsCmd) readRunningScript(rd *proto.Reader) (Runn...
    method readEngines (line 5994) | func (cmd *FunctionStatsCmd) readEngines(rd *proto.Reader) ([]Engine, ...
    method readDuration (line 6031) | func (cmd *FunctionStatsCmd) readDuration(rd *proto.Reader) (time.Dura...
    method readCommand (line 6039) | func (cmd *FunctionStatsCmd) readCommand(rd *proto.Reader) ([]string, ...
    method readRunningScripts (line 6057) | func (cmd *FunctionStatsCmd) readRunningScripts(rd *proto.Reader) ([]R...
    method Clone (line 6075) | func (cmd *FunctionStatsCmd) Clone() Cmder {
  function NewFunctionStatsCmd (line 5899) | func NewFunctionStatsCmd(ctx context.Context, args ...interface{}) *Func...
  type LCSQuery (line 6106) | type LCSQuery struct
  type LCSMatch (line 6116) | type LCSMatch struct
  type LCSMatchedPosition (line 6122) | type LCSMatchedPosition struct
  type LCSPosition (line 6130) | type LCSPosition struct
  type LCSCmd (line 6135) | type LCSCmd struct
    method SetVal (line 6174) | func (cmd *LCSCmd) SetVal(val *LCSMatch) {
    method String (line 6178) | func (cmd *LCSCmd) String() string {
    method Val (line 6182) | func (cmd *LCSCmd) Val() *LCSMatch {
    method Result (line 6186) | func (cmd *LCSCmd) Result() (*LCSMatch, error) {
    method readReply (line 6190) | func (cmd *LCSCmd) readReply(rd *proto.Reader) (err error) {
    method readMatchedPositions (line 6235) | func (cmd *LCSCmd) readMatchedPositions(rd *proto.Reader) ([]LCSMatche...
    method readPosition (line 6266) | func (cmd *LCSCmd) readPosition(rd *proto.Reader) (pos LCSPosition, er...
    method Clone (line 6280) | func (cmd *LCSCmd) Clone() Cmder {
  function NewLCSCmd (line 6145) | func NewLCSCmd(ctx context.Context, q *LCSQuery) *LCSCmd {
  type KeyFlags (line 6301) | type KeyFlags struct
  type KeyFlagsCmd (line 6306) | type KeyFlagsCmd struct
    method SetVal (line 6324) | func (cmd *KeyFlagsCmd) SetVal(val []KeyFlags) {
    method Val (line 6328) | func (cmd *KeyFlagsCmd) Val() []KeyFlags {
    method Result (line 6332) | func (cmd *KeyFlagsCmd) Result() ([]KeyFlags, error) {
    method String (line 6336) | func (cmd *KeyFlagsCmd) String() string {
    method readReply (line 6340) | func (cmd *KeyFlagsCmd) readReply(rd *proto.Reader) error {
    method Clone (line 6378) | func (cmd *KeyFlagsCmd) Clone() Cmder {
  function NewKeyFlagsCmd (line 6314) | func NewKeyFlagsCmd(ctx context.Context, args ...interface{}) *KeyFlagsC...
  type ClusterLink (line 6400) | type ClusterLink struct
  type ClusterLinksCmd (line 6409) | type ClusterLinksCmd struct
    method SetVal (line 6427) | func (cmd *ClusterLinksCmd) SetVal(val []ClusterLink) {
    method Val (line 6431) | func (cmd *ClusterLinksCmd) Val() []ClusterLink {
    method Result (line 6435) | func (cmd *ClusterLinksCmd) Result() ([]ClusterLink, error) {
    method String (line 6439) | func (cmd *ClusterLinksCmd) String() string {
    method readReply (line 6443) | func (cmd *ClusterLinksCmd) readReply(rd *proto.Reader) error {
    method Clone (line 6488) | func (cmd *ClusterLinksCmd) Clone() Cmder {
  function NewClusterLinksCmd (line 6417) | func NewClusterLinksCmd(ctx context.Context, args ...interface{}) *Clust...
  type SlotRange (line 6502) | type SlotRange struct
  type Node (line 6507) | type Node struct
  type ClusterShard (line 6519) | type ClusterShard struct
  type ClusterShardsCmd (line 6524) | type ClusterShardsCmd struct
    method SetVal (line 6542) | func (cmd *ClusterShardsCmd) SetVal(val []ClusterShard) {
    method Val (line 6546) | func (cmd *ClusterShardsCmd) Val() []ClusterShard {
    method Result (line 6550) | func (cmd *ClusterShardsCmd) Result() ([]ClusterShard, error) {
    method String (line 6554) | func (cmd *ClusterShardsCmd) String() string {
    method readReply (line 6558) | func (cmd *ClusterShardsCmd) readReply(rd *proto.Reader) error {
    method Clone (line 6651) | func (cmd *ClusterShardsCmd) Clone() Cmder {
  function NewClusterShardsCmd (line 6532) | func NewClusterShardsCmd(ctx context.Context, args ...interface{}) *Clus...
  type RankScore (line 6675) | type RankScore struct
  type RankWithScoreCmd (line 6680) | type RankWithScoreCmd struct
    method SetVal (line 6698) | func (cmd *RankWithScoreCmd) SetVal(val RankScore) {
    method Val (line 6702) | func (cmd *RankWithScoreCmd) Val() RankScore {
    method Result (line 6706) | func (cmd *RankWithScoreCmd) Result() (RankScore, error) {
    method String (line 6710) | func (cmd *RankWithScoreCmd) String() string {
    method readReply (line 6714) | func (cmd *RankWithScoreCmd) readReply(rd *proto.Reader) error {
    method Clone (line 6734) | func (cmd *RankWithScoreCmd) Clone() Cmder {
  function NewRankWithScoreCmd (line 6688) | func NewRankWithScoreCmd(ctx context.Context, args ...interface{}) *Rank...
  type ClientFlags (line 6744) | type ClientFlags
  constant ClientSlave (line 6747) | ClientSlave            ClientFlags = 1 << 0
  constant ClientMaster (line 6748) | ClientMaster           ClientFlags = 1 << 1
  constant ClientMonitor (line 6749) | ClientMonitor          ClientFlags = 1 << 2
  constant ClientMulti (line 6750) | ClientMulti            ClientFlags = 1 << 3
  constant ClientBlocked (line 6751) | ClientBlocked          ClientFlags = 1 << 4
  constant ClientDirtyCAS (line 6752) | ClientDirtyCAS         ClientFlags = 1 << 5
  constant ClientCloseAfterReply (line 6753) | ClientCloseAfterReply  ClientFlags = 1 << 6
  constant ClientUnBlocked (line 6754) | ClientUnBlocked        ClientFlags = 1 << 7
  constant ClientScript (line 6755) | ClientScript           ClientFlags = 1 << 8
  constant ClientAsking (line 6756) | ClientAsking           ClientFlags = 1 << 9
  constant ClientCloseASAP (line 6757) | ClientCloseASAP        ClientFlags = 1 << 10
  constant ClientUnixSocket (line 6758) | ClientUnixSocket       ClientFlags = 1 << 11
  constant ClientDirtyExec (line 6759) | ClientDirtyExec        ClientFlags = 1 << 12
  constant ClientMasterForceReply (line 6760) | ClientMasterForceReply ClientFlags = 1 << 13
  constant ClientForceAOF (line 6761) | ClientForceAOF         ClientFlags = 1 << 14
  constant ClientForceRepl (line 6762) | ClientForceRepl        ClientFlags = 1 << 15
  constant ClientPrePSync (line 6763) | ClientPrePSync         ClientFlags = 1 << 16
  constant ClientReadOnly (line 6764) | ClientReadOnly         ClientFlags = 1 << 17
  constant ClientPubSub (line 6765) | ClientPubSub           ClientFlags = 1 << 18
  constant ClientPreventAOFProp (line 6766) | ClientPreventAOFProp   ClientFlags = 1 << 19
  constant ClientPreventReplProp (line 6767) | ClientPreventReplProp  ClientFlags = 1 << 20
  constant ClientPreventProp (line 6768) | ClientPreventProp      ClientFlags = ClientPreventAOFProp | ClientPreven...
  constant ClientPendingWrite (line 6769) | ClientPendingWrite     ClientFlags = 1 << 21
  constant ClientReplyOff (line 6770) | ClientReplyOff         ClientFlags = 1 << 22
  constant ClientReplySkipNext (line 6771) | ClientReplySkipNext    ClientFlags = 1 << 23
  constant ClientReplySkip (line 6772) | ClientReplySkip        ClientFlags = 1 << 24
  constant ClientLuaDebug (line 6773) | ClientLuaDebug         ClientFlags = 1 << 25
  constant ClientLuaDebugSync (line 6774) | ClientLuaDebugSync     ClientFlags = 1 << 26
  constant ClientModule (line 6775) | ClientModule           ClientFlags = 1 << 27
  constant ClientProtected (line 6776) | ClientProtected        ClientFlags = 1 << 28
  constant ClientExecutingCommand (line 6777) | ClientExecutingCommand ClientFlags = 1 << 29
  constant ClientPendingCommand (line 6781) | ClientPendingCommand      ClientFlags = 1 << 30
  constant ClientTracking (line 6782) | ClientTracking            ClientFlags = 1 << 31
  constant ClientTrackingBrokenRedir (line 6783) | ClientTrackingBrokenRedir ClientFlags = 1 << 32
  constant ClientTrackingBCAST (line 6784) | ClientTrackingBCAST       ClientFlags = 1 << 33
  constant ClientTrackingOptIn (line 6785) | ClientTrackingOptIn       ClientFlags = 1 << 34
  constant ClientTrackingOptOut (line 6786) | ClientTrackingOptOut      ClientFlags = 1 << 35
  constant ClientTrackingCaching (line 6787) | ClientTrackingCaching     ClientFlags = 1 << 36
  constant ClientTrackingNoLoop (line 6788) | ClientTrackingNoLoop      ClientFlags = 1 << 37
  constant ClientInTimeoutTable (line 6789) | ClientInTimeoutTable      ClientFlags = 1 << 38
  constant ClientProtocolError (line 6790) | ClientProtocolError       ClientFlags = 1 << 39
  constant ClientCloseAfterCommand (line 6791) | ClientCloseAfterCommand   ClientFlags = 1 << 40
  constant ClientDenyBlocking (line 6792) | ClientDenyBlocking        ClientFlags = 1 << 41
  constant ClientReplRDBOnly (line 6793) | ClientReplRDBOnly         ClientFlags = 1 << 42
  constant ClientNoEvict (line 6794) | ClientNoEvict             ClientFlags = 1 << 43
  constant ClientAllowOOM (line 6795) | ClientAllowOOM            ClientFlags = 1 << 44
  constant ClientNoTouch (line 6796) | ClientNoTouch             ClientFlags = 1 << 45
  constant ClientPushing (line 6797) | ClientPushing             ClientFlags = 1 << 46
  type ClientInfo (line 6801) | type ClientInfo struct
  type ClientInfoCmd (line 6839) | type ClientInfoCmd struct
    method SetVal (line 6857) | func (cmd *ClientInfoCmd) SetVal(val *ClientInfo) {
    method String (line 6861) | func (cmd *ClientInfoCmd) String() string {
    method Val (line 6865) | func (cmd *ClientInfoCmd) Val() *ClientInfo {
    method Result (line 6869) | func (cmd *ClientInfoCmd) Result() (*ClientInfo, error) {
    method readReply (line 6873) | func (cmd *ClientInfoCmd) readReply(rd *proto.Reader) (err error) {
    method Clone (line 7029) | func (cmd *ClientInfoCmd) Clone() Cmder {
  function NewClientInfoCmd (line 6847) | func NewClientInfoCmd(ctx context.Context, args ...interface{}) *ClientI...
  function parseClientInfo (line 6888) | func parseClientInfo(txt string) (info *ClientInfo, err error) {
  type ACLLogEntry (line 7075) | type ACLLogEntry struct
  type ACLLogCmd (line 7088) | type ACLLogCmd struct
    method SetVal (line 7106) | func (cmd *ACLLogCmd) SetVal(val []*ACLLogEntry) {
    method Val (line 7110) | func (cmd *ACLLogCmd) Val() []*ACLLogEntry {
    method Result (line 7114) | func (cmd *ACLLogCmd) Result() ([]*ACLLogEntry, error) {
    method String (line 7118) | func (cmd *ACLLogCmd) String() string {
    method readReply (line 7122) | func (cmd *ACLLogCmd) readReply(rd *proto.Reader) error {
    method Clone (line 7183) | func (cmd *ACLLogCmd) Clone() Cmder {
  function NewACLLogCmd (line 7096) | func NewACLLogCmd(ctx context.Context, args ...interface{}) *ACLLogCmd {
  type LibraryInfo (line 7247) | type LibraryInfo struct
  function WithLibraryName (line 7253) | func WithLibraryName(libName string) LibraryInfo {
  function WithLibraryVersion (line 7258) | func WithLibraryVersion(libVer string) LibraryInfo {
  type InfoCmd (line 7264) | type InfoCmd struct
    method SetVal (line 7281) | func (cmd *InfoCmd) SetVal(val map[string]map[string]string) {
    method Val (line 7285) | func (cmd *InfoCmd) Val() map[string]map[string]string {
    method Result (line 7289) | func (cmd *InfoCmd) Result() (map[string]map[string]string, error) {
    method String (line 7293) | func (cmd *InfoCmd) String() string {
    method readReply (line 7297) | func (cmd *InfoCmd) readReply(rd *proto.Reader) error {
    method Item (line 7332) | func (cmd *InfoCmd) Item(section, key string) string {
    method Clone (line 7342) | func (cmd *InfoCmd) Clone() Cmder {
  function NewInfoCmd (line 7271) | func NewInfoCmd(ctx context.Context, args ...interface{}) *InfoCmd {
  type MonitorStatus (line 7361) | type MonitorStatus
  constant monitorStatusIdle (line 7364) | monitorStatusIdle MonitorStatus = iota
  constant monitorStatusStart (line 7365) | monitorStatusStart
  constant monitorStatusStop (line 7366) | monitorStatusStop
  type MonitorCmd (line 7369) | type MonitorCmd struct
    method String (line 7389) | func (cmd *MonitorCmd) String() string {
    method readReply (line 7393) | func (cmd *MonitorCmd) readReply(rd *proto.Reader) error {
    method readMonitor (line 7412) | func (cmd *MonitorCmd) readMonitor(rd *proto.Reader, cancel context.Ca...
    method Start (line 7435) | func (cmd *MonitorCmd) Start() {
    method Stop (line 7441) | func (cmd *MonitorCmd) Stop() {
    method Clone (line 7511) | func (cmd *MonitorCmd) Clone() Cmder {
  function newMonitorCmd (line 7376) | func newMonitorCmd(ctx context.Context, ch chan string) *MonitorCmd {
  type VectorScoreSliceCmd (line 7447) | type VectorScoreSliceCmd struct
    method SetVal (line 7464) | func (cmd *VectorScoreSliceCmd) SetVal(val []VectorScore) {
    method Val (line 7468) | func (cmd *VectorScoreSliceCmd) Val() []VectorScore {
    method Result (line 7472) | func (cmd *VectorScoreSliceCmd) Result() ([]VectorScore, error) {
    method String (line 7476) | func (cmd *VectorScoreSliceCmd) String() string {
    method readReply (line 7480) | func (cmd *VectorScoreSliceCmd) readReply(rd *proto.Reader) error {
    method Clone (line 7504) | func (cmd *VectorScoreSliceCmd) Clone() Cmder {
  function NewVectorInfoSliceCmd (line 7455) | func NewVectorInfoSliceCmd(ctx context.Context, args ...any) *VectorScor...
  function ExtractCommandValue (line 7518) | func ExtractCommandValue(cmd interface{}) (interface{}, error) {

FILE: command_digest_test.go
  function TestDigestCmd (line 11) | func TestDigestCmd(t *testing.T) {
  function TestDigestCmdResult (line 85) | func TestDigestCmdResult(t *testing.T) {
  type mockConn (line 101) | type mockConn struct
    method Read (line 110) | func (c *mockConn) Read(p []byte) (n int, err error) {
  function newMockConn (line 106) | func newMockConn(data []byte) *mockConn {

FILE: command_policy_resolver.go
  type CommandInfoResolveFunc (line 159) | type CommandInfoResolveFunc
  type commandInfoResolver (line 161) | type commandInfoResolver struct
    method GetCommandPolicy (line 190) | func (r *commandInfoResolver) GetCommandPolicy(ctx context.Context, cm...
    method SetFallbackResolver (line 207) | func (r *commandInfoResolver) SetFallbackResolver(fallbackResolver *co...
  function NewCommandInfoResolver (line 166) | func NewCommandInfoResolver(resolveFunc CommandInfoResolveFunc) *command...
  function NewDefaultCommandPolicyResolver (line 172) | func NewDefaultCommandPolicyResolver() *commandInfoResolver {

FILE: command_recorder_test.go
  type commandRecorder (line 12) | type commandRecorder struct
    method Record (line 27) | func (r *commandRecorder) Record(cmd string) {
    method LastCommands (line 39) | func (r *commandRecorder) LastCommands() []string {
    method Contains (line 46) | func (r *commandRecorder) Contains(cmd string) bool {
    method Hook (line 59) | func (r *commandRecorder) Hook() redis.Hook {
  function newCommandRecorder (line 19) | func newCommandRecorder(maxSize int) *commandRecorder {
  type commandHook (line 64) | type commandHook struct
    method DialHook (line 68) | func (h *commandHook) DialHook(next redis.DialHook) redis.DialHook {
    method ProcessHook (line 72) | func (h *commandHook) ProcessHook(next redis.ProcessHook) redis.Proces...
    method ProcessPipelineHook (line 79) | func (h *commandHook) ProcessPipelineHook(next redis.ProcessPipelineHo...

FILE: commands.go
  constant KeepTTL (line 23) | KeepTTL = -1
  function usePrecise (line 25) | func usePrecise(dur time.Duration) bool {
  function formatMs (line 29) | func formatMs(ctx context.Context, dur time.Duration) int64 {
  function formatSec (line 41) | func formatSec(ctx context.Context, dur time.Duration) int64 {
  function appendArgs (line 53) | func appendArgs(dst, src []interface{}) []interface{} {
  function appendArg (line 67) | func appendArg(dst []interface{}, arg interface{}) []interface{} {
  function appendStructField (line 111) | func appendStructField(dst []interface{}, v reflect.Value) []interface{} {
  function omitEmpty (line 138) | func omitEmpty(opt string) bool {
  function isEmptyValue (line 149) | func isEmptyValue(v reflect.Value) bool {
  type Cmdable (line 173) | type Cmdable interface
  type StatefulCmdable (line 251) | type StatefulCmdable interface
  type cmdable (line 270) | type cmdable
    method Wait (line 291) | func (c cmdable) Wait(ctx context.Context, numSlaves int, timeout time...
    method WaitAOF (line 298) | func (c cmdable) WaitAOF(ctx context.Context, numLocal, numSlaves int,...
    method Command (line 377) | func (c cmdable) Command(ctx context.Context) *CommandsInfoCmd {
    method CommandList (line 390) | func (c cmdable) CommandList(ctx context.Context, filter *FilterBy) *S...
    method CommandGetKeys (line 407) | func (c cmdable) CommandGetKeys(ctx context.Context, commands ...inter...
    method CommandGetKeysAndFlags (line 417) | func (c cmdable) CommandGetKeysAndFlags(ctx context.Context, commands ...
    method ClientGetName (line 428) | func (c cmdable) ClientGetName(ctx context.Context) *StringCmd {
    method Echo (line 434) | func (c cmdable) Echo(ctx context.Context, message interface{}) *Strin...
    method Ping (line 440) | func (c cmdable) Ping(ctx context.Context) *StatusCmd {
    method Do (line 446) | func (c cmdable) Do(ctx context.Context, args ...interface{}) *Cmd {
    method Quit (line 455) | func (c cmdable) Quit(_ context.Context) *StatusCmd {
    method BgRewriteAOF (line 461) | func (c cmdable) BgRewriteAOF(ctx context.Context) *StatusCmd {
    method BgSave (line 467) | func (c cmdable) BgSave(ctx context.Context) *StatusCmd {
    method ClientKill (line 473) | func (c cmdable) ClientKill(ctx context.Context, ipPort string) *Statu...
    method ClientKillByFilter (line 482) | func (c cmdable) ClientKillByFilter(ctx context.Context, keys ...strin...
    method ClientList (line 494) | func (c cmdable) ClientList(ctx context.Context) *StringCmd {
    method ClientPause (line 500) | func (c cmdable) ClientPause(ctx context.Context, dur time.Duration) *...
    method ClientUnpause (line 506) | func (c cmdable) ClientUnpause(ctx context.Context) *BoolCmd {
    method ClientID (line 512) | func (c cmdable) ClientID(ctx context.Context) *IntCmd {
    method ClientUnblock (line 518) | func (c cmdable) ClientUnblock(ctx context.Context, id int64) *IntCmd {
    method ClientUnblockWithError (line 524) | func (c cmdable) ClientUnblockWithError(ctx context.Context, id int64)...
    method ClientInfo (line 530) | func (c cmdable) ClientInfo(ctx context.Context) *ClientInfoCmd {
    method ClientMaintNotifications (line 538) | func (c cmdable) ClientMaintNotifications(ctx context.Context, enabled...
    method ConfigGet (line 555) | func (c cmdable) ConfigGet(ctx context.Context, parameter string) *Map...
    method ConfigResetStat (line 561) | func (c cmdable) ConfigResetStat(ctx context.Context) *StatusCmd {
    method ConfigSet (line 567) | func (c cmdable) ConfigSet(ctx context.Context, parameter, value strin...
    method ConfigRewrite (line 573) | func (c cmdable) ConfigRewrite(ctx context.Context) *StatusCmd {
    method DBSize (line 579) | func (c cmdable) DBSize(ctx context.Context) *IntCmd {
    method FlushAll (line 585) | func (c cmdable) FlushAll(ctx context.Context) *StatusCmd {
    method FlushAllAsync (line 591) | func (c cmdable) FlushAllAsync(ctx context.Context) *StatusCmd {
    method FlushDB (line 597) | func (c cmdable) FlushDB(ctx context.Context) *StatusCmd {
    method FlushDBAsync (line 603) | func (c cmdable) FlushDBAsync(ctx context.Context) *StatusCmd {
    method Info (line 609) | func (c cmdable) Info(ctx context.Context, sections ...string) *String...
    method InfoMap (line 620) | func (c cmdable) InfoMap(ctx context.Context, sections ...string) *Inf...
    method LastSave (line 631) | func (c cmdable) LastSave(ctx context.Context) *IntCmd {
    method Save (line 637) | func (c cmdable) Save(ctx context.Context) *StatusCmd {
    method shutdown (line 643) | func (c cmdable) shutdown(ctx context.Context, modifier string) *Statu...
    method Shutdown (line 665) | func (c cmdable) Shutdown(ctx context.Context) *StatusCmd {
    method ShutdownSave (line 669) | func (c cmdable) ShutdownSave(ctx context.Context) *StatusCmd {
    method ShutdownNoSave (line 673) | func (c cmdable) ShutdownNoSave(ctx context.Context) *StatusCmd {
    method SlaveOf (line 680) | func (c cmdable) SlaveOf(ctx context.Context, host, port string) *Stat...
    method ReplicaOf (line 687) | func (c cmdable) ReplicaOf(ctx context.Context, host, port string) *St...
    method SlowLogGet (line 693) | func (c cmdable) SlowLogGet(ctx context.Context, num int64) *SlowLogCmd {
    method SlowLogLen (line 699) | func (c cmdable) SlowLogLen(ctx context.Context) *IntCmd {
    method SlowLogReset (line 705) | func (c cmdable) SlowLogReset(ctx context.Context) *StatusCmd {
    method Latency (line 711) | func (c cmdable) Latency(ctx context.Context) *LatencyCmd {
    method LatencyReset (line 717) | func (c cmdable) LatencyReset(ctx context.Context, events ...interface...
    method Sync (line 727) | func (c cmdable) Sync(_ context.Context) {
    method Time (line 731) | func (c cmdable) Time(ctx context.Context) *TimeCmd {
    method DebugObject (line 737) | func (c cmdable) DebugObject(ctx context.Context, key string) *StringC...
    method MemoryUsage (line 743) | func (c cmdable) MemoryUsage(ctx context.Context, key string, samples ...
    method ModuleLoadex (line 784) | func (c cmdable) ModuleLoadex(ctx context.Context, conf *ModuleLoadexC...
    method Monitor (line 801) | func (c cmdable) Monitor(ctx context.Context, ch chan string) *Monitor...
  type statefulCmdable (line 272) | type statefulCmdable
    method Auth (line 276) | func (c statefulCmdable) Auth(ctx context.Context, password string) *S...
    method AuthACL (line 285) | func (c statefulCmdable) AuthACL(ctx context.Context, username, passwo...
    method Select (line 305) | func (c statefulCmdable) Select(ctx context.Context, index int) *Statu...
    method SwapDB (line 311) | func (c statefulCmdable) SwapDB(ctx context.Context, index1, index2 in...
    method ClientSetName (line 318) | func (c statefulCmdable) ClientSetName(ctx context.Context, name strin...
    method ClientSetInfo (line 325) | func (c statefulCmdable) ClientSetInfo(ctx context.Context, info Libra...
    method Hello (line 355) | func (c statefulCmdable) Hello(ctx context.Context,
  method Validate (line 344) | func (info LibraryInfo) Validate() error {
  type FilterBy (line 384) | type FilterBy struct
  type ModuleLoadexConfig (line 763) | type ModuleLoadexConfig struct
    method toArgs (line 769) | func (c *ModuleLoadexConfig) toArgs() []interface{} {

FILE: commands_test.go
  type TimeValue (line 21) | type TimeValue struct
    method ScanRedis (line 25) | func (t *TimeValue) ScanRedis(s string) (err error) {
  type numberStruct (line 9204) | type numberStruct struct
    method MarshalBinary (line 9208) | func (n numberStruct) MarshalBinary() ([]byte, error) {
    method UnmarshalBinary (line 9212) | func (n *numberStruct) UnmarshalBinary(b []byte) error {
    method ScanRedis (line 9216) | func (n *numberStruct) ScanRedis(str string) error {
  function deref (line 9220) | func deref(viface interface{}) interface{} {

FILE: dial_retry_backoff.go
  function DialRetryBackoffConstant (line 11) | func DialRetryBackoffConstant(d time.Duration) func(attempt int) time.Du...
  function DialRetryBackoffExponential (line 22) | func DialRetryBackoffExponential(minBackoff, maxBackoff time.Duration) f...

FILE: digest_test.go
  function init (line 14) | func init() {
  function skipIfRedisBelow84 (line 25) | func skipIfRedisBelow84(t *testing.T) {
  function TestDigestBasic (line 32) | func TestDigestBasic(t *testing.T) {
  function TestSetIFDEQWithDigest (line 76) | func TestSetIFDEQWithDigest(t *testing.T) {
  function TestSetIFDNEWithDigest (line 140) | func TestSetIFDNEWithDigest(t *testing.T) {
  function TestDelExArgsWithDigest (line 204) | func TestDelExArgsWithDigest(t *testing.T) {
  function TestDigestHelperMatchesRedis (line 269) | func TestDigestHelperMatchesRedis(t *testing.T) {
  function TestDigestBytesHelperMatchesRedis (line 328) | func TestDigestBytesHelperMatchesRedis(t *testing.T) {
  function TestDigestHelperWithSetIFDEQ (line 384) | func TestDigestHelperWithSetIFDEQ(t *testing.T) {
  function TestDigestHelperWithDelExArgs (line 441) | func TestDigestHelperWithDelExArgs(t *testing.T) {

FILE: doctests/bf_tutorial_test.go
  function ExampleClient_bloom (line 14) | func ExampleClient_bloom() {

FILE: doctests/bitfield_tutorial_test.go
  function ExampleClient_bf (line 14) | func ExampleClient_bf() {

FILE: doctests/bitmap_tutorial_test.go
  function ExampleClient_ping (line 14) | func ExampleClient_ping() {
  function ExampleClient_bitcount (line 61) | func ExampleClient_bitcount() {

FILE: doctests/cmds_generic_test.go
  function ExampleClient_del_cmd (line 16) | func ExampleClient_del_cmd() {
  function ExampleClient_expire_cmd (line 63) | func ExampleClient_expire_cmd() {
  function ExampleClient_ttl_cmd (line 164) | func ExampleClient_ttl_cmd() {

FILE: doctests/cmds_hash_test.go
  function ExampleClient_hset (line 15) | func ExampleClient_hset() {
  function ExampleClient_hget (line 107) | func ExampleClient_hget() {
  function ExampleClient_hgetall (line 154) | func ExampleClient_hgetall() {
  function ExampleClient_hvals (line 208) | func ExampleClient_hvals() {

FILE: doctests/cmds_list_test.go
  function ExampleClient_cmd_llen (line 14) | func ExampleClient_cmd_llen() {
  function ExampleClient_cmd_lpop (line 58) | func ExampleClient_cmd_lpop() {
  function ExampleClient_cmd_lpush (line 114) | func ExampleClient_cmd_lpush() {
  function ExampleClient_cmd_lrange (line 159) | func ExampleClient_cmd_lrange() {
  function ExampleClient_cmd_rpop (line 224) | func ExampleClient_cmd_rpop() {
  function ExampleClient_cmd_rpush (line 280) | func ExampleClient_cmd_rpush() {

FILE: doctests/cmds_servermgmt_test.go
  function ExampleClient_cmd_flushall (line 14) | func ExampleClient_cmd_flushall() {
  function ExampleClient_cmd_info (line 53) | func ExampleClient_cmd_info() {

FILE: doctests/cmds_set_test.go
  function ExampleClient_sadd_cmd (line 14) | func ExampleClient_sadd_cmd() {
  function ExampleClient_smembers_cmd (line 68) | func ExampleClient_smembers_cmd() {

FILE: doctests/cmds_sorted_set_test.go
  function ExampleClient_zadd_cmd (line 14) | func ExampleClient_zadd_cmd() {
  function ExampleClient_zrange1 (line 77) | func ExampleClient_zrange1() {
  function ExampleClient_zrange2 (line 137) | func ExampleClient_zrange2() {
  function ExampleClient_zrange3 (line 179) | func ExampleClient_zrange3() {

FILE: doctests/cmds_string_test.go
  function ExampleClient_cmd_incr (line 14) | func ExampleClient_cmd_incr() {

FILE: doctests/cms_tutorial_test.go
  function ExampleClient_cms (line 14) | func ExampleClient_cms() {

FILE: doctests/cuckoo_tutorial_test.go
  function ExampleClient_cuckoo (line 14) | func ExampleClient_cuckoo() {

FILE: doctests/geo_index_test.go
  function ExampleClient_geoindex (line 14) | func ExampleClient_geoindex() {

FILE: doctests/geo_tutorial_test.go
  function ExampleClient_geoadd (line 14) | func ExampleClient_geoadd() {
  function ExampleClient_geosearch (line 76) | func ExampleClient_geosearch() {

FILE: doctests/hash_tutorial_test.go
  function ExampleClient_set_get_all (line 14) | func ExampleClient_set_get_all() {
  function ExampleClient_hmget (line 97) | func ExampleClient_hmget() {
  function ExampleClient_hincrby (line 157) | func ExampleClient_hincrby() {
  function ExampleClient_incrby_get_mget (line 208) | func ExampleClient_incrby_get_mget() {

FILE: doctests/hll_tutorial_test.go
  function ExampleClient_pfadd (line 14) | func ExampleClient_pfadd() {

FILE: doctests/home_json_example_test.go
  function ExampleClient_search_json (line 17) | func ExampleClient_search_json() {
  function ExampleClient_search_hash (line 231) | func ExampleClient_search_hash() {

FILE: doctests/home_prob_dts_test.go
  function ExampleClient_probabilistic_datatypes (line 14) | func ExampleClient_probabilistic_datatypes() {

FILE: doctests/json_tutorial_test.go
  function ExampleClient_setget (line 13) | func ExampleClient_setget() {
  function ExampleClient_str (line 62) | func ExampleClient_str() {
  function ExampleClient_num (line 117) | func ExampleClient_num() {
  function ExampleClient_arr (line 173) | func ExampleClient_arr() {
  function ExampleClient_arr2 (line 244) | func ExampleClient_arr2() {
  function ExampleClient_obj (line 349) | func ExampleClient_obj() {
  function ExampleClient_setbikes (line 472) | func ExampleClient_setbikes() {
  function ExampleClient_getbikes (line 571) | func ExampleClient_getbikes() {
  function ExampleClient_getmtnbikes (line 682) | func ExampleClient_getmtnbikes() {
  function ExampleClient_getmodels (line 742) | func ExampleClient_getmodels() {
  function ExampleClient_get2mtnbikes (line 775) | func ExampleClient_get2mtnbikes() {
  function ExampleClient_filter1 (line 808) | func ExampleClient_filter1() {
  function ExampleClient_filter2 (line 868) | func ExampleClient_filter2() {
  function ExampleClient_filter3 (line 904) | func ExampleClient_filter3() {
  function ExampleClient_filter4 (line 940) | func ExampleClient_filter4() {
  function ExampleClient_updatebikes (line 1015) | func ExampleClient_updatebikes() {
  function ExampleClient_updatefilters1 (line 1066) | func ExampleClient_updatefilters1() {
  function ExampleClient_updatefilters2 (line 1112) | func ExampleClient_updatefilters2() {

FILE: doctests/list_tutorial_test.go
  function ExampleClient_queue (line 14) | func ExampleClient_queue() {
  function ExampleClient_stack (line 70) | func ExampleClient_stack() {
  function ExampleClient_llen (line 126) | func ExampleClient_llen() {
  function ExampleClient_lmove_lrange (line 155) | func ExampleClient_lmove_lrange() {
  function ExampleClient_lpush_rpush (line 221) | func ExampleClient_lpush_rpush() {
  function ExampleClient_variadic (line 277) | func ExampleClient_variadic() {
  function ExampleClient_lpop_rpop (line 324) | func ExampleClient_lpop_rpop() {
  function ExampleClient_ltrim (line 391) | func ExampleClient_ltrim() {
  function ExampleClient_ltrim_end_of_list (line 438) | func ExampleClient_ltrim_end_of_list() {
  function ExampleClient_brpop (line 485) | func ExampleClient_brpop() {
  function ExampleClient_rule1 (line 542) | func ExampleClient_rule1() {
  function ExampleClient_rule11 (line 580) | func ExampleClient_rule11() {
  function ExampleClient_rule2 (line 627) | func ExampleClient_rule2() {
  function ExampleClient_rule3 (line 699) | func ExampleClient_rule3() {
  function ExampleClient_ltrim1 (line 745) | func ExampleClient_ltrim1() {

FILE: doctests/lpush_lrange_test.go
  function ExampleClient_LPush_and_lrange (line 13) | func ExampleClient_LPush_and_lrange() {

FILE: doctests/main_test.go
  function init (line 12) | func init() {

FILE: doctests/pipe_trans_example_test.go
  function ExampleClient_transactions (line 14) | func ExampleClient_transactions() {

FILE: doctests/query_agg_test.go
  function ExampleClient_query_agg (line 13) | func ExampleClient_query_agg() {

FILE: doctests/query_em_test.go
  function ExampleClient_query_em (line 14) | func ExampleClient_query_em() {

FILE: doctests/query_ft_test.go
  function ExampleClient_query_ft (line 13) | func ExampleClient_query_ft() {

FILE: doctests/query_geo_test.go
  function ExampleClient_query_geo (line 13) | func ExampleClient_query_geo() {

FILE: doctests/query_range_test.go
  function ExampleClient_query_range (line 12) | func ExampleClient_query_range() {

FILE: doctests/search_quickstart_test.go
  function ExampleClient_search_qs (line 154) | func ExampleClient_search_qs() {

FILE: doctests/set_get_test.go
  function ExampleClient_Set_and_get (line 12) | func ExampleClient_Set_and_get() {

FILE: doctests/sets_example_test.go
  function ExampleClient_sadd (line 14) | func ExampleClient_sadd() {
  function ExampleClient_sismember (line 71) | func ExampleClient_sismember() {
  function ExampleClient_sinter (line 122) | func ExampleClient_sinter() {
  function ExampleClient_scard (line 164) | func ExampleClient_scard() {
  function ExampleClient_saddsmembers (line 199) | func ExampleClient_saddsmembers() {
  function ExampleClient_smismember (line 240) | func ExampleClient_smismember() {
  function ExampleClient_sdiff (line 284) | func ExampleClient_sdiff() {
  function ExampleClient_multisets (line 325) | func ExampleClient_multisets() {
  function ExampleClient_srem (line 416) | func ExampleClient_srem() {

FILE: doctests/ss_tutorial_test.go
  function ExampleClient_zadd (line 13) | func ExampleClient_zadd() {
  function ExampleClient_zrange (line 71) | func ExampleClient_zrange() {
  function ExampleClient_zrangewithscores (line 124) | func ExampleClient_zrangewithscores() {
  function ExampleClient_zrangebyscore (line 167) | func ExampleClient_zrangebyscore() {
  function ExampleClient_zremrangebyscore (line 212) | func ExampleClient_zremrangebyscore() {
  function ExampleClient_zrank (line 273) | func ExampleClient_zrank() {
  function ExampleClient_zaddlex (line 321) | func ExampleClient_zaddlex() {
  function ExampleClient_leaderboard (line 384) | func ExampleClient_leaderboard() {

FILE: doctests/stream_tutorial_test.go
  function UNUSED (line 15) | func UNUSED(v ...interface{}) {}
  function ExampleClient_xadd (line 19) | func ExampleClient_xadd() {
  function ExampleClient_racefrance1 (line 100) | func ExampleClient_racefrance1() {
  function ExampleClient_raceusa (line 224) | func ExampleClient_raceusa() {
  function ExampleClient_racefrance2 (line 309) | func ExampleClient_racefrance2() {
  function ExampleClient_xgroupcreate (line 479) | func ExampleClient_xgroupcreate() {
  function ExampleClient_xgroupcreatemkstream (line 523) | func ExampleClient_xgroupcreatemkstream() {
  function ExampleClient_xgroupread (line 554) | func ExampleClient_xgroupread() {
  function ExampleClient_raceitaly (line 661) | func ExampleClient_raceitaly() {
  function ExampleClient_xdel (line 1023) | func ExampleClient_xdel() {

FILE: doctests/string_example_test.go
  function ExampleClient_set_get (line 13) | func ExampleClient_set_get() {
  function ExampleClient_setnx_xx (line 51) | func ExampleClient_setnx_xx() {
  function ExampleClient_mset (line 98) | func ExampleClient_mset() {
  function ExampleClient_incr (line 136) | func ExampleClient_incr() {

FILE: doctests/tdigest_tutorial_test.go
  function ExampleClient_tdigstart (line 14) | func ExampleClient_tdigstart() {
  function ExampleClient_tdigcdf (line 64) | func ExampleClient_tdigcdf() {
  function ExampleClient_tdigquant (line 123) | func ExampleClient_tdigquant() {
  function ExampleClient_tdigmin (line 176) | func ExampleClient_tdigmin() {
  function ExampleClient_tdigreset (line 229) | func ExampleClient_tdigreset() {

FILE: doctests/timeseries_tut_test.go
  function mapKeys (line 18) | func mapKeys[K comparable, V any](m map[K]V) []K {
  function ExampleClient_timeseries_create (line 26) | func ExampleClient_timeseries_create() {
  function ExampleClient_timeseries_add (line 126) | func ExampleClient_timeseries_add() {
  function ExampleClient_timeseries_range (line 173) | func ExampleClient_timeseries_range() {
  function ExampleClient_timeseries_query_multi (line 321) | func ExampleClient_timeseries_query_multi() {
  function ExampleClient_timeseries_aggregation (line 627) | func ExampleClient_timeseries_aggregation() {
  function ExampleClient_timeseries_agg_bucket (line 683) | func ExampleClient_timeseries_agg_bucket() {
  function ExampleClient_timeseries_aggmulti (line 764) | func ExampleClient_timeseries_aggmulti() {
  function ExampleClient_timeseries_compaction (line 975) | func ExampleClient_timeseries_compaction() {
  function ExampleClient_timeseries_delete (line 1079) | func ExampleClient_timeseries_delete() {

FILE: doctests/topk_tutorial_test.go
  function ExampleClient_topk (line 14) | func ExampleClient_topk() {

FILE: doctests/vec_set_test.go
  function ExampleClient_vectorset (line 15) | func ExampleClient_vectorset() {
  function ExampleClient_vectorset_quantization (line 383) | func ExampleClient_vectorset_quantization() {
  function ExampleClient_vectorset_dimension_reduction (line 476) | func ExampleClient_vectorset_dimension_reduction() {

FILE: error.go
  function HasErrorPrefix (line 37) | func HasErrorPrefix(err error, prefix string) bool {
  type Error (line 47) | type Error interface
  function isContextError (line 59) | func isContextError(err error) bool {
  function isTimeoutError (line 68) | func isTimeoutError(err error) (isTimeout bool, hasTimeoutFlag bool) {
  function shouldRetry (line 84) | func shouldRetry(err error, retryTimeout bool) bool {
  function isRedisError (line 163) | func isRedisError(err error) bool {
  function isBadConn (line 174) | func isBadConn(err error, allowTimeout bool, addr string) bool {
  function isMovedError (line 216) | func isMovedError(err error) (moved bool, ask bool, addr string) {
  function isLoadingError (line 253) | func isLoadingError(err error) bool {
  function isReadOnlyError (line 257) | func isReadOnlyError(err error) bool {
  function isMovedSameConnAddr (line 261) | func isMovedSameConnAddr(err error, addr string) bool {
  function IsLoadingError (line 275) | func IsLoadingError(err error) bool {
  function IsReadOnlyError (line 281) | func IsReadOnlyError(err error) bool {
  function IsClusterDownError (line 287) | func IsClusterDownError(err error) bool {
  function IsTryAgainError (line 293) | func IsTryAgainError(err error) bool {
  function IsMasterDownError (line 299) | func IsMasterDownError(err error) bool {
  function IsMaxClientsError (line 305) | func IsMaxClientsError(err error) bool {
  function IsMovedError (line 312) | func IsMovedError(err error) (addr string, ok bool) {
  function IsAskError (line 322) | func IsAskError(err error) (addr string, ok bool) {
  function IsAuthError (line 334) | func IsAuthError(err error) bool {
  function IsPermissionError (line 340) | func IsPermissionError(err error) bool {
  function IsExecAbortError (line 346) | func IsExecAbortError(err error) bool {
  function IsOOMError (line 352) | func IsOOMError(err error) bool {
  function IsNoReplicasError (line 360) | func IsNoReplicasError(err error) bool {
  type timeoutError (line 366) | type timeoutError interface

FILE: error_test.go
  type testTimeout (line 13) | type testTimeout struct
    method Timeout (line 17) | func (t testTimeout) Timeout() bool {
    method Error (line 21) | func (t testTimeout) Error() string {

FILE: error_wrapping_test.go
  function TestTypedErrorsWithHookWrapping (line 17) | func TestTypedErrorsWithHookWrapping(t *testing.T) {
  function TestMovedAndAskErrorsWithHookWrapping (line 97) | func TestMovedAndAskErrorsWithHookWrapping(t *testing.T) {
  function TestBackwardCompatibilityWithStringChecks (line 151) | func TestBackwardCompatibilityWithStringChecks(t *testing.T) {
  function TestErrorWrappingInHookScenario (line 194) | func TestErrorWrappingInHookScenario(t *testing.T) {
  function TestShouldRetryWithTypedErrors (line 240) | func TestShouldRetryWithTypedErrors(t *testing.T) {
  function TestSetErrWithWrappedError (line 309) | func TestSetErrWithWrappedError(t *testing.T) {
  type AppError (line 361) | type AppError struct
    method Error (line 369) | func (e *AppError) Error() string {
    method Unwrap (line 374) | func (e *AppError) Unwrap() error {
  function TestCustomErrorTypeWrapping (line 380) | func TestCustomErrorTypeWrapping(t *testing.T) {
  function TestTimeoutErrorWrapping (line 455) | func TestTimeoutErrorWrapping(t *testing.T) {
  type testTimeoutError (line 529) | type testTimeoutError struct
    method Error (line 534) | func (e *testTimeoutError) Error() string {
    method Timeout (line 538) | func (e *testTimeoutError) Timeout() bool {
  type testNetError (line 543) | type testNetError struct
    method Error (line 549) | func (e *testNetError) Error() string {
    method Timeout (line 553) | func (e *testNetError) Timeout() bool {
    method Temporary (line 557) | func (e *testNetError) Temporary() bool {
  function TestContextErrorWrapping (line 562) | func TestContextErrorWrapping(t *testing.T) {
  function TestIOErrorWrapping (line 591) | func TestIOErrorWrapping(t *testing.T) {
  function TestPoolErrorWrapping (line 613) | func TestPoolErrorWrapping(t *testing.T) {
  function TestRedisErrorWrapping (line 626) | func TestRedisErrorWrapping(t *testing.T) {
  function contains (line 645) | func contains(s, substr string) bool {
  function TestAuthErrorWrapping (line 649) | func TestAuthErrorWrapping(t *testing.T) {
  function TestPermissionErrorWrapping (line 691) | func TestPermissionErrorWrapping(t *testing.T) {
  function TestExecAbortErrorWrapping (line 706) | func TestExecAbortErrorWrapping(t *testing.T) {
  function TestOOMErrorWrapping (line 721) | func TestOOMErrorWrapping(t *testing.T) {

FILE: example/cluster-mget/main.go
  function main (line 10) | func main() {

FILE: example/del-keys-without-ttl/main.go
  function main (line 14) | func main() {
  type KeyChecker (line 42) | type KeyChecker struct
    method Add (line 62) | func (c *KeyChecker) Add(key string) {
    method Start (line 66) | func (c *KeyChecker) Start(ctx context.Context) {
    method Stop (line 103) | func (c *KeyChecker) Stop() int {
    method checkKeys (line 109) | func (c *KeyChecker) checkKeys(ctx context.Context, keys []string) err...
    method del (line 133) | func (c *KeyChecker) del(ctx context.Context) error {
  function NewKeyChecker (line 52) | func NewKeyChecker(rdb *redis.Client, batchSize int) *KeyChecker {

FILE: example/digest-optimistic-locking/main.go
  function main (line 12) | func main() {
  function basicDigestExample (line 64) | func basicDigestExample(ctx context.Context, rdb *redis.Client) {
  function optimisticLockingExample (line 87) | func optimisticLockingExample(ctx context.Context, rdb *redis.Client) {
  function detectChangesExample (line 123) | func detectChangesExample(ctx context.Context, rdb *redis.Client) {
  function conditionalDeleteExample (line 159) | func conditionalDeleteExample(ctx context.Context, rdb *redis.Client) {
  function clientSideDigestExample (line 200) | func clientSideDigestExample(ctx context.Context, rdb *redis.Client) {

FILE: example/disable-maintnotifications/main.go
  function main (line 12) | func main() {

FILE: example/hll/main.go
  function main (line 10) | func main() {

FILE: example/hset-struct/main.go
  type Model (line 12) | type Model struct
  function main (line 31) | func main() {
  function ToPtr (line 127) | func ToPtr[T any](v T) *T {

FILE: example/lua-scripting/main.go
  function main (line 10) | func main() {

FILE: example/maintnotifiations-pubsub/main.go
  function main (line 24) | func main() {
  function floodThePool (line 122) | func floodThePool(ctx context.Context, rdb *redis.Client, wg *sync.WaitG...
  function subscribe (line 149) | func subscribe(ctx context.Context, rdb *redis.Client, topic string, sub...

FILE: example/otel-metrics/main.go
  function main (line 22) | func main() {

FILE: example/otel/client.go
  function main (line 21) | func main() {
  function handleRequest (line 61) | func handleRequest(ctx context.Context, rdb *redis.Client) error {

FILE: example/redis-bloom/main.go
  function main (line 11) | func main() {
  function bloomFilter (line 32) | func bloomFilter(ctx context.Context, rdb *redis.Client) {
  function cuckooFilter (line 62) | func cuckooFilter(ctx context.Context, rdb *redis.Client) {
  function countMinSketch (line 94) | func countMinSketch(ctx context.Context, rdb *redis.Client) {
  function topK (line 121) | func topK(ctx context.Context, rdb *redis.Client) {

FILE: example/scan-struct/main.go
  type Model (line 11) | type Model struct
  function main (line 23) | func main() {

FILE: example/tls-cert-auth/main.go
  function main (line 33) | func main() {

FILE: example/tls-connection/main.go
  function main (line 13) | func main() {

FILE: example_instrumentation_test.go
  type redisHook (line 11) | type redisHook struct
    method DialHook (line 15) | func (redisHook) DialHook(hook redis.DialHook) redis.DialHook {
    method ProcessHook (line 24) | func (redisHook) ProcessHook(hook redis.ProcessHook) redis.ProcessHook {
    method ProcessPipelineHook (line 33) | func (redisHook) ProcessPipelineHook(hook redis.ProcessPipelineHook) r...
  function Example_instrumentation (line 46) | func Example_instrumentation() {
  function ExamplePipeline_instrumentation (line 65) | func ExamplePipeline_instrumentation() {
  function ExampleClient_Watch_instrumentation (line 88) | func ExampleClient_Watch_instrumentation() {

FILE: example_test.go
  function init (line 18) | func init() {
  function ExampleNewClient (line 29) | func ExampleNewClient() {
  function ExampleParseURL (line 41) | func ExampleParseURL() {
  function ExampleNewFailoverClient (line 60) | func ExampleNewFailoverClient() {
  function ExampleNewClusterClient (line 70) | func ExampleNewClusterClient() {
  function ExampleNewClusterClient_manualSetup (line 81) | func ExampleNewClusterClient_manualSetup() {
  function ExampleNewRing (line 122) | func ExampleNewRing() {
  function ExampleClient (line 133) | func ExampleClient() {
  function ExampleConn_name (line 157) | func ExampleConn_name() {
  function ExampleConn_client_setInfo_libraryVersion (line 178) | func ExampleConn_client_setInfo_libraryVersion() {
  function ExampleClient_Set (line 200) | func ExampleClient_Set() {
  function ExampleClient_SetEx (line 215) | func ExampleClient_SetEx() {
  function ExampleClient_HSet (line 222) | func ExampleClient_HSet() {
  function ExampleClient_Incr (line 237) | func ExampleClient_Incr() {
  function ExampleClient_BLPop (line 247) | func ExampleClient_BLPop() {
  function ExampleClient_Scan (line 262) | func ExampleClient_Scan() {
  function ExampleClient_ScanType (line 290) | func ExampleClient_ScanType() {
  function ExampleClient_ScanType_hashType (line 319) | func ExampleClient_ScanType_hashType() {
  function ExampleMapStringStringCmd_Scan (line 349) | func ExampleMapStringStringCmd_Scan() {
  function ExampleSliceCmd_Scan (line 383) | func ExampleSliceCmd_Scan() {
  function ExampleClient_Pipelined (line 414) | func ExampleClient_Pipelined() {
  function ExampleClient_Pipeline (line 425) | func ExampleClient_Pipeline() {
  function ExampleClient_TxPipelined (line 442) | func ExampleClient_TxPipelined() {
  function ExampleClient_TxPipeline (line 453) | func ExampleClient_TxPipeline() {
  function ExampleClient_Watch (line 472) | func ExampleClient_Watch() {
  function ExamplePubSub (line 531) | func ExamplePubSub() {
  function ExamplePubSub_Receive (line 562) | func ExamplePubSub_Receive() {
  function ExampleScript (line 592) | func ExampleScript() {
  function Example_customCommand (line 615) | func Example_customCommand() {
  function Example_customCommand2 (line 627) | func Example_customCommand2() {
  function ExampleScanIterator (line 633) | func ExampleScanIterator() {
  function ExampleScanCmd_Iterator (line 643) | func ExampleScanCmd_Iterator() {
  function ExampleNewUniversalClient_simple (line 653) | func ExampleNewUniversalClient_simple() {
  function ExampleNewUniversalClient_failover (line 662) | func ExampleNewUniversalClient_failover() {
  function ExampleNewUniversalClient_cluster (line 672) | func ExampleNewUniversalClient_cluster() {
  function ExampleClient_SlowLogGet (line 681) | func ExampleClient_SlowLogGet() {

FILE: export_test.go
  method Pool (line 14) | func (c *baseClient) Pool() pool.Pooler {
  method SetNetConn (line 18) | func (c *PubSub) SetNetConn(netConn net.Conn) {
  method LoadState (line 22) | func (c *ClusterClient) LoadState(ctx context.Context) (*clusterState, e...
  method SlotAddrs (line 27) | func (c *ClusterClient) SlotAddrs(ctx context.Context, slot int) []string {
  method Nodes (line 40) | func (c *ClusterClient) Nodes(ctx context.Context, key string) ([]*clust...
  method SwapNodes (line 54) | func (c *ClusterClient) SwapNodes(ctx context.Context, key string) error {
  method IsConsistent (line 63) | func (c *clusterState) IsConsistent(ctx context.Context) bool {
  function GetSlavesAddrByName (line 87) | func GetSlavesAddrByName(ctx context.Context, c *SentinelClient, name st...
  method ShardByName (line 97) | func (c *Ring) ShardByName(name string) *ringShard {
  method ToArgs (line 102) | func (c *ModuleLoadexConfig) ToArgs() []interface{} {
  function ShouldRetry (line 106) | func ShouldRetry(err error, retryTimeout bool) bool {

FILE: extra/rediscensus/rediscensus.go
  type TracingHook (line 13) | type TracingHook struct
    method DialHook (line 21) | func (TracingHook) DialHook(next redis.DialHook) redis.DialHook {
    method ProcessHook (line 43) | func (TracingHook) ProcessHook(next redis.ProcessHook) redis.ProcessHo...
    method ProcessPipelineHook (line 67) | func (TracingHook) ProcessPipelineHook(next redis.ProcessPipelineHook)...
  function NewTracingHook (line 17) | func NewTracingHook() *TracingHook {
  function recordErrorOnOCSpan (line 71) | func recordErrorOnOCSpan(ctx context.Context, span *trace.Span, err erro...

FILE: extra/rediscmd/rediscmd.go
  function CmdString (line 13) | func CmdString(cmd redis.Cmder) string {
  function CmdsString (line 19) | func CmdsString(cmds []redis.Cmder) (string, string) {
  function AppendCmd (line 48) | func AppendCmd(b []byte, cmd redis.Cmder) []byte {
  function appendArg (line 64) | func appendArg(b []byte, v interface{}) []byte {
  function appendUTF8String (line 108) | func appendUTF8String(dst []byte, src []byte) []byte {
  function isSimple (line 120) | func isSimple(b []byte) bool {
  function isSimpleByte (line 129) | func isSimpleByte(c byte) bool {

FILE: extra/rediscmd/rediscmd_test.go
  function TestGinkgo (line 10) | func TestGinkgo(t *testing.T) {

FILE: extra/rediscmd/safe.go
  function String (line 6) | func String(b []byte) string {
  function Bytes (line 10) | func Bytes(s string) []byte {

FILE: extra/rediscmd/unsafe.go
  function String (line 9) | func String(b []byte) string {
  function Bytes (line 14) | func Bytes(s string) []byte {

FILE: extra/redisotel-native/attributes.go
  constant AttrDBSystemName (line 9) | AttrDBSystemName         = "db.system.name"
  constant AttrDBNamespace (line 10) | AttrDBNamespace          = "db.namespace"
  constant AttrDBOperationName (line 11) | AttrDBOperationName      = "db.operation.name"
  constant AttrDBOperationBatchSize (line 12) | AttrDBOperationBatchSize = "db.operation.batch.size"
  constant AttrDBResponseStatusCode (line 13) | AttrDBResponseStatusCode = "db.response.status_code"
  constant AttrDBClientConnectionPoolName (line 16) | AttrDBClientConnectionPoolName = "db.client.connection.pool.name"
  constant AttrDBClientConnectionState (line 17) | AttrDBClientConnectionState    = "db.client.connection.state"
  constant AttrServerAddress (line 20) | AttrServerAddress = "server.address"
  constant AttrServerPort (line 21) | AttrServerPort    = "server.port"
  constant AttrNetworkPeerAddress (line 24) | AttrNetworkPeerAddress = "network.peer.address"
  constant AttrNetworkPeerPort (line 25) | AttrNetworkPeerPort    = "network.peer.port"
  constant AttrErrorType (line 28) | AttrErrorType = "error.type"
  constant AttrRedisClientLibrary (line 31) | AttrRedisClientLibrary                = "redis.client.library"
  constant AttrRedisClientConnectionPubSub (line 32) | AttrRedisClientConnectionPubSub       = "redis.client.connection.pubsub"
  constant AttrRedisClientConnectionCloseReason (line 33) | AttrRedisClientConnectionCloseReason  = "redis.client.connection.close.r...
  constant AttrRedisClientErrorsCategory (line 34) | AttrRedisClientErrorsCategory         = "redis.client.errors.category"
  constant AttrRedisClientErrorsInternal (line 35) | AttrRedisClientErrorsInternal         = "redis.client.errors.internal"
  constant AttrRedisClientOperationRetryAttempts (line 36) | AttrRedisClientOperationRetryAttempts = "redis.client.operation.retry_at...
  constant AttrRedisClientPubSubDirection (line 39) | AttrRedisClientPubSubDirection = "redis.client.pubsub.direction"
  constant AttrRedisClientPubSubSharded (line 40) | AttrRedisClientPubSubSharded   = "redis.client.pubsub.sharded"
  constant AttrRedisClientPubSubChannel (line 41) | AttrRedisClientPubSubChannel   = "redis.client.pubsub.channel"
  constant AttrRedisClientStreamName (line 44) | AttrRedisClientStreamName          = "redis.client.stream.name"
  constant AttrRedisClientStreamConsumerGroup (line 45) | AttrRedisClientStreamConsumerGroup = "redis.client.stream.consumer_group"
  constant AttrRedisClientStreamConsumerName (line 46) | AttrRedisClientStreamConsumerName  = "redis.client.stream.consumer_name"
  constant AttrRedisClientConnectionNotification (line 49) | AttrRedisClientConnectionNotification = "redis.client.connection.notific...
  constant ConnectionStateIdle (line 54) | ConnectionStateIdle = "idle"
  constant ConnectionStateUsed (line 55) | ConnectionStateUsed = "used"
  constant PubSubDirectionSent (line 60) | PubSubDirectionSent     = "sent"
  constant PubSubDirectionReceived (line 61) | PubSubDirectionReceived = "received"
  constant DBSystemRedis (line 66) | DBSystemRedis = "redis"

FILE: extra/redisotel-native/config.go
  type MetricGroup (line 9) | type MetricGroup
  constant MetricGroupCommand (line 12) | MetricGroupCommand            MetricGroup = "command"
  constant MetricGroupConnectionBasic (line 13) | MetricGroupConnectionBasic    MetricGroup = "connection-basic"
  constant MetricGroupResiliency (line 14) | MetricGroupResiliency         MetricGroup = "resiliency"
  constant MetricGroupConnectionAdvanced (line 15) | MetricGroupConnectionAdvanced MetricGroup = "connection-advanced"
  constant MetricGroupPubSub (line 16) | MetricGroupPubSub             MetricGroup = "pubsub"
  constant MetricGroupStream (line 17) | MetricGroupStream             MetricGroup = "stream"
  type HistogramAggregation (line 20) | type HistogramAggregation
  constant HistogramAggregationExplicitBucket (line 23) | HistogramAggregationExplicitBucket   HistogramAggregation = "explicit_bu...
  constant HistogramAggregationBase2Exponential (line 24) | HistogramAggregationBase2Exponential HistogramAggregation = "base2_expon...
  type config (line 27) | type config struct
    method isMetricGroupEnabled (line 53) | func (c *config) isMetricGroupEnabled(group MetricGroup) bool {
    method isCommandIncluded (line 57) | func (c *config) isCommandIncluded(command string) bool {
  function defaultHistogramBuckets (line 82) | func defaultHistogramBuckets() []float64 {
  type MetricGroupFlags (line 99) | type MetricGroupFlags
  constant MetricGroupFlagCommand (line 102) | MetricGroupFlagCommand            MetricGroupFlags = 1 << 0
  constant MetricGroupFlagConnectionBasic (line 103) | MetricGroupFlagConnectionBasic    MetricGroupFlags = 1 << 1
  constant MetricGroupFlagResiliency (line 104) | MetricGroupFlagResiliency         MetricGroupFlags = 1 << 2
  constant MetricGroupFlagConnectionAdvanced (line 105) | MetricGroupFlagConnectionAdvanced MetricGroupFlags = 1 << 3
  constant MetricGroupFlagPubSub (line 106) | MetricGroupFlagPubSub             MetricGroupFlags = 1 << 4
  constant MetricGroupFlagStream (line 107) | MetricGroupFlagStream             MetricGroupFlags = 1 << 5
  constant MetricGroupAll (line 110) | MetricGroupAll MetricGroupFlags = MetricGroupFlagCommand |
  type Config (line 130) | type Config struct
    method WithEnabled (line 202) | func (c *Config) WithEnabled(enabled bool) *Config {
    method WithMeterProvider (line 209) | func (c *Config) WithMeterProvider(provider metric.MeterProvider) *Con...
    method WithMetricGroups (line 216) | func (c *Config) WithMetricGroups(groups MetricGroupFlags) *Config {
    method WithIncludeCommands (line 222) | func (c *Config) WithIncludeCommands(commands []string) *Config {
    method WithExcludeCommands (line 232) | func (c *Config) WithExcludeCommands(commands []string) *Config {
    method WithHidePubSubChannelNames (line 241) | func (c *Config) WithHidePubSubChannelNames(hide bool) *Config {
    method WithHideStreamNames (line 247) | func (c *Config) WithHideStreamNames(hide bool) *Config {
    method WithHistogramAggregation (line 253) | func (c *Config) WithHistogramAggregation(agg HistogramAggregation) *C...
    method WithHistogramBuckets (line 261) | func (c *Config) WithHistogramBuckets(buckets []float64) *Config {
  function NewConfig (line 173) | func NewConfig() *Config {

FILE: extra/redisotel-native/metrics.go
  type timeoutError (line 19) | type timeoutError interface
  constant libraryName (line 25) | libraryName = "go-redis"
  function getLibraryVersionAttr (line 29) | func getLibraryVersionAttr() attribute.KeyValue {
  function addServerPortIfNonDefault (line 34) | func addServerPortIfNonDefault(attrs []attribute.KeyValue, serverPort st...
  type poolInfo (line 42) | type poolInfo struct
  type pubsubPoolInfo (line 48) | type pubsubPoolInfo struct
  type metricsRecorder (line 54) | type metricsRecorder struct
    method RecordOperationDuration (line 81) | func (r *metricsRecorder) RecordOperationDuration(
    method RecordPipelineOperationDuration (line 148) | func (r *metricsRecorder) RecordPipelineOperationDuration(
    method RecordConnectionCreateTime (line 510) | func (r *metricsRecorder) RecordConnectionCreateTime(
    method RecordConnectionRelaxedTimeout (line 542) | func (r *metricsRecorder) RecordConnectionRelaxedTimeout(
    method RecordConnectionHandoff (line 574) | func (r *metricsRecorder) RecordConnectionHandoff(
    method RecordError (line 601) | func (r *metricsRecorder) RecordError(
    method RecordMaintenanceNotification (line 651) | func (r *metricsRecorder) RecordMaintenanceNotification(
    method RecordConnectionWaitTime (line 689) | func (r *metricsRecorder) RecordConnectionWaitTime(
    method RecordConnectionClosed (line 717) | func (r *metricsRecorder) RecordConnectionClosed(
    method RecordPubSubMessage (line 762) | func (r *metricsRecorder) RecordPubSubMessage(
    method RecordStreamLag (line 807) | func (r *metricsRecorder) RecordStreamLag(
    method RegisterPool (line 854) | func (r *metricsRecorder) RegisterPool(poolName string, pool redis.Poo...
    method UnregisterPool (line 867) | func (r *metricsRecorder) UnregisterPool(pool redis.Pooler) {
    method RegisterPubSubPool (line 884) | func (r *metricsRecorder) RegisterPubSubPool(poolName string, pool red...
    method UnregisterPubSubPool (line 897) | func (r *metricsRecorder) UnregisterPubSubPool(pool redis.PubSubPooler) {
  function classifyError (line 211) | func classifyError(err error) string {
  function normalizeNetworkError (line 237) | func normalizeNetworkError(err error) string {
  function normalizeGenericError (line 284) | func normalizeGenericError(errStr string) string {
  function extractRedisErrorPrefix (line 325) | func extractRedisErrorPrefix(err error) string {
  function isNetworkError (line 347) | func isNetworkError(err error) bool {
  function isTimeoutError (line 358) | func isTimeoutError(err error) bool {
  function getErrorCategory (line 380) | func getErrorCategory(err error) string {
  function getErrorCategoryFromString (line 402) | func getErrorCategoryFromString(errStr string) string {
  function splitHostPort (line 457) | func splitHostPort(addr string) (host, port string) {
  function parseAddr (line 473) | func parseAddr(addr string) (host, port string) {
  function extractServerInfo (line 494) | func extractServerInfo(cn redis.ConnInfo) (addr, port string) {

FILE: extra/redisotel-native/metrics_definitions_test.go
  constant semconvOperationDuration (line 8) | semconvOperationDuration    = "db.client.operation.duration"
  constant semconvConnectionCount (line 9) | semconvConnectionCount      = "db.client.connection.count"
  constant semconvConnectionCreateTime (line 10) | semconvConnectionCreateTime = "db.client.connection.create_time"
  constant semconvConnectionWaitTime (line 11) | semconvConnectionWaitTime   = "db.client.connection.wait_time"
  constant semconvConnectionPending (line 12) | semconvConnectionPending    = "db.client.connection.pending_requests"
  function TestMetricDefinitionsMatchSemconv (line 16) | func TestMetricDefinitionsMatchSemconv(t *testing.T) {
  function TestSemconvMetricTypes (line 41) | func TestSemconvMetricTypes(t *testing.T) {

FILE: extra/redisotel-native/metrics_stress_test.go
  constant stressTestDuration (line 19) | stressTestDuration       = 30 * time.Second
  constant stressTestConcurrency (line 20) | stressTestConcurrency    = 50
  constant stressTestMinDelay (line 21) | stressTestMinDelay       = 10 * time.Millisecond
  constant stressTestMaxDelay (line 22) | stressTestMaxDelay       = 100 * time.Millisecond
  constant stressTestStatusInterval (line 23) | stressTestStatusInterval = 5 * time.Second
  function TestMetricsUnderStress (line 27) | func TestMetricsUnderStress(t *testing.T) {
  function validateMetrics (line 129) | func validateMetrics(t *testing.T, rm metricdata.ResourceMetrics) {
  function resetObservabilityForTest (line 150) | func resetObservabilityForTest() {
  function TestTracingAndMetricsCompatibility (line 158) | func TestTracingAndMetricsCompatibility(t *testing.T) {

FILE: extra/redisotel-native/redisotel.go
  constant MetricOperationDuration (line 21) | MetricOperationDuration = "db.client.operation.duration"
  constant MetricConnectionCount (line 24) | MetricConnectionCount          = "db.client.connection.count"
  constant MetricConnectionCreateTime (line 25) | MetricConnectionCreateTime     = "db.client.connection.create_time"
  constant MetricConnectionWaitTime (line 26) | MetricConnectionWaitTime       = "db.client.connection.wait_time"
  constant MetricConnectionPendingReqs (line 27) | MetricConnectionPendingReqs    = "db.client.connection.pending_requests"
  constant MetricConnectionRelaxedTimeout (line 28) | MetricConnectionRelaxedTimeout = "redis.client.connection.relaxed_timeout"
  constant MetricConnectionHandoff (line 29) | MetricConnectionHandoff        = "redis.client.connection.handoff"
  constant MetricConnectionClosed (line 30) | MetricConnectionClosed         = "redis.client.connection.closed"
  constant MetricClientErrors (line 33) | MetricClientErrors             = "redis.client.errors"
  constant MetricMaintenanceNotifications (line 34) | MetricMaintenanceNotifications = "redis.client.maintenance.notifications"
  constant MetricPubSubMessages (line 37) | MetricPubSubMessages = "redis.client.pubsub.messages"
  constant MetricStreamLag (line 40) | MetricStreamLag = "redis.client.stream.lag"
  constant PoolNameMain (line 43) | PoolNameMain   = "main"
  constant PoolNamePubSub (line 44) | PoolNamePubSub = "pubsub"
  type ObservabilityInstance (line 54) | type ObservabilityInstance struct
    method Init (line 73) | func (o *ObservabilityInstance) Init(cfg *Config) error {
    method IsEnabled (line 113) | func (o *ObservabilityInstance) IsEnabled() bool {
    method Shutdown (line 121) | func (o *ObservabilityInstance) Shutdown() error {
    method shutdownLocked (line 127) | func (o *ObservabilityInstance) shutdownLocked() error {
    method configToInternal (line 144) | func (o *ObservabilityInstance) configToInternal(cfg *Config) config {
    method createRecorder (line 182) | func (o *ObservabilityInstance) createRecorder(meter metric.Meter, cfg...
    method registerAsyncCallbacks (line 388) | func (o *ObservabilityInstance) registerAsyncCallbacks(meter metric.Me...
  function GetObservabilityInstance (line 62) | func GetObservabilityInstance() *ObservabilityInstance {
  function parsePoolName (line 372) | func parsePoolName(poolName string) (string, string, string) {

FILE: extra/redisotel/config.go
  type config (line 14) | type config struct
  type baseOption (line 41) | type baseOption interface
  type Option (line 45) | type Option interface
  type option (line 51) | type option
    method apply (line 53) | func (fn option) apply(conf *config) {
    method tracing (line 57) | func (fn option) tracing() {}
    method metrics (line 59) | func (fn option) metrics() {}
  function newConfig (line 61) | func newConfig(opts ...baseOption) *config {
  function WithDBSystem (line 90) | func WithDBSystem(dbSystem string) Option {
  function WithAttributes (line 97) | func WithAttributes(attrs ...attribute.KeyValue) Option {
  type TracingOption (line 105) | type TracingOption interface
  type tracingOption (line 110) | type tracingOption
    method apply (line 114) | func (fn tracingOption) apply(conf *config) {
    method tracing (line 118) | func (fn tracingOption) tracing() {}
  function WithTracerProvider (line 122) | func WithTracerProvider(provider trace.TracerProvider) TracingOption {
  function WithDBStatement (line 129) | func WithDBStatement(on bool) TracingOption {
  function WithCallerEnabled (line 136) | func WithCallerEnabled(on bool) TracingOption {
  function WithCommandFilter (line 144) | func WithCommandFilter(filter func(cmd redis.Cmder) bool) TracingOption {
  function WithCommandsFilter (line 153) | func WithCommandsFilter(filter func(cmds []redis.Cmder) bool) TracingOpt...
  function WithDialFilter (line 160) | func WithDialFilter(on bool) TracingOption {
  function DefaultCommandFilter (line 167) | func DefaultCommandFilter(cmd redis.Cmder) bool {
  function BasicCommandFilter (line 192) | func BasicCommandFilter(cmd redis.Cmder) bool {
  type MetricsOption (line 198) | type MetricsOption interface
  type metricsOption (line 203) | type metricsOption
    method apply (line 207) | func (fn metricsOption) apply(conf *config) {
    method metrics (line 211) | func (fn metricsOption) metrics() {}
  function WithMeterProvider (line 214) | func WithMeterProvider(mp metric.MeterProvider) MetricsOption {
  function WithCloseChan (line 220) | func WithCloseChan(closeChan chan struct{}) MetricsOption {

FILE: extra/redisotel/metrics.go
  type metricsState (line 18) | type metricsState struct
  function InstrumentMetrics (line 27) | func InstrumentMetrics(rdb redis.UniversalClient, opts ...MetricsOption)...
  function registerClient (line 86) | func registerClient(rdb *redis.Client, conf *config, state *metricsState...
  function poolStatsAttrs (line 117) | func poolStatsAttrs(conf *config) (poolAttrs, idleAttrs, usedAttrs attri...
  function reportPoolStats (line 124) | func reportPoolStats(rdb *redis.Client, conf *config) (metric.Registrati...
  function addMetricsHook (line 232) | func addMetricsHook(rdb *redis.Client, conf *config) error {
  type metricsHook (line 259) | type metricsHook struct
    method DialHook (line 267) | func (mh *metricsHook) DialHook(hook redis.DialHook) redis.DialHook {
    method ProcessHook (line 285) | func (mh *metricsHook) ProcessHook(hook redis.ProcessHook) redis.Proce...
    method ProcessPipelineHook (line 305) | func (mh *metricsHook) ProcessPipelineHook(
  function milliseconds (line 327) | func milliseconds(d time.Duration) float64 {
  function statusAttr (line 331) | func statusAttr(err error) attribute.KeyValue {
  function errorTypeAttribute (line 341) | func errorTypeAttribute(err error) attribute.KeyValue {

FILE: extra/redisotel/metrics_test.go
  function Test_poolStatsAttrs (line 10) | func Test_poolStatsAttrs(t *testing.T) {

FILE: extra/redisotel/tracing.go
  constant instrumName (line 21) | instrumName = "github.com/redis/go-redis/extra/redisotel"
  function InstrumentTracing (line 24) | func InstrumentTracing(rdb redis.UniversalClient, opts ...TracingOption)...
  type tracingHook (line 53) | type tracingHook struct
    method DialHook (line 88) | func (th *tracingHook) DialHook(hook redis.DialHook) redis.DialHook {
    method ProcessHook (line 107) | func (th *tracingHook) ProcessHook(hook redis.ProcessHook) redis.Proce...
    method ProcessPipelineHook (line 145) | func (th *tracingHook) ProcessPipelineHook(
  function newTracingHook (line 61) | func newTracingHook(connString string, opts ...TracingOption) *tracingHo...
  function recordError (line 187) | func recordError(span trace.Span, err error) {
  function formatDBConnString (line 194) | func formatDBConnString(network, addr string) string {
  function funcFileLine (line 201) | func funcFileLine(pkg string) (string, string, int) {
  function addServerAttributes (line 229) | func addServerAttributes(opts []TracingOption, addr string) []TracingOpt...

FILE: extra/redisotel/tracing_test.go
  type providerFunc (line 22) | type providerFunc
    method TracerProvider (line 24) | func (fn providerFunc) TracerProvider(name string, opts ...trace.Trace...
  function TestNewWithTracerProvider (line 28) | func TestNewWithTracerProvider(t *testing.T) {
  function TestWithDBStatement (line 43) | func TestWithDBStatement(t *testing.T) {
  function TestWithoutCaller (line 69) | func TestWithoutCaller(t *testing.T) {
  function TestWithCommandFilter (line 98) | func TestWithCommandFilter(t *testing.T) {
  function TestWithCommandsFilter (line 230) | func TestWithCommandsFilter(t *testing.T) {
  function TestWithDialFilter (line 297) | func TestWithDialFilter(t *testing.T) {
  function TestTracingHook_DialHook (line 344) | func TestTracingHook_DialHook(t *testing.T) {
  function TestTracingHook_ProcessHook (line 396) | func TestTracingHook_ProcessHook(t *testing.T) {
  function TestTracingHook_ProcessPipelineHook (line 447) | func TestTracingHook_ProcessPipelineHook(t *testing.T) {
  function TestTracingHook_ProcessHook_LongCommand (line 501) | func TestTracingHook_ProcessHook_LongCommand(t *testing.T) {
  function TestTracingHook_ProcessPipelineHook_LongCommands (line 578) | func TestTracingHook_ProcessPipelineHook_LongCommands(t *testing.T) {
  function assertEqual (line 664) | func assertEqual(t *testing.T, expected, actual interface{}) {
  function assertAttributeContains (line 671) | func assertAttributeContains(t *testing.T, attrs []attribute.KeyValue, a...

FILE: extra/redisprometheus/collector.go
  type StatGetter (line 10) | type StatGetter interface
  type Collector (line 16) | type Collector struct
    method Describe (line 75) | func (s *Collector) Describe(descs chan<- *prometheus.Desc) {
    method Collect (line 85) | func (s *Collector) Collect(metrics chan<- prometheus.Metric) {
  function NewCollector (line 38) | func NewCollector(namespace, subsystem string, getter StatGetter) *Colle...

FILE: fuzz/fuzz.go
  constant minDataLength (line 14) | minDataLength     = 4
  constant redisAddr (line 15) | redisAddr         = ":6379"
  constant dialTimeout (line 16) | dialTimeout       = 10 * time.Second
  constant readTimeout (line 17) | readTimeout       = 10 * time.Second
  constant writeTimeout (line 18) | writeTimeout      = 10 * time.Second
  constant poolSize (line 19) | poolSize          = 10
  constant poolTimeout (line 20) | poolTimeout       = 10 * time.Second
  constant scanCount (line 21) | scanCount         = 10
  constant maxIterPercentage (line 22) | maxIterPercentage = 256
  type redisOperation (line 30) | type redisOperation
  function init (line 32) | func init() {
  function Fuzz (line 43) | func Fuzz(data []byte) int {

FILE: generic_commands.go
  type GenericCmdable (line 10) | type GenericCmdable interface
  method Del (line 51) | func (c cmdable) Del(ctx context.Context, keys ...string) *IntCmd {
  method Unlink (line 62) | func (c cmdable) Unlink(ctx context.Context, keys ...string) *IntCmd {
  method Dump (line 73) | func (c cmdable) Dump(ctx context.Context, key string) *StringCmd {
  method Exists (line 79) | func (c cmdable) Exists(ctx context.Context, keys ...string) *IntCmd {
  method Expire (line 90) | func (c cmdable) Expire(ctx context.Context, key string, expiration time...
  method ExpireNX (line 94) | func (c cmdable) ExpireNX(ctx context.Context, key string, expiration ti...
  method ExpireXX (line 98) | func (c cmdable) ExpireXX(ctx context.Context, key string, expiration ti...
  method ExpireGT (line 102) | func (c cmdable) ExpireGT(ctx context.Context, key string, expiration ti...
  method ExpireLT (line 106) | func (c cmdable) ExpireLT(ctx context.Context, key string, expiration ti...
  method expire (line 110) | func (c cmdable) expire(
  method ExpireAt (line 126) | func (c cmdable) ExpireAt(ctx context.Context, key string, tm time.Time)...
  method ExpireTime (line 132) | func (c cmdable) ExpireTime(ctx context.Context, key string) *DurationCmd {
  method Keys (line 138) | func (c cmdable) Keys(ctx context.Context, pattern string) *StringSliceC...
  method Migrate (line 144) | func (c cmdable) Migrate(ctx context.Context, host, port, key string, db...
  method Move (line 159) | func (c cmdable) Move(ctx context.Context, key string, db int) *BoolCmd {
  method ObjectFreq (line 165) | func (c cmdable) ObjectFreq(ctx context.Context, key string) *IntCmd {
  method ObjectRefCount (line 171) | func (c cmdable) ObjectRefCount(ctx context.Context, key string) *IntCmd {
  method ObjectEncoding (line 177) | func (c cmdable) ObjectEncoding(ctx context.Context, key string) *String...
  method ObjectIdleTime (line 183) | func (c cmdable) ObjectIdleTime(ctx context.Context, key string) *Durati...
  method Persist (line 189) | func (c cmdable) Persist(ctx context.Context, key string) *BoolCmd {
  method PExpire (line 195) | func (c cmdable) PExpire(ctx context.Context, key string, expiration tim...
  method PExpireAt (line 201) | func (c cmdable) PExpireAt(ctx context.Context, key string, tm time.Time...
  method PExpireTime (line 212) | func (c cmdable) PExpireTime(ctx context.Context, key string) *DurationC...
  method PTTL (line 218) | func (c cmdable) PTTL(ctx context.Context, key string) *DurationCmd {
  method RandomKey (line 224) | func (c cmdable) RandomKey(ctx context.Context) *StringCmd {
  method Rename (line 230) | func (c cmdable) Rename(ctx context.Context, key, newkey string) *Status...
  method RenameNX (line 236) | func (c cmdable) RenameNX(ctx context.Context, key, newkey string) *Bool...
  method Restore (line 242) | func (c cmdable) Restore(ctx context.Context, key string, ttl time.Durat...
  method RestoreReplace (line 254) | func (c cmdable) RestoreReplace(ctx context.Context, key string, ttl tim...
  type Sort (line 267) | type Sort struct
    method args (line 275) | func (sort *Sort) args(command, key string) []interface{} {
  method SortRO (line 296) | func (c cmdable) SortRO(ctx context.Context, key string, sort *Sort) *St...
  method Sort (line 302) | func (c cmdable) Sort(ctx context.Context, key string, sort *Sort) *Stri...
  method SortStore (line 308) | func (c cmdable) SortStore(ctx context.Context, key, store string, sort ...
  method SortInterfaces (line 318) | func (c cmdable) SortInterfaces(ctx context.Context, key string, sort *S...
  method Touch (line 324) | func (c cmdable) Touch(ctx context.Context, keys ...string) *IntCmd {
  method TTL (line 335) | func (c cmdable) TTL(ctx context.Context, key string) *DurationCmd {
  method Type (line 341) | func (c cmdable) Type(ctx context.Context, key string) *StatusCmd {
  method Copy (line 347) | func (c cmdable) Copy(ctx context.Context, sourceKey, destKey string, db...
  method Scan (line 359) | func (c cmdable) Scan(ctx context.Context, cursor uint64, match string, ...
  method ScanType (line 375) | func (c cmdable) ScanType(ctx context.Context, cursor uint64, match stri...

FILE: geo_commands.go
  type GeoCmdable (line 8) | type GeoCmdable interface
  method GeoAdd (line 22) | func (c cmdable) GeoAdd(ctx context.Context, key string, geoLocation ......
  method GeoRadius (line 40) | func (c cmdable) GeoRadius(
  method GeoRadiusStore (line 53) | func (c cmdable) GeoRadiusStore(
  method GeoRadiusByMember (line 70) | func (c cmdable) GeoRadiusByMember(
  method GeoRadiusByMemberStore (line 83) | func (c cmdable) GeoRadiusByMemberStore(
  method GeoSearch (line 96) | func (c cmdable) GeoSearch(ctx context.Context, key string, q *GeoSearch...
  method GeoSearchLocation (line 105) | func (c cmdable) GeoSearchLocation(
  method GeoSearchStore (line 116) | func (c cmdable) GeoSearchStore(ctx context.Context, key, store string, ...
  method GeoDist (line 128) | func (c cmdable) GeoDist(
  method GeoHash (line 139) | func (c cmdable) GeoHash(ctx context.Context, key string, members ...str...
  method GeoPos (line 151) | func (c cmdable) GeoPos(ctx context.Context, key string, members ...stri...

FILE: hash_commands.go
  type HashCmdable (line 10) | type HashCmdable interface
  method HDel (line 49) | func (c cmdable) HDel(ctx context.Context, key string, fields ...string)...
  method HExists (line 61) | func (c cmdable) HExists(ctx context.Context, key, field string) *BoolCmd {
  method HGet (line 67) | func (c cmdable) HGet(ctx context.Context, key, field string) *StringCmd {
  method HGetAll (line 73) | func (c cmdable) HGetAll(ctx context.Context, key string) *MapStringStri...
  method HIncrBy (line 79) | func (c cmdable) HIncrBy(ctx context.Context, key, field string, incr in...
  method HIncrByFloat (line 85) | func (c cmdable) HIncrByFloat(ctx context.Context, key, field string, in...
  method HKeys (line 91) | func (c cmdable) HKeys(ctx context.Context, key string) *StringSliceCmd {
  method HLen (line 97) | func (c cmdable) HLen(ctx context.Context, key string) *IntCmd {
  method HMGet (line 105) | func (c cmdable) HMGet(ctx context.Context, key string, fields ...string...
  method HSet (line 141) | func (c cmdable) HSet(ctx context.Context, key string, values ...interfa...
  method HMSet (line 152) | func (c cmdable) HMSet(ctx context.Context, key string, values ...interf...
  method HSetNX (line 162) | func (c cmdable) HSetNX(ctx context.Context, key, field string, value in...
  method HVals (line 168) | func (c cmdable) HVals(ctx context.Context, key string) *StringSliceCmd {
  method HRandField (line 175) | func (c cmdable) HRandField(ctx context.Context, key string, count int) ...
  method HRandFieldWithValues (line 182) | func (c cmdable) HRandFieldWithValues(ctx context.Context, key string, c...
  method HScan (line 188) | func (c cmdable) HScan(ctx context.Context, key string, cursor uint64, m...
  method HStrLen (line 204) | func (c cmdable) HStrLen(ctx context.Context, key, field string) *IntCmd {
  method HScanNoValues (line 209) | func (c cmdable) HScanNoValues(ctx context.Context, key string, cursor u...
  type HExpireArgs (line 226) | type HExpireArgs struct
  method HExpire (line 239) | func (c cmdable) HExpire(ctx context.Context, key string, expiration tim...
  method HExpireWithArgs (line 257) | func (c cmdable) HExpireWithArgs(ctx context.Context, key string, expira...
  method HPExpire (line 289) | func (c cmdable) HPExpire(ctx context.Context, key string, expiration ti...
  method HPExpireWithArgs (line 307) | func (c cmdable) HPExpireWithArgs(ctx context.Context, key string, expir...
  method HExpireAt (line 339) | func (c cmdable) HExpireAt(ctx context.Context, key string, tm time.Time...
  method HExpireAtWithArgs (line 351) | func (c cmdable) HExpireAtWithArgs(ctx context.Context, key string, tm t...
  method HPExpireAt (line 382) | func (c cmdable) HPExpireAt(ctx context.Context, key string, tm time.Tim...
  method HPExpireAtWithArgs (line 393) | func (c cmdable) HPExpireAtWithArgs(ctx context.Context, key string, tm ...
  method HPersist (line 425) | func (c cmdable) HPersist(ctx context.Context, key string, fields ...str...
  method HExpireTime (line 444) | func (c cmdable) HExpireTime(ctx context.Context, key string, fields ......
  method HPExpireTime (line 463) | func (c cmdable) HPExpireTime(ctx context.Context, key string, fields .....
  method HTTL (line 481) | func (c cmdable) HTTL(ctx context.Context, key string, fields ...string)...
  method HPTTL (line 500) | func (c cmdable) HPTTL(ctx context.Context, key string, fields ...string...
  method HGetDel (line 511) | func (c cmdable) HGetDel(ctx context.Context, key string, fields ...stri...
  method HGetEX (line 521) | func (c cmdable) HGetEX(ctx context.Context, key string, fields ...strin...
  type HGetEXExpirationType (line 532) | type HGetEXExpirationType
  constant HGetEXExpirationEX (line 535) | HGetEXExpirationEX      HGetEXExpirationType = "EX"
  constant HGetEXExpirationPX (line 536) | HGetEXExpirationPX      HGetEXExpirationType = "PX"
  constant HGetEXExpirationEXAT (line 537) | HGetEXExpirationEXAT    HGetEXExpirationType = "EXAT"
  constant HGetEXExpirationPXAT (line 538) | HGetEXExpirationPXAT    HGetEXExpirationType = "PXAT"
  constant HGetEXExpirationPERSIST (line 539) | HGetEXExpirationPERSIST HGetEXExpirationType = "PERSIST"
  type HGetEXOptions (line 542) | type HGetEXOptions struct
  method HGetEXWithArgs (line 547) | func (c cmdable) HGetEXWithArgs(ctx context.Context, key string, options...
  type HSetEXCondition (line 566) | type HSetEXCondition
  constant HSetEXFNX (line 569) | HSetEXFNX HSetEXCondition = "FNX"
  constant HSetEXFXX (line 570) | HSetEXFXX HSetEXCondition = "FXX"
  type HSetEXExpirationType (line 573) | type HSetEXExpirationType
  constant HSetEXExpirationEX (line 576) | HSetEXExpirationEX      HSetEXExpirationType = "EX"
  constant HSetEXExpirationPX (line 577) | HSetEXExpirationPX      HSetEXExpirationType = "PX"
  constant HSetEXExpirationEXAT (line 578) | HSetEXExpirationEXAT    HSetEXExpirationType = "EXAT"
  constant HSetEXExpirationPXAT (line 579) | HSetEXExpirationPXAT    HSetEXExpirationType = "PXAT"
  constant HSetEXExpirationKEEPTTL (line 580) | HSetEXExpirationKEEPTTL HSetEXExpirationType = "KEEPTTL"
  type HSetEXOptions (line 583) | type HSetEXOptions struct
  method HSetEX (line 589) | func (c cmdable) HSetEX(ctx context.Context, key string, fieldsAndValues...
  method HSetEXWithArgs (line 600) | func (c cmdable) HSetEXWithArgs(ctx context.Context, key string, options...

FILE: helper/helper.go
  function ParseFloat (line 8) | func ParseFloat(s string) (float64, error) {
  function MustParseFloat (line 12) | func MustParseFloat(s string) float64 {
  function DigestBytes (line 20) | func DigestBytes(data []byte) uint64 {
  function DigestString (line 28) | func DigestString(s string) uint64 {

FILE: helper/helper_test.go
  constant goldenTestValue (line 13) | goldenTestValue   = "myvalue"
  constant goldenRedisDigest (line 14) | goldenRedisDigest = uint64(0x5a32b091fa5dafe7)
  function TestDigestString_RedisCompatibility (line 17) | func TestDigestString_RedisCompatibility(t *testing.T) {
  function TestDigestBytes_RedisCompatibility (line 26) | func TestDigestBytes_RedisCompatibility(t *testing.T) {
  function TestDigestString_EqualsDigestBytes (line 35) | func TestDigestString_EqualsDigestBytes(t *testing.T) {
  function BenchmarkDigestString (line 57) | func BenchmarkDigestString(b *testing.B) {
  function BenchmarkDigestBytes (line 77) | func BenchmarkDigestBytes(b *testing.B) {

FILE: hotkeys_commands.go
  type HotKeysMetric (line 23) | type HotKeysMetric
  constant HotKeysMetricCPU (line 27) | HotKeysMetricCPU HotKeysMetric = "CPU"
  constant HotKeysMetricNET (line 29) | HotKeysMetricNET HotKeysMetric = "NET"
  type HotKeysStartArgs (line 35) | type HotKeysStartArgs struct
  method HotKeysStart (line 59) | func (c *Client) HotKeysStart(ctx context.Context, args *HotKeysStartArg...
  method HotKeysStop (line 101) | func (c *Client) HotKeysStop(ctx context.Context) *StatusCmd {
  method HotKeysReset (line 110) | func (c *Client) HotKeysReset(ctx context.Context) *StatusCmd {
  method HotKeysGet (line 118) | func (c *Client) HotKeysGet(ctx context.Context) *HotKeysCmd {

FILE: hset_benchmark_test.go
  function BenchmarkHSET (line 36) | func BenchmarkHSET(b *testing.B) {
  function benchmarkHSETOperations (line 66) | func benchmarkHSETOperations(b *testing.B, rdb *redis.Client, ctx contex...
  function benchmarkHSETOperationsConcurrent (line 113) | func benchmarkHSETOperationsConcurrent(b *testing.B, rdb *redis.Client, ...
  function BenchmarkHSETPipelined (line 184) | func BenchmarkHSETPipelined(b *testing.B) {
  function BenchmarkHSET_Concurrent (line 213) | func BenchmarkHSET_Concurrent(b *testing.B) {
  function benchmarkHSETPipelined (line 245) | func benchmarkHSETPipelined(b *testing.B, rdb *redis.Client, ctx context...
  function BenchmarkHSET_RESP2 (line 296) | func BenchmarkHSET_RESP2(b *testing.B) {
  function BenchmarkHSETPipelined_RESP2 (line 327) | func BenchmarkHSETPipelined_RESP2(b *testing.B) {

FILE: hyperloglog_commands.go
  type HyperLogLogCmdable (line 5) | type HyperLogLogCmdable interface
  method PFAdd (line 11) | func (c cmdable) PFAdd(ctx context.Context, key string, els ...interface...
  method PFCount (line 21) | func (c cmdable) PFCount(ctx context.Context, keys ...string) *IntCmd {
  method PFMerge (line 32) | func (c cmdable) PFMerge(ctx context.Context, dest string, keys ...strin...

FILE: internal/arg.go
  function AppendArg (line 11) | func AppendArg(b []byte, v interface{}) []byte {
  function appendUTF8String (line 55) | func appendUTF8String(dst []byte, src []byte) []byte {

FILE: internal/auth/streaming/conn_reauth_credentials_listener.go
  type ConnReAuthCredentialsListener (line 24) | type ConnReAuthCredentialsListener struct
    method OnNext (line 54) | func (c *ConnReAuthCredentialsListener) OnNext(credentials auth.Creden...
    method OnError (line 91) | func (c *ConnReAuthCredentialsListener) OnError(err error) {

FILE: internal/auth/streaming/cred_listeners.go
  type CredentialsListeners (line 19) | type CredentialsListeners struct
    method Add (line 41) | func (c *CredentialsListeners) Add(connID uint64, listener auth.Creden...
    method Get (line 57) | func (c *CredentialsListeners) Get(connID uint64) (auth.CredentialsLis...
    method Remove (line 73) | func (c *CredentialsListeners) Remove(connID uint64) {
  function NewCredentialsListeners (line 28) | func NewCredentialsListeners() *CredentialsListeners {

FILE: internal/auth/streaming/manager.go
  type Manager (line 26) | type Manager struct
    method PoolHook (line 59) | func (m *Manager) PoolHook() pool.PoolHook {
    method Listener (line 82) | func (m *Manager) Listener(
    method MarkForReAuth (line 121) | func (m *Manager) MarkForReAuth(poolCn *pool.Conn, reAuthFn func(error...
    method RemoveListener (line 135) | func (m *Manager) RemoveListener(connID uint64) {
  function NewManager (line 45) | func NewManager(pl pool.Pooler, reAuthTimeout time.Duration) *Manager {

FILE: internal/auth/streaming/manager_test.go
  function TestManager_Listener_ReturnsNewListener (line 13) | func TestManager_Listener_ReturnsNewListener(t *testing.T) {
  function TestManager_Listener_NilConn (line 66) | func TestManager_Listener_NilConn(t *testing.T) {
  type mockPooler (line 87) | type mockPooler struct
    method NewConn (line 89) | func (m *mockPooler) NewConn(ctx context.Context) (*pool.Conn, error) ...
    method CloseConn (line 90) | func (m *mockPooler) CloseConn(context.Context, *pool.Conn, string, st...
    method Get (line 91) | func (m *mockPooler) Get(ctx context.Context) (*pool.Conn, error)     ...
    method Put (line 92) | func (m *mockPooler) Put(ctx context.Context, conn *pool.Conn)        ...
    method Remove (line 93) | func (m *mockPooler) Remove(ctx context.Context, conn *pool.Conn, reas...
    method RemoveWithoutTurn (line 94) | func (m *mockPooler) RemoveWithoutTurn(ctx context.Context, conn *pool...
    method Len (line 95) | func (m *mockPooler) Len() int                                        ...
    method IdleLen (line 96) | func (m *mockPooler) IdleLen() int                                    ...
    method Stats (line 97) | func (m *mockPooler) Stats() *pool.Stats                              ...
    method Size (line 98) | func (m *mockPooler) Size() int                                       ...
    method AddPoolHook (line 99) | func (m *mockPooler) AddPoolHook(hook pool.PoolHook)                  ...
    method RemovePoolHook (line 100) | func (m *mockPooler) RemovePoolHook(hook pool.PoolHook)               ...
    method Close (line 101) | func (m *mockPooler) Close() error                                    ...

FILE: internal/auth/streaming/pool_hook.go
  type ReAuthPoolHook (line 31) | type ReAuthPoolHook struct
    method MarkForReAuth (line 82) | func (r *ReAuthPoolHook) MarkForReAuth(connID uint64, reAuthFn func(er...
    method OnGet (line 99) | func (r *ReAuthPoolHook) OnGet(_ context.Context, conn *pool.Conn, _ b...
    method OnPut (line 139) | func (r *ReAuthPoolHook) OnPut(_ context.Context, conn *pool.Conn) (bo...
    method OnRemove (line 228) | func (r *ReAuthPoolHook) OnRemove(_ context.Context, conn *pool.Conn, ...
  function NewReAuthPoolHook (line 62) | func NewReAuthPoolHook(poolSize int, reAuthTimeout time.Duration) *ReAut...

FILE: internal/auth/streaming/pool_hook_state_test.go
  function TestReAuthOnlyWhenIdle (line 14) | func TestReAuthOnlyWhenIdle(t *testing.T) {
  function TestReAuthWaitsForConnectionToBeIdle (line 67) | func TestReAuthWaitsForConnectionToBeIdle(t *testing.T) {
  function TestConcurrentReAuthAndUsage (line 153) | func TestConcurrentReAuthAndUsage(t *testing.T) {
  function TestReAuthRespectsClosed (line 219) | func TestReAuthRespectsClosed(t *testing.T) {

FILE: internal/customvet/checks/setval/setval.go
  function parseFuncDecl (line 42) | func parseFuncDecl(decl ast.Decl, typesInfo *types.Info) (funcName, rece...

FILE: internal/customvet/checks/setval/setval_test.go
  function Test (line 11) | func Test(t *testing.T) {

FILE: internal/customvet/checks/setval/testdata/src/a/a.go
  type GoodCmd (line 3) | type GoodCmd struct
    method SetVal (line 7) | func (c *GoodCmd) SetVal(val int) {
    method Result (line 11) | func (c *GoodCmd) Result() (int, error) {
  type BadCmd (line 15) | type BadCmd struct
    method Result (line 19) | func (c *BadCmd) Result() (int, error) { // want "\\*a.BadCmd is missi...
  type NotACmd (line 23) | type NotACmd struct
    method Val (line 27) | func (c *NotACmd) Val() int {

FILE: internal/customvet/main.go
  function main (line 9) | func main() {

FILE: internal/hashtag/hashtag.go
  constant slotNumber (line 9) | slotNumber = 16384
  function Key (line 50) | func Key(key string) string {
  function Present (line 59) | func Present(key string) bool {
  function RandomSlot (line 71) | func RandomSlot() int {
  function Slot (line 77) | func Slot(key string) int {
  function crc16sum (line 85) | func crc16sum(key string) (crc uint16) {

FILE: internal/hashtag/hashtag_test.go
  function TestGinkgoSuite (line 12) | func TestGinkgoSuite(t *testing.T) {

FILE: internal/hscan/hscan.go
  type decoderFunc (line 11) | type decoderFunc
  type Scanner (line 15) | type Scanner interface
  function Struct (line 55) | func Struct(dst interface{}) (StructValue, error) {
  function Scan (line 76) | func Scan(dst interface{}, keys []interface{}, vals []interface{}) error {
  function decodeBool (line 106) | func decodeBool(f reflect.Value, s string) error {
  function decodeInt8 (line 115) | func decodeInt8(f reflect.Value, s string) error {
  function decodeInt16 (line 119) | func decodeInt16(f reflect.Value, s string) error {
  function decodeInt32 (line 123) | func decodeInt32(f reflect.Value, s string) error {
  function decodeInt64 (line 127) | func decodeInt64(f reflect.Value, s string) error {
  function decodeInt (line 131) | func decodeInt(f reflect.Value, s string) error {
  function decodeNumber (line 135) | func decodeNumber(f reflect.Value, s string, bitSize int) error {
  function decodeUint8 (line 144) | func decodeUint8(f reflect.Value, s string) error {
  function decodeUint16 (line 148) | func decodeUint16(f reflect.Value, s string) error {
  function decodeUint32 (line 152) | func decodeUint32(f reflect.Value, s string) error {
  function decodeUint64 (line 156) | func decodeUint64(f reflect.Value, s string) error {
  function decodeUint (line 160) | func decodeUint(f reflect.Value, s string) error {
  function decodeUnsignedNumber (line 164) | func decodeUnsignedNumber(f reflect.Value, s string, bitSize int) error {
  function decodeFloat32 (line 173) | func decodeFloat32(f reflect.Value, s string) error {
  function decodeFloat64 (line 183) | func decodeFloat64(f reflect.Value, s string) error {
  function decodeString (line 192) | func decodeString(f reflect.Value, s string) error {
  function decodeSlice (line 197) | func decodeSlice(f reflect.Value, s string) error {
  function decodeUnsupported (line 205) | func decodeUnsupported(v reflect.Value, s string) error {

FILE: internal/hscan/hscan_test.go
  type data (line 15) | type data struct
  type TimeRFC3339Nano (line 37) | type TimeRFC3339Nano struct
    method ScanRedis (line 41) | func (t *TimeRFC3339Nano) ScanRedis(s string) (err error) {
  type TimeData (line 46) | type TimeData struct
  type i (line 51) | type i
  function TestGinkgoSuite (line 53) | func TestGinkgoSuite(t *testing.T) {

FILE: internal/hscan/structmap.go
  type structMap (line 15) | type structMap struct
    method get (line 23) | func (s *structMap) get(t reflect.Type) *structSpec {
  function newStructMap (line 19) | func newStructMap() *structMap {
  type structSpec (line 36) | type structSpec struct
    method set (line 40) | func (s *structSpec) set(tag string, sf *structField) {
  function newStructSpec (line 44) | func newStructSpec(t reflect.Type, fieldTag string) *structSpec {
  type structField (line 77) | type structField struct
  type StructValue (line 84) | type StructValue struct
    method Scan (line 89) | func (s StructValue) Scan(key string, value string) error {

FILE: internal/interfaces/interfaces.go
  type NotificationProcessor (line 13) | type NotificationProcessor interface
  type ClientInterface (line 20) | type ClientInterface interface
  type OptionsInterface (line 30) | type OptionsInterface interface

FILE: internal/internal.go
  function RetryBackoff (line 9) | func RetryBackoff(retry int, minBackoff, maxBackoff time.Duration) time....

FILE: internal/internal_test.go
  function TestRetryBackoff (line 10) | func TestRetryBackoff(t *testing.T) {

FILE: internal/log.go
  type Logging (line 13) | type Logging interface
  type DefaultLogger (line 17) | type DefaultLogger struct
    method Printf (line 21) | func (l *DefaultLogger) Printf(ctx context.Context, format string, v ....
  function NewDefaultLogger (line 25) | func NewDefaultLogger() Logging {
  type LogLevelT (line 38) | type LogLevelT
    method String (line 49) | func (l LogLevelT) String() string {
    method IsValid (line 65) | func (l LogLevelT) IsValid() bool {
    method WarnOrAbove (line 69) | func (l LogLevelT) WarnOrAbove() bool {
    method InfoOrAbove (line 73) | func (l LogLevelT) InfoOrAbove() bool {
    method DebugOrAbove (line 77) | func (l LogLevelT) DebugOrAbove() bool {
  constant LogLevelError (line 42) | LogLevelError LogLevelT = iota
  constant LogLevelWarn (line 43) | LogLevelWarn
  constant LogLevelInfo (line 44) | LogLevelInfo
  constant LogLevelDebug (line 45) | LogLevelDebug

FILE: internal/maintnotifications/logs/log_messages.go
  function appendJSONIfDebug (line 12) | func appendJSONIfDebug(message string, data map[string]interface{}) stri...
  constant CircuitBreakerTransitioningToHalfOpenMessage (line 24) | CircuitBreakerTransitioningToHalfOpenMessage = "circuit breaker transiti...
  constant CircuitBreakerOpenedMessage (line 25) | CircuitBreakerOpenedMessage                  = "circuit breaker opened"
  constant CircuitBreakerReopenedMessage (line 26) | CircuitBreakerReopenedMessage                = "circuit breaker reopened"
  constant CircuitBreakerClosedMessage (line 27) | CircuitBreakerClosedMessage                  = "circuit breaker closed"
  constant CircuitBreakerCleanupMessage (line 28) | CircuitBreakerCleanupMessage                 = "circuit breaker cleanup"
  constant CircuitBreakerOpenMessage (line 29) | CircuitBreakerOpenMessage                    = "circuit breaker is open,...
  constant DebugLoggingEnabledMessage (line 34) | DebugLoggingEnabledMessage = "debug logging enabled"
  constant ConfigDebugMessage (line 35) | ConfigDebugMessage         = "config debug"
  constant InvalidRelaxedTimeoutErrorMessage (line 40) | InvalidRelaxedTimeoutErrorMessage                 = "relaxed timeout mus...
  constant InvalidHandoffTimeoutErrorMessage (line 41) | InvalidHandoffTimeoutErrorMessage                 = "handoff timeout mus...
  constant InvalidHandoffWorkersErrorMessage (line 42) | InvalidHandoffWorkersErrorMessage                 = "MaxWorkers must be ...
  constant InvalidHandoffQueueSizeErrorMessage (line 43) | InvalidHandoffQueueSizeErrorMessage               = "handoff queue size ...
  constant InvalidPostHandoffRelaxedDurationErrorMessage (line 44) | InvalidPostHandoffRelaxedDurationErrorMessage     = "post-handoff relaxe...
  constant InvalidEndpointTypeErrorMessage (line 45) | InvalidEndpointTypeErrorMessage                   = "invalid endpoint type"
  constant InvalidMaintNotificationsErrorMessage (line 46) | InvalidMaintNotificationsErrorMessage             = "invalid maintenance...
  constant InvalidHandoffRetriesErrorMessage (line 47) | InvalidHandoffRetriesErrorMessage                 = "MaxHandoffRetries m...
  constant InvalidClientErrorMessage (line 48) | InvalidClientErrorMessage                         = "invalid client type"
  constant InvalidNotificationErrorMessage (line 49) | InvalidNotificationErrorMessage                   = "invalid notificatio...
  constant MaxHandoffRetriesReachedErrorMessage (line 50) | MaxHandoffRetriesReachedErrorMessage              = "max handoff retries...
  constant HandoffQueueFullErrorMessage (line 51) | HandoffQueueFullErrorMessage                      = "handoff queue is fu...
  constant InvalidCircuitBreakerFailureThresholdErrorMessage (line 52) | InvalidCircuitBreakerFailureThresholdErrorMessage = "circuit breaker fai...
  constant InvalidCircuitBreakerResetTimeoutErrorMessage (line 53) | InvalidCircuitBreakerResetTimeoutErrorMessage     = "circuit breaker res...
  constant InvalidCircuitBreakerMaxRequestsErrorMessage (line 54) | InvalidCircuitBreakerMaxRequestsErrorMessage      = "circuit breaker max...
  constant ConnectionMarkedForHandoffErrorMessage (line 55) | ConnectionMarkedForHandoffErrorMessage            = "connection marked f...
  constant ConnectionInvalidHandoffStateErrorMessage (line 56) | ConnectionInvalidHandoffStateErrorMessage         = "connection is in in...
  constant ShutdownErrorMessage (line 57) | ShutdownErrorMessage                              = "shutdown"
  constant CircuitBreakerOpenErrorMessage (line 58) | CircuitBreakerOpenErrorMessage                    = "circuit breaker is ...
  constant MetricsHookProcessingNotificationMessage (line 63) | MetricsHookProcessingNotificationMessage = "metrics hook processing"
  constant MetricsHookRecordedErrorMessage (line 64) | MetricsHookRecordedErrorMessage          = "metrics hook recorded error"
  constant HandoffStartedMessage (line 69) | HandoffStartedMessage                            = "handoff started"
  constant HandoffFailedMessage (line 70) | HandoffFailedMessage                             = "handoff failed"
  constant ConnectionNotMarkedForHandoffMessage (line 71) | ConnectionNotMarkedForHandoffMessage             = "is not marked for ha...
  constant ConnectionNotMarkedForHandoffErrorMessage (line 72) | ConnectionNotMarkedForHandoffErrorMessage        = "is not marked for ha...
  constant HandoffRetryAttemptMessage (line 73) | HandoffRetryAttemptMessage                       = "Performing handoff"
  constant CannotQueueHandoffForRetryMessage (line 74) | CannotQueueHandoffForRetryMessage                = "can't queue handoff ...
  constant HandoffQueueFullMessage (line 75) | HandoffQueueFullMessage                          = "handoff queue is full"
  constant FailedToDialNewEndpointMessage (line 76) | FailedToDialNewEndpointMessage                   = "failed to dial new e...
  constant ApplyingRelaxedTimeoutDueToPostHandoffMessage (line 77) | ApplyingRelaxedTimeoutDueToPostHandoffMessage    = "applying relaxed tim...
  constant HandoffSuccessMessage (line 78) | HandoffSuccessMessage                            = "handoff succeeded"
  constant RemovingConnectionFromPoolMessage (line 79) | RemovingConnectionFromPoolMessage                = "removing connection ...
  constant NoPoolProvidedMessageCannotRemoveMessage (line 80) | NoPoolProvidedMessageCannotRemoveMessage         = "no pool provided, ca...
  constant WorkerExitingDueToShutdownMessage (line 81) | WorkerExitingDueToShutdownMessage                = "worker exiting due t...
  constant WorkerExitingDueToShutdownWhileProcessingMessage (line 82) | WorkerExitingDueToShutdownWhileProcessingMessage = "worker exiting due t...
  constant WorkerPanicRecoveredMessage (line 83) | WorkerPanicRecoveredMessage                      = "worker panic recovered"
  constant WorkerExitingDueToInactivityTimeoutMessage (line 84) | WorkerExitingDueToInactivityTimeoutMessage       = "worker exiting due t...
  constant ReachedMaxHandoffRetriesMessage (line 85) | ReachedMaxHandoffRetriesMessage                  = "reached max handoff ...
  constant DuplicateMovingOperationMessage (line 90) | DuplicateMovingOperationMessage  = "duplicate MOVING operation ignored"
  constant TrackingMovingOperationMessage (line 91) | TrackingMovingOperationMessage   = "tracking MOVING operation"
  constant UntrackingMovingOperationMessage (line 92) | UntrackingMovingOperationMessage = "untracking MOVING operation"
  constant OperationNotTrackedMessage (line 93) | OperationNotTrackedMessage       = "operation not tracked"
  constant FailedToRegisterHandlerMessage (line 94) | FailedToRegisterHandlerMessage   = "failed to register handler"
  constant ProcessingNotificationMessage (line 99) | ProcessingNotificationMessage          = "processing notification started"
  constant ProcessingNotificationFailedMessage (line 100) | ProcessingNotificationFailedMessage    = "proccessing notification failed"
  constant ProcessingNotificationSucceededMessage (line 101) | ProcessingNotificationSucceededMessage = "processing notification succee...
  constant FailedToQueueHandoffMessage (line 106) | FailedToQueueHandoffMessage = "failed to queue handoff"
  constant MarkedForHandoffMessage (line 107) | MarkedForHandoffMessage     = "connection marked for handoff"
  constant InvalidNotificationFormatMessage (line 112) | InvalidNotificationFormatMessage              = "invalid notification fo...
  constant InvalidNotificationTypeFormatMessage (line 113) | InvalidNotificationTypeFormatMessage          = "invalid notification ty...
  constant InvalidSeqIDInMovingNotificationMessage (line 114) | InvalidSeqIDInMovingNotificationMessage       = "invalid seqID in MOVING...
  constant InvalidTimeSInMovingNotificationMessage (line 115) | InvalidTimeSInMovingNotificationMessage       = "invalid timeS in MOVING...
  constant InvalidNewEndpointInMovingNotificationMessage (line 116) | InvalidNewEndpointInMovingNotificationMessage = "invalid newEndpoint in ...
  constant NoConnectionInHandlerContextMessage (line 117) | NoConnectionInHandlerContextMessage           = "no connection in handle...
  constant InvalidConnectionTypeInHandlerContextMessage (line 118) | InvalidConnectionTypeInHandlerContextMessage  = "invalid connection type...
  constant SchedulingHandoffToCurrentEndpointMessage (line 119) | SchedulingHandoffToCurrentEndpointMessage     = "scheduling handoff to c...
  constant RelaxedTimeoutDueToNotificationMessage (line 120) | RelaxedTimeoutDueToNotificationMessage        = "applying relaxed timeou...
  constant UnrelaxedTimeoutMessage (line 121) | UnrelaxedTimeoutMessage                       = "clearing relaxed timeout"
  constant ManagerNotInitializedMessage (line 122) | ManagerNotInitializedMessage                  = "manager not initialized"
  constant FailedToMarkForHandoffMessage (line 123) | FailedToMarkForHandoffMessage                 = "failed to mark connecti...
  constant InvalidSeqIDInSMigratingNotificationMessage (line 124) | InvalidSeqIDInSMigratingNotificationMessage   = "invalid SeqID in SMIGRA...
  constant InvalidSeqIDInSMigratedNotificationMessage (line 125) | InvalidSeqIDInSMigratedNotificationMessage    = "invalid SeqID in SMIGRA...
  constant TriggeringClusterStateReloadMessage (line 126) | TriggeringClusterStateReloadMessage           = "triggering cluster stat...
  constant UnrelaxedTimeoutAfterDeadlineMessage (line 131) | UnrelaxedTimeoutAfterDeadlineMessage = "clearing relaxed timeout after d...
  function HandoffStarted (line 134) | func HandoffStarted(connID uint64, newEndpoint string) string {
  function HandoffFailed (line 142) | func HandoffFailed(connID uint64, newEndpoint string, attempt int, maxAt...
  function HandoffSucceeded (line 153) | func HandoffSucceeded(connID uint64, newEndpoint string) string {
  function RelaxedTimeoutDueToNotification (line 162) | func RelaxedTimeoutDueToNotification(connID uint64, notificationType str...
  function UnrelaxedTimeout (line 171) | func UnrelaxedTimeout(connID uint64) string {
  function UnrelaxedTimeoutAfterDeadline (line 178) | func UnrelaxedTimeoutAfterDeadline(connID uint64) string {
  function HandoffQueueFull (line 186) | func HandoffQueueFull(queueLen, queueCap int) string {
  function FailedToQueueHandoff (line 194) | func FailedToQueueHandoff(connID uint64, err error) string {
  function FailedToMarkForHandoff (line 202) | func FailedToMarkForHandoff(connID uint64, err error) string {
  function FailedToDialNewEndpoint (line 210) | func FailedToDialNewEndpoint(connID uint64, endpoint string, err error) ...
  function ReachedMaxHandoffRetries (line 219) | func ReachedMaxHandoffRetries(connID uint64, endpoint string, maxRetries...
  function ProcessingNotification (line 229) | func ProcessingNotification(connID uint64, seqID int64, notificationType...
  function ProcessingNotificationFailed (line 239) | func ProcessingNotificationFailed(connID uint64, notificationType string...
  function ProcessingNotificationSucceeded (line 249) | func ProcessingNotificationSucceeded(connID uint64, notificationType str...
  function DuplicateMovingOperation (line 258) | func DuplicateMovingOperation(connID uint64, endpoint string, seqID int6...
  function TrackingMovingOperation (line 267) | func TrackingMovingOperation(connID uint64, endpoint string, seqID int64...
  function UntrackingMovingOperation (line 276) | func UntrackingMovingOperation(connID uint64, seqID int64) string {
  function OperationNotTracked (line 284) | func OperationNotTracked(connID uint64, seqID int64) string {
  function RemovingConnectionFromPool (line 293) | func RemovingConnectionFromPool(connID uint64, reason error) string {
  function NoPoolProvidedCannotRemove (line 306) | func NoPoolProvidedCannotRemove(connID uint64, reason error) string {
  function CircuitBreakerOpen (line 320) | func CircuitBreakerOpen(connID uint64, endpoint string) string {
  function ConnectionNotMarkedForHandoff (line 329) | func ConnectionNotMarkedForHandoff(connID uint64) string {
  function ConnectionNotMarkedForHandoffError (line 336) | func ConnectionNotMarkedForHandoffError(connID uint64) string {
  function HandoffRetryAttempt (line 340) | func HandoffRetryAttempt(connID uint64, retries int, newEndpoint string,...
  function CannotQueueHandoffForRetry (line 350) | func CannotQueueHandoffForRetry(err error) string {
  function InvalidNotificationFormat (line 358) | func InvalidNotificationFormat(notification interface{}) string {
  function InvalidNotificationTypeFormat (line 365) | func InvalidNotificationTypeFormat(notificationType interface{}) string {
  function InvalidNotification (line 373) | func InvalidNotification(notificationType string, notification interface...
  function InvalidSeqIDInMovingNotification (line 381) | func InvalidSeqIDInMovingNotification(seqID interface{}) string {
  function InvalidTimeSInMovingNotification (line 388) | func InvalidTimeSInMovingNotification(timeS interface{}) string {
  function InvalidNewEndpointInMovingNotification (line 395) | func InvalidNewEndpointInMovingNotification(newEndpoint interface{}) str...
  function NoConnectionInHandlerContext (line 402) | func NoConnectionInHandlerContext(notificationType string) string {
  function InvalidConnectionTypeInHandlerContext (line 409) | func InvalidConnectionTypeInHandlerContext(notificationType string, conn...
  function SchedulingHandoffToCurrentEndpoint (line 417) | func SchedulingHandoffToCurrentEndpoint(connID uint64, seconds float64) ...
  function ManagerNotInitialized (line 425) | func ManagerNotInitialized() string {
  function FailedToRegisterHandler (line 429) | func FailedToRegisterHandler(notificationType string, err error) string {
  function ShutdownError (line 437) | func ShutdownError() string {
  function InvalidRelaxedTimeoutError (line 442) | func InvalidRelaxedTimeoutError() string {
  function InvalidHandoffTimeoutError (line 446) | func InvalidHandoffTimeoutError() string {
  function InvalidHandoffWorkersError (line 450) | func InvalidHandoffWorkersError() string {
  function InvalidHandoffQueueSizeError (line 454) | func InvalidHandoffQueueSizeError() string {
  function InvalidPostHandoffRelaxedDurationError (line 458) | func InvalidPostHandoffRelaxedDurationError() string {
  function InvalidEndpointTypeError (line 462) | func InvalidEndpointTypeError() string {
  function InvalidMaintNotificationsError (line 466) | func InvalidMaintNotificationsError() string {
  function InvalidHandoffRetriesError (line 470) | func InvalidHandoffRetriesError() string {
  function InvalidClientError (line 474) | func InvalidClientError() string {
  function InvalidNotificationError (line 478) | func InvalidNotificationError() string {
  function MaxHandoffRetriesReachedError (line 482) | func MaxHandoffRetriesReachedError() string {
  function HandoffQueueFullError (line 486) | func HandoffQueueFullError() string {
  function InvalidCircuitBreakerFailureThresholdError (line 490) | func InvalidCircuitBreakerFailureThresholdError() string {
  function InvalidCircuitBreakerResetTimeoutError (line 494) | func InvalidCircuitBreakerResetTimeoutError() string {
  function InvalidCircuitBreakerMaxRequestsError (line 498) | func InvalidCircuitBreakerMaxRequestsError() string {
  function DebugLoggingEnabled (line 503) | func DebugLoggingEnabled() string {
  function ConfigDebug (line 507) | func ConfigDebug(config interface{}) string {
  function WorkerExitingDueToShutdown (line 515) | func WorkerExitingDueToShutdown() string {
  function WorkerExitingDueToShutdownWhileProcessing (line 519) | func WorkerExitingDueToShutdownWhileProcessing() string {
  function WorkerPanicRecovered (line 523) | func WorkerPanicRecovered(panicValue interface{}) string {
  function WorkerExitingDueToInactivityTimeout (line 530) | func WorkerExitingDueToInactivityTimeout(timeout interface{}) string {
  function ApplyingRelaxedTimeoutDueToPostHandoff (line 537) | func ApplyingRelaxedTimeoutDueToPostHandoff(connID uint64, timeout inter...
  function MetricsHookProcessingNotification (line 547) | func MetricsHookProcessingNotification(notificationType string, connID u...
  function MetricsHookRecordedError (line 555) | func MetricsHookRecordedError(notificationType string, connID uint64, er...
  function MarkedForHandoff (line 565) | func MarkedForHandoff(connID uint64) string {
  function CircuitBreakerTransitioningToHalfOpen (line 573) | func CircuitBreakerTransitioningToHalfOpen(endpoint string) string {
  function CircuitBreakerOpened (line 580) | func CircuitBreakerOpened(endpoint string, failures int64) string {
  function CircuitBreakerReopened (line 588) | func CircuitBreakerReopened(endpoint string) string {
  function CircuitBreakerClosed (line 595) | func CircuitBreakerClosed(endpoint string, successes int64) string {
  function CircuitBreakerCleanup (line 603) | func CircuitBreakerCleanup(removed int, total int) string {
  function ExtractDataFromLogMessage (line 615) | func ExtractDataFromLogMessage(logMessage string) map[string]interface{} {
  function InvalidSeqIDInSMigratingNotification (line 641) | func InvalidSeqIDInSMigratingNotification(seqID interface{}) string {
  function InvalidSeqIDInSMigratedNotification (line 648) | func InvalidSeqIDInSMigratedNotification(seqID interface{}) string {
  function TriggeringClusterStateReload (line 656) | func TriggeringClusterStateReload(seqID int64, hostPort string, slotRang...

FILE: internal/once.go
  type Once (line 28) | type Once struct
    method Do (line 48) | func (o *Once) Do(f func() error) error {

FILE: internal/otel/metrics.go
  function generateUniqueID (line 14) | func generateUniqueID() string {
  type Cmder (line 24) | type Cmder interface
  type Recorder (line 32) | type Recorder interface
  type PubSubPooler (line 90) | type PubSubPooler interface
  type PoolRegistrar (line 94) | type PoolRegistrar interface
  function GetOperationDurationCallback (line 124) | func GetOperationDurationCallback() func(ctx context.Context, duration t...
  function GetPipelineOperationDurationCallback (line 132) | func GetPipelineOperationDurationCallback() func(ctx context.Context, du...
  function getRecorder (line 140) | func getRecorder() Recorder {
  function SetGlobalRecorder (line 148) | func SetGlobalRecorder(r Recorder) {
  function RecordOperationDuration (line 201) | func RecordOperationDuration(ctx context.Context, duration time.Duration...
  function RecordPipelineOperationDuration (line 210) | func RecordPipelineOperationDuration(ctx context.Context, duration time....
  function RecordConnectionCreateTime (line 215) | func RecordConnectionCreateTime(ctx context.Context, duration time.Durat...
  function RecordPubSubMessage (line 220) | func RecordPubSubMessage(ctx context.Context, cn *pool.Conn, direction, ...
  function RecordStreamLag (line 225) | func RecordStreamLag(ctx context.Context, lag time.Duration, cn *pool.Co...
  type noopRecorder (line 229) | type noopRecorder struct
    method RecordOperationDuration (line 231) | func (noopRecorder) RecordOperationDuration(context.Context, time.Dura...
    method RecordPipelineOperationDuration (line 233) | func (noopRecorder) RecordPipelineOperationDuration(context.Context, t...
    method RecordConnectionCreateTime (line 235) | func (noopRecorder) RecordConnectionCreateTime(context.Context, time.D...
    method RecordConnectionRelaxedTimeout (line 236) | func (noopRecorder) RecordConnectionRelaxedTimeout(context.Context, in...
    method RecordConnectionHandoff (line 238) | func (noopRecorder) RecordConnectionHandoff(context.Context, *pool.Con...
    method RecordError (line 239) | func (noopRecorder) RecordError(context.Context, string, *pool.Conn, s...
    method RecordMaintenanceNotification (line 240) | func (noopRecorder) RecordMaintenanceNotification(context.Context, *po...
    method RecordConnectionWaitTime (line 242) | func (noopRecorder) RecordConnectionWaitTime(context.Context, time.Dur...
    method RecordConnectionClosed (line 243) | func (noopRecorder) RecordConnectionClosed(context.Context, *pool.Conn...
    method RecordPubSubMessage (line 245) | func (noopRecorder) RecordPubSubMessage(context.Context, *pool.Conn, s...
    method RecordStreamLag (line 247) | func (noopRecorder) RecordStreamLag(context.Context, time.Duration, *p...
  function RegisterPools (line 251) | func RegisterPools(connPool pool.Pooler, pubSubPool PubSubPooler, addr s...
  function UnregisterPools (line 269) | func UnregisterPools(connPool pool.Pooler, pubSubPool PubSubPooler) {

FILE: internal/pool/bench_test.go
  type poolGetPutBenchmark (line 13) | type poolGetPutBenchmark struct
    method String (line 17) | func (bm poolGetPutBenchmark) String() string {
  function BenchmarkPoolGetPut (line 21) | func BenchmarkPoolGetPut(b *testing.B) {
  type poolGetRemoveBenchmark (line 57) | type poolGetRemoveBenchmark struct
    method String (line 61) | func (bm poolGetRemoveBenchmark) String() string {
  function BenchmarkPoolGetRemove (line 65) | func BenchmarkPoolGetRemove(b *testing.B) {

FILE: internal/pool/buffer_size_test.go
  function getWriterBufSizeUnsafe (line 135) | func getWriterBufSizeUnsafe(cn *pool.Conn) int {
  function getReaderBufSizeUnsafe (line 163) | func getReaderBufSizeUnsafe(cn *pool.Conn) int {

FILE: internal/pool/conn.go
  function getCachedTimeNs (line 36) | func getCachedTimeNs() int64 {
  function GetCachedTimeNs (line 42) | func GetCachedTimeNs() int64 {
  type HandoffState (line 52) | type HandoffState struct
  type atomicNetConn (line 59) | type atomicNetConn struct
  function generateConnID (line 64) | func generateConnID() uint64 {
  type Conn (line 68) | type Conn struct
    method UsedAt (line 168) | func (cn *Conn) UsedAt() time.Time {
    method SetUsedAt (line 171) | func (cn *Conn) SetUsedAt(tm time.Time) {
    method UsedAtNs (line 175) | func (cn *Conn) UsedAtNs() int64 {
    method SetUsedAtNs (line 178) | func (cn *Conn) SetUsedAtNs(ns int64) {
    method LastPutAtNs (line 182) | func (cn *Conn) LastPutAtNs() int64 {
    method SetLastPutAtNs (line 185) | func (cn *Conn) SetLastPutAtNs(ns int64) {
    method GetDialStartNs (line 191) | func (cn *Conn) GetDialStartNs() int64 {
    method PoolName (line 197) | func (cn *Conn) PoolName() string {
    method SetPoolName (line 203) | func (cn *Conn) SetPoolName(name string) {
    method CompareAndSwapUsable (line 221) | func (cn *Conn) CompareAndSwapUsable(old, new bool) bool {
    method IsUsable (line 266) | func (cn *Conn) IsUsable() bool {
    method SetUsable (line 285) | func (cn *Conn) SetUsable(usable bool) {
    method IsInited (line 297) | func (cn *Conn) IsInited() bool {
    method CompareAndSwapUsed (line 315) | func (cn *Conn) CompareAndSwapUsed(old, new bool) bool {
    method IsUsed (line 344) | func (cn *Conn) IsUsed() bool {
    method SetUsed (line 356) | func (cn *Conn) SetUsed(val bool) {
    method getNetConn (line 366) | func (cn *Conn) getNetConn() net.Conn {
    method setNetConn (line 377) | func (cn *Conn) setNetConn(netConn net.Conn) {
    method ShouldHandoff (line 384) | func (cn *Conn) ShouldHandoff() bool {
    method GetHandoffEndpoint (line 392) | func (cn *Conn) GetHandoffEndpoint() string {
    method GetMovingSeqID (line 400) | func (cn *Conn) GetMovingSeqID() int64 {
    method GetHandoffInfo (line 410) | func (cn *Conn) GetHandoffInfo() (bool, string, int64) {
    method HandoffRetries (line 419) | func (cn *Conn) HandoffRetries() int {
    method IncrementAndGetHandoffRetries (line 424) | func (cn *Conn) IncrementAndGetHandoffRetries(n int) int {
    method IsPooled (line 429) | func (cn *Conn) IsPooled() bool {
    method IsPubSub (line 434) | func (cn *Conn) IsPubSub() bool {
    method SetRelaxedTimeout (line 443) | func (cn *Conn) SetRelaxedTimeout(readTimeout, writeTimeout time.Durat...
    method SetRelaxedTimeoutWithDeadline (line 452) | func (cn *Conn) SetRelaxedTimeoutWithDeadline(readTimeout, writeTimeou...
    method ClearRelaxedTimeout (line 459) | func (cn *Conn) ClearRelaxedTimeout() {
    method clearRelaxedTimeout (line 472) | func (cn *Conn) clearRelaxedTimeout() {
    method HasRelaxedTimeout (line 487) | func (cn *Conn) HasRelaxedTimeout() bool {
    method getEffectiveReadTimeout (line 514) | func (cn *Conn) getEffectiveReadTimeout(normalTimeout time.Duration) t...
    method getEffectiveWriteTimeout (line 548) | func (cn *Conn) getEffectiveWriteTimeout(normalTimeout time.Duration) ...
    method SetOnClose (line 579) | func (cn *Conn) SetOnClose(fn func() error) {
    method SetInitConnFunc (line 584) | func (cn *Conn) SetInitConnFunc(fn func(context.Context, *Conn) error) {
    method ExecuteInitConn (line 589) | func (cn *Conn) ExecuteInitConn(ctx context.Context) error {
    method SetNetConn (line 596) | func (cn *Conn) SetNetConn(netConn net.Conn) {
    method GetNetConn (line 610) | func (cn *Conn) GetNetConn() net.Conn {
    method SetNetConnAndInitConn (line 617) | func (cn *Conn) SetNetConnAndInitConn(ctx context.Context, netConn net...
    method MarkForHandoff (line 660) | func (cn *Conn) MarkForHandoff(newEndpoint string, seqID int64) error {
    method MarkQueuedForHandoff (line 679) | func (cn *Conn) MarkQueuedForHandoff() error {
    method GetID (line 727) | func (cn *Conn) GetID() uint64 {
    method GetStateMachine (line 733) | func (cn *Conn) GetStateMachine() *ConnStateMachine {
    method TryAcquire (line 752) | func (cn *Conn) TryAcquire() bool {
    method Release (line 770) | func (cn *Conn) Release() bool {
    method ClearHandoffState (line 777) | func (cn *Conn) ClearHandoffState() {
    method HasBufferedData (line 796) | func (cn *Conn) HasBufferedData() bool {
    method PeekReplyTypeSafe (line 805) | func (cn *Conn) PeekReplyTypeSafe() (byte, error) {
    method Write (line 816) | func (cn *Conn) Write(b []byte) (int, error) {
    method RemoteAddr (line 824) | func (cn *Conn) RemoteAddr() net.Addr {
    method WithReader (line 832) | func (cn *Conn) WithReader(
    method WithWriter (line 852) | func (cn *Conn) WithWriter(
    method IsClosed (line 884) | func (cn *Conn) IsClosed() bool {
    method Close (line 888) | func (cn *Conn) Close() error {
    method MaybeHasData (line 909) | func (cn *Conn) MaybeHasData() bool {
    method deadline (line 920) | func (cn *Conn) deadline(ctx context.Context, timeout time.Duration) t...
  function NewConn (line 128) | func NewConn(netConn net.Conn) *Conn {
  function NewConnWithBufferSize (line 132) | func NewConnWithBufferSize(netConn net.Conn, readBufSize, writeBufSize i...

FILE: internal/pool/conn_check.go
  function connCheck (line 18) | func connCheck(conn net.Conn) error {
  function maybeHasData (line 57) | func maybeHasData(conn net.Conn) bool {

FILE: internal/pool/conn_check_dummy.go
  function connCheck (line 13) | func connCheck(_ net.Conn) error {
  function maybeHasData (line 18) | func maybeHasData(_ net.Conn) bool {

FILE: internal/pool/conn_relaxed_timeout_test.go
  function TestConcurrentRelaxedTimeoutClearing (line 11) | func TestConcurrentRelaxedTimeoutClearing(t *testing.T) {
  function TestRelaxedTimeoutCounterRaceCondition (line 51) | func TestRelaxedTimeoutCounterRaceCondition(t *testing.T) {

FILE: internal/pool/conn_state.go
  type ConnState (line 22) | type ConnState
    method String (line 73) | func (s ConnState) String() string {
  constant StateCreated (line 26) | StateCreated ConnState = iota
  constant StateInitializing (line 29) | StateInitializing
  constant StateIdle (line 32) | StateIdle
  constant StateInUse (line 35) | StateInUse
  constant StateUnusable (line 39) | StateUnusable
  constant StateClosed (line 42) | StateClosed
  function ValidFromIdle (line 62) | func ValidFromIdle() []ConnState {
  function ValidFromCreatedIdleOrUnusable (line 68) | func ValidFromCreatedIdleOrUnusable() []ConnState {
  type waiter (line 105) | type waiter struct
  type ConnStateMachine (line 118) | type ConnStateMachine struct
    method GetState (line 142) | func (sm *ConnStateMachine) GetState() ConnState {
    method TryTransitionFast (line 159) | func (sm *ConnStateMachine) TryTransitionFast(fromState, targetState C...
    method TryTransition (line 171) | func (sm *ConnStateMachine) TryTransition(validFromStates []ConnState,...
    method Transition (line 199) | func (sm *ConnStateMachine) Transition(targetState ConnState) {
    method AwaitAndTransition (line 216) | func (sm *ConnStateMachine) AwaitAndTransition(
    method notifyWaiters (line 285) | func (sm *ConnStateMachine) notifyWaiters() {
  function NewConnStateMachine (line 130) | func NewConnStateMachine() *ConnStateMachine {

FILE: internal/pool/conn_state_alloc_test.go
  function TestPredefinedSlicesAvoidAllocations (line 10) | func TestPredefinedSlicesAvoidAllocations(t *testing.T) {
  function TestInlineSliceAllocations (line 27) | func TestInlineSliceAllocations(t *testing.T) {
  function BenchmarkAwaitAndTransition_PredefinedSlice (line 46) | func BenchmarkAwaitAndTransition_PredefinedSlice(b *testing.B) {
  function BenchmarkAwaitAndTransition_InlineSlice (line 61) | func BenchmarkAwaitAndTransition_InlineSlice(b *testing.B) {
  function BenchmarkAwaitAndTransition_MultipleStates_Predefined (line 76) | func BenchmarkAwaitAndTransition_MultipleStates_Predefined(b *testing.B) {
  function BenchmarkAwaitAndTransition_MultipleStates_Inline (line 91) | func BenchmarkAwaitAndTransition_MultipleStates_Inline(b *testing.B) {
  function TestPreallocatedErrorsAvoidAllocations (line 107) | func TestPreallocatedErrorsAvoidAllocations(t *testing.T) {
  function BenchmarkHandoffErrors_Preallocated (line 127) | func BenchmarkHandoffErrors_Preallocated(b *testing.B) {
  function BenchmarkCompareAndSwapUsable_Preallocated (line 140) | func BenchmarkCompareAndSwapUsable_Preallocated(b *testing.B) {
  function TestAllTryTransitionUsePredefinedSlices (line 154) | func TestAllTryTransitionUsePredefinedSlices(t *testing.T) {

FILE: internal/pool/conn_state_test.go
  function TestConnStateMachine_GetState (line 11) | func TestConnStateMachine_GetState(t *testing.T) {
  function TestConnStateMachine_Transition (line 19) | func TestConnStateMachine_Transition(t *testing.T) {
  function TestConnStateMachine_TryTransition (line 34) | func TestConnStateMachine_TryTransition(t *testing.T) {
  function TestConnStateMachine_AwaitAndTransition_FastPath (line 95) | func TestConnStateMachine_AwaitAndTransition_FastPath(t *testing.T) {
  function TestConnStateMachine_AwaitAndTransition_Timeout (line 112) | func TestConnStateMachine_AwaitAndTransition_Timeout(t *testing.T) {
  function TestConnStateMachine_AwaitAndTransition_FIFO (line 129) | func TestConnStateMachine_AwaitAndTransition_FIFO(t *testing.T) {
  function TestConnStateMachine_ConcurrentAccess (line 192) | func TestConnStateMachine_ConcurrentAccess(t *testing.T) {
  function TestConnStateMachine_StateString (line 232) | func TestConnStateMachine_StateString(t *testing.T) {
  function BenchmarkConnStateMachine_GetState (line 255) | func BenchmarkConnStateMachine_GetState(b *testing.B) {
  function TestConnStateMachine_PreventsConcurrentInitialization (line 265) | func TestConnStateMachine_PreventsConcurrentInitialization(t *testing.T) {
  function TestConnStateMachine_AwaitAndTransitionWaitsForInitialization (line 329) | func TestConnStateMachine_AwaitAndTransitionWaitsForInitialization(t *te...
  function TestConnStateMachine_FIFOOrdering (line 393) | func TestConnStateMachine_FIFOOrdering(t *testing.T) {
  function TestConnStateMachine_FIFOWithFastPath (line 464) | func TestConnStateMachine_FIFOWithFastPath(t *testing.T) {
  function BenchmarkConnStateMachine_TryTransition (line 531) | func BenchmarkConnStateMachine_TryTransition(b *testing.B) {
  function TestConnStateMachine_IdleInUseTransitions (line 542) | func TestConnStateMachine_IdleInUseTransitions(t *testing.T) {
  function TestConn_UsedMethods (line 595) | func TestConn_UsedMethods(t *testing.T) {
  function TestConnStateMachine_UnusableState (line 639) | func TestConnStateMachine_UnusableState(t *testing.T) {
  function TestConn_UsableUnusable (line 687) | func TestConn_UsableUnusable(t *testing.T) {

FILE: internal/pool/conn_used_at_test.go
  function TestConn_UsedAtUpdatedOnRead (line 13) | func TestConn_UsedAtUpdatedOnRead(t *testing.T) {
  function TestConn_UsedAtUpdatedOnWrite (line 56) | func TestConn_UsedAtUpdatedOnWrite(t *testing.T) {
  function TestConn_UsedAtUpdatedOnMultipleOperations (line 101) | func TestConn_UsedAtUpdatedOnMultipleOperations(t *testing.T) {
  function TestConn_UsedAtNotUpdatedWithoutOperation (line 149) | func TestConn_UsedAtNotUpdatedWithoutOperation(t *testing.T) {
  function TestConn_UsedAtConcurrentUpdates (line 175) | func TestConn_UsedAtConcurrentUpdates(t *testing.T) {
  function TestConn_UsedAtPrecision (line 225) | func TestConn_UsedAtPrecision(t *testing.T) {

FILE: internal/pool/dial_conn_retry_test.go
  function TestDialConn_HangingDial_RetriesWithPerAttemptTimeout (line 12) | func TestDialConn_HangingDial_RetriesWithPerAttemptTimeout(t *testing.T) {
  function TestDialConn_DoesNotExtendEarlierParentDeadline (line 78) | func TestDialConn_DoesNotExtendEarlierParentDeadline(t *testing.T) {
  function TestDialConn_ContextCancelStopsFurtherRetries (line 114) | func TestDialConn_ContextCancelStopsFurtherRetries(t *testing.T) {
  function TestDialConn_DialTimeoutDisabled_DoesNotSetDeadline (line 151) | func TestDialConn_DialTimeoutDisabled_DoesNotSetDeadline(t *testing.T) {
  function TestDialConn_NoBackoffAfterLastAttempt (line 178) | func TestDialConn_NoBackoffAfterLastAttempt(t *testing.T) {

FILE: internal/pool/dial_context_timeout_test.go
  function TestDialConn_AppliesDialTimeoutPerAttemptViaContext (line 13) | func TestDialConn_AppliesDialTimeoutPerAttemptViaContext(t *testing.T) {

FILE: internal/pool/dial_retry_backoff_test.go
  function TestDialRetryBackoff_ConstantByDefault_ExponentialWhenMaxSet (line 8) | func TestDialRetryBackoff_ConstantByDefault_ExponentialWhenMaxSet(t *tes...

FILE: internal/pool/double_freeturn_simple_test.go
  function TestDoubleFreeTurnSimple (line 27) | func TestDoubleFreeTurnSimple(t *testing.T) {

FILE: internal/pool/double_freeturn_test.go
  function TestDoubleFreeTurnBug (line 22) | func TestDoubleFreeTurnBug(t *testing.T) {
  function TestDoubleFreeTurnHighConcurrency (line 139) | func TestDoubleFreeTurnHighConcurrency(t *testing.T) {

FILE: internal/pool/export_test.go
  method SetCreatedAt (line 8) | func (cn *Conn) SetCreatedAt(tm time.Time) {
  method NetConn (line 12) | func (cn *Conn) NetConn() net.Conn {
  method CheckMinIdleConns (line 16) | func (p *ConnPool) CheckMinIdleConns() {
  method QueueLen (line 22) | func (p *ConnPool) QueueLen() int {
  method DialsQueueLen (line 26) | func (p *ConnPool) DialsQueueLen() int {
  method CalcConnExpiresAt (line 32) | func (p *ConnPool) CalcConnExpiresAt() time.Time {

FILE: internal/pool/hooks.go
  type PoolHook (line 9) | type PoolHook interface
  type PoolHookManager (line 36) | type PoolHookManager struct
    method AddHook (line 50) | func (phm *PoolHookManager) AddHook(hook PoolHook) {
    method RemoveHook (line 57) | func (phm *PoolHookManager) RemoveHook(hook PoolHook) {
    method ProcessOnGet (line 73) | func (phm *PoolHookManager) ProcessOnGet(ctx context.Context, conn *Co...
    method ProcessOnPut (line 95) | func (phm *PoolHookManager) ProcessOnPut(ctx context.Context, conn *Co...
    method ProcessOnRemove (line 125) | func (phm *PoolHookManager) ProcessOnRemove(ctx context.Context, conn ...
    method GetHookCount (line 138) | func (phm *PoolHookManager) GetHookCount() int {
    method GetHooks (line 145) | func (phm *PoolHookManager) GetHooks() []PoolHook {
    method Clone (line 156) | func (phm *PoolHookManager) Clone() *PoolHookManager {
  function NewPoolHookManager (line 42) | func NewPoolHookManager() *PoolHookManager {

FILE: internal/pool/hooks_test.go
  type TestHook (line 12) | type TestHook struct
    method OnGet (line 23) | func (th *TestHook) OnGet(ctx context.Context, conn *Conn, isNewConn b...
    method OnPut (line 28) | func (th *TestHook) OnPut(ctx context.Context, conn *Conn) (shouldPool...
    method OnRemove (line 33) | func (th *TestHook) OnRemove(ctx context.Context, conn *Conn, reason e...
  function TestPoolHookManager (line 37) | func TestPoolHookManager(t *testing.T) {
  function TestHookErrorHandling (line 106) | func TestHookErrorHandling(t *testing.T) {
  function TestHookShouldRemove (line 143) | func TestHookShouldRemove(t *testing.T) {
  function TestPoolWithHooks (line 184) | func TestPoolWithHooks(t *testing.T) {

FILE: internal/pool/main_test.go
  function TestGinkgoSuite (line 16) | func TestGinkgoSuite(t *testing.T) {
  function perform (line 21) | func perform(n int, cbs ...func(int)) {
  function dummyDialer (line 37) | func dummyDialer(context.Context) (net.Conn, error) {
  function newDummyConn (line 41) | func newDummyConn() net.Conn {
  type dummyConn (line 52) | type dummyConn struct
    method SyscallConn (line 56) | func (d *dummyConn) SyscallConn() (syscall.RawConn, error) {
    method Read (line 62) | func (d *dummyConn) Read(b []byte) (n int, err error) {
    method Write (line 66) | func (d *dummyConn) Write(b []byte) (n int, err error) {
    method Close (line 70) | func (d *dummyConn) Close() error {
    method LocalAddr (line 75) | func (d *dummyConn) LocalAddr() net.Addr {
    method RemoteAddr (line 79) | func (d *dummyConn) RemoteAddr() net.Addr {
    method SetDeadline (line 83) | func (d *dummyConn) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 87) | func (d *dummyConn) SetReadDeadline(t time.Time) error {
    method SetWriteDeadline (line 91) | func (d *dummyConn) SetWriteDeadline(t time.Time) error {
  type dummyRawConn (line 97) | type dummyRawConn struct
    method Control (line 102) | func (d *dummyRawConn) Control(f func(fd uintptr)) error {
    method Read (line 106) | func (d *dummyRawConn) Read(f func(fd uintptr) (done bool)) error {
    method Write (line 115) | func (d *dummyRawConn) Write(f func(fd uintptr) (done bool)) error {
    method Close (line 119) | func (d *dummyRawConn) Close() {

FILE: internal/pool/pool.go
  constant CloseReasonStale (line 21) | CloseReasonStale = "stale"
  constant CloseReasonHookError (line 25) | CloseReasonHookError = "hook_error"
  constant CloseReasonAuthError (line 29) | CloseReasonAuthError = "auth_error"
  constant CloseReasonTest (line 32) | CloseReasonTest = "test"
  constant MetricStateIdle (line 41) | MetricStateIdle = "idle"
  constant MetricStateUsed (line 45) | MetricStateUsed = "used"
  type MetricCallbacks (line 127) | type MetricCallbacks struct
  function SetAllMetricCallbacks (line 161) | func SetAllMetricCallbacks(callbacks *MetricCallbacks) {
  function getMetricConnectionStateChangeCallback (line 186) | func getMetricConnectionStateChangeCallback() func(ctx context.Context, ...
  function GetMetricConnectionCreateTimeCallback (line 194) | func GetMetricConnectionCreateTimeCallback() func(ctx context.Context, d...
  function GetMetricConnectionRelaxedTimeoutCallback (line 203) | func GetMetricConnectionRelaxedTimeoutCallback() func(ctx context.Contex...
  function GetMetricConnectionHandoffCallback (line 212) | func GetMetricConnectionHandoffCallback() func(ctx context.Context, cn *...
  function GetMetricErrorCallback (line 221) | func GetMetricErrorCallback() func(ctx context.Context, errorType string...
  function GetMetricMaintenanceNotificationCallback (line 230) | func GetMetricMaintenanceNotificationCallback() func(ctx context.Context...
  function getMetricConnectionWaitTimeCallback (line 237) | func getMetricConnectionWaitTimeCallback() func(ctx context.Context, dur...
  function getMetricConnectionTimeoutCallback (line 244) | func getMetricConnectionTimeoutCallback() func(ctx context.Context, cn *...
  function getMetricConnectionClosedCallback (line 251) | func getMetricConnectionClosedCallback() func(ctx context.Context, cn *C...
  type Stats (line 259) | type Stats struct
  type Pooler (line 275) | type Pooler interface
  type Options (line 303) | type Options struct
  type lastDialErrorWrap (line 338) | type lastDialErrorWrap struct
  type ConnPool (line 342) | type ConnPool struct
    method initializeHooks (line 399) | func (p *ConnPool) initializeHooks() {
    method AddPoolHook (line 405) | func (p *ConnPool) AddPoolHook(hook PoolHook) {
    method RemovePoolHook (line 422) | func (p *ConnPool) RemovePoolHook(hook PoolHook) {
    method checkMinIdleConns (line 434) | func (p *ConnPool) checkMinIdleConns() {
    method addIdleConn (line 494) | func (p *ConnPool) addIdleConn() error {
    method NewConn (line 523) | func (p *ConnPool) NewConn(ctx context.Context) (*Conn, error) {
    method newConn (line 527) | func (p *ConnPool) newConn(ctx context.Context, pooled bool) (*Conn, e...
    method dialConn (line 588) | func (p *ConnPool) dialConn(ctx context.Context, pooled bool) (*Conn, ...
    method dialRetryBackoff (line 672) | func (p *ConnPool) dialRetryBackoff(attempt int) time.Duration {
    method calcConnExpiresAt (line 692) | func (p *ConnPool) calcConnExpiresAt() time.Time {
    method tryDial (line 707) | func (p *ConnPool) tryDial() {
    method setLastDialError (line 737) | func (p *ConnPool) setLastDialError(err error) {
    method getLastDialError (line 741) | func (p *ConnPool) getLastDialError() error {
    method Get (line 750) | func (p *ConnPool) Get(ctx context.Context) (*Conn, error) {
    method getConn (line 755) | func (p *ConnPool) getConn(ctx context.Context) (cn *Conn, err error) {
    method queuedNewConn (line 901) | func (p *ConnPool) queuedNewConn(ctx context.Context) (*Conn, error) {
    method putIdleConn (line 980) | func (p *ConnPool) putIdleConn(ctx context.Context, cn *Conn) bool {
    method waitTurn (line 1006) | func (p *ConnPool) waitTurn(ctx context.Context) error {
    method freeTurn (line 1035) | func (p *ConnPool) freeTurn() {
    method popIdle (line 1039) | func (p *ConnPool) popIdle() (*Conn, error) {
    method Put (line 1101) | func (p *ConnPool) Put(ctx context.Context, cn *Conn) {
    method putConnWithoutTurn (line 1108) | func (p *ConnPool) putConnWithoutTurn(ctx context.Context, cn *Conn) {
    method putConn (line 1113) | func (p *ConnPool) putConn(ctx context.Context, cn *Conn, freeTurn boo...
    method Remove (line 1240) | func (p *ConnPool) Remove(ctx context.Context, cn *Conn, reason error) {
    method RemoveWithoutTurn (line 1248) | func (p *ConnPool) RemoveWithoutTurn(ctx context.Context, cn *Conn, re...
    method removeConnInternal (line 1253) | func (p *ConnPool) removeConnInternal(ctx context.Context, cn *Conn, r...
    method CloseConn (line 1293) | func (p *ConnPool) CloseConn(ctx context.Context, cn *Conn, reason str...
    method removeConnWithLock (line 1309) | func (p *ConnPool) removeConnWithLock(cn *Conn) {
    method removeConn (line 1315) | func (p *ConnPool) removeConn(cn *Conn) {
    method closeConn (line 1334) | func (p *ConnPool) closeConn(cn *Conn) error {
    method Len (line 1339) | func (p *ConnPool) Len() int {
    method IdleLen (line 1347) | func (p *ConnPool) IdleLen() int {
    method Size (line 1358) | func (p *ConnPool) Size() int {
    method Stats (line 1362) | func (p *ConnPool) Stats() *Stats {
    method closed (line 1378) | func (p *ConnPool) closed() bool {
    method Filter (line 1382) | func (p *ConnPool) Filter(fn func(*Conn) bool) error {
    method Close (line 1397) | func (p *ConnPool) Close() error {
    method isHealthyConn (line 1418) | func (p *ConnPool) isHealthyConn(cn *Conn, nowNs int64) bool {
  function NewConnPool (line 376) | func NewConnPool(opt *Options) *ConnPool {

FILE: internal/pool/pool_single.go
  type SingleConnPool (line 11) | type SingleConnPool struct
    method NewConn (line 32) | func (p *SingleConnPool) NewConn(ctx context.Context) (*Conn, error) {
    method CloseConn (line 36) | func (p *SingleConnPool) CloseConn(ctx context.Context, cn *Conn, reas...
    method Get (line 40) | func (p *SingleConnPool) Get(_ context.Context) (*Conn, error) {
    method Put (line 59) | func (p *SingleConnPool) Put(_ context.Context, cn *Conn) {
    method Remove (line 69) | func (p *SingleConnPool) Remove(_ context.Context, cn *Conn, reason er...
    method RemoveWithoutTurn (line 77) | func (p *SingleConnPool) RemoveWithoutTurn(ctx context.Context, cn *Co...
    method Close (line 81) | func (p *SingleConnPool) Close() error {
    method Len (line 87) | func (p *SingleConnPool) Len() int {
    method IdleLen (line 91) | func (p *SingleConnPool) IdleLen() int {
    method Size (line 96) | func (p *SingleConnPool) Size() int { return 1 }
    method Stats (line 98) | func (p *SingleConnPool) Stats() *Stats {
    method AddPoolHook (line 102) | func (p *SingleConnPool) AddPoolHook(_ PoolHook) {}
    method RemovePoolHook (line 104) | func (p *SingleConnPool) RemovePoolHook(_ PoolHook) {}
  function NewSingleConnPool (line 25) | func NewSingleConnPool(pool Pooler, cn *Conn) *SingleConnPool {

FILE: internal/pool/pool_sticky.go
  constant stateDefault (line 11) | stateDefault = 0
  constant stateInited (line 12) | stateInited  = 1
  constant stateClosed (line 13) | stateClosed  = 2
  type BadConnError (line 16) | type BadConnError struct
    method Error (line 22) | func (e BadConnError) Error() string {
    method Unwrap (line 30) | func (e BadConnError) Unwrap() error {
  type StickyConnPool (line 36) | type StickyConnPool struct
    method
Condensed preview — 402 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,463K chars).
[
  {
    "path": ".github/CODEOWNERS",
    "chars": 29,
    "preview": "doctests/* @dmaier-redislabs\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 40,
    "preview": "custom: ['https://uptrace.dev/sponsor']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 1231,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n---\n\nIssue tracker is "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 168,
    "preview": "blank_issues_enabled: true\ncontact_links:\n  - name: Discussions\n    url: https://github.com/go-redis/redis/discussions\n "
  },
  {
    "path": ".github/RELEASE_NOTES_TEMPLATE.md",
    "chars": 4080,
    "preview": "# Release Notes Template for go-redis\n\nThis template provides a structured format for creating release notes for go-redi"
  },
  {
    "path": ".github/actions/run-tests/action.yml",
    "chars": 1693,
    "preview": "name: 'Run go-redis tests'\ndescription: 'Runs go-redis tests against different Redis versions and configurations'\ninputs"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 179,
    "preview": "version: 2\nupdates:\n- package-ecosystem: gomod\n  directory: /\n  schedule:\n    interval: weekly\n- package-ecosystem: gith"
  },
  {
    "path": ".github/release-drafter-config.yml",
    "chars": 960,
    "preview": "name-template: '$NEXT_MINOR_VERSION'\ntag-template: 'v$NEXT_MINOR_VERSION'\nautolabeler:\n  - label: 'maintenance'\n    file"
  },
  {
    "path": ".github/spellcheck-settings.yml",
    "chars": 529,
    "preview": "matrix:\n- name: Markdown\n  expect_match: false\n  apsell:\n    lang: en\n    d: en_US\n    ignore-case: true\n  dictionary:\n "
  },
  {
    "path": ".github/wordlist.txt",
    "chars": 677,
    "preview": "ACLs\nAPIs\nautoload\nautoloader\nautoloading\nanalytics\nAutoloading\nbackend\nbackends\nbehaviour\nCAS\nClickHouse\nconfig\ncustomi"
  },
  {
    "path": ".github/workflows/build.yml",
    "chars": 2895,
    "preview": "name: Go\n\non:\n  push:\n    branches: [master, v9, 'v9.*']\n  pull_request:\n    branches: [master, v9, v9.7, v9.8, 'ndyakov"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "chars": 2249,
    "preview": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# Y"
  },
  {
    "path": ".github/workflows/doctests.yaml",
    "chars": 841,
    "preview": "name: Documentation Tests\n\non:\n  push:\n    branches: [master, examples]\n  pull_request:\n    branches: [master, examples]"
  },
  {
    "path": ".github/workflows/golangci-lint.yml",
    "chars": 473,
    "preview": "name: golangci-lint\n\non:\n  push:\n    tags:\n      - v*\n    branches:\n      - master\n      - main\n      - v9\n      - v9.8\n"
  },
  {
    "path": ".github/workflows/release-drafter.yml",
    "chars": 767,
    "preview": "name: Release Drafter\n\non:\n  push:\n    # branches to consider in the event; optional, defaults to all\n    branches:\n    "
  },
  {
    "path": ".github/workflows/spellcheck.yml",
    "chars": 341,
    "preview": "name: spellcheck\non:\n  pull_request:\njobs:\n  check-spelling:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkou"
  },
  {
    "path": ".github/workflows/stale-issues.yml",
    "chars": 3713,
    "preview": "name: \"Stale Issue Management\"\non:\n  schedule:\n    # Run daily at midnight UTC\n    - cron: \"0 0 * * *\"\n  workflow_dispat"
  },
  {
    "path": ".github/workflows/test-e2e.yml",
    "chars": 1778,
    "preview": "name: E2E Tests\n\non:\n  push:\n    branches: [master, v9, 'v9.*']\n  pull_request:\n    branches: [master, v9, v9.7, v9.8, '"
  },
  {
    "path": ".github/workflows/test-redis-enterprise.yml",
    "chars": 1492,
    "preview": "name: RE Tests\n\non:\n  push:\n    branches: [master, v9, v9.7, v9.8]\n  pull_request:\n\npermissions:\n  contents: read\n\njobs:"
  },
  {
    "path": ".gitignore",
    "chars": 356,
    "preview": "*.rdb\ntestdata/*\n.idea/\n.DS_Store\n*.tar.gz\n*.dic\nredis8tests.sh\ncoverage.txt\n**/coverage.txt\n.vscode\ntmp/*\n*.test\nextra/"
  },
  {
    "path": ".golangci.yml",
    "chars": 717,
    "preview": "version: \"2\"\nrun:\n  timeout: 5m\n  tests: false\nlinters:\n  settings:\n    staticcheck:\n      checks:\n        - all\n       "
  },
  {
    "path": ".prettierrc.yml",
    "chars": 64,
    "preview": "semi: false\nsingleQuote: true\nproseWrap: always\nprintWidth: 100\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 4457,
    "preview": "# Contributing\n\n## Introduction\n\nWe appreciate your interest in considering contributing to go-redis.\nCommunity contribu"
  },
  {
    "path": "LICENSE",
    "chars": 1318,
    "preview": "Copyright (c) 2013 The github.com/redis/go-redis Authors.\nAll rights reserved.\n\nRedistribution and use in source and bin"
  },
  {
    "path": "Makefile",
    "chars": 4087,
    "preview": "GO_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \\; | sort)\nREDIS_VERSION ?= 8.6\nRE_CLUSTER ?= fals"
  },
  {
    "path": "README.md",
    "chars": 21884,
    "preview": "# Redis client for Go\n\n[![build workflow](https://github.com/redis/go-redis/actions/workflows/build.yml/badge.svg)](http"
  },
  {
    "path": "RELEASE-NOTES.md",
    "chars": 54564,
    "preview": "# Release Notes\n\n# 9.18.0 (2026-02-16)\n\n## 🚀 Highlights\n\n### Redis 8.6 Support\n\nAdded support for Redis 8.6, including n"
  },
  {
    "path": "RELEASING.md",
    "chars": 333,
    "preview": "# Releasing\n\n1. Run `release.sh` script which updates versions in go.mod files and pushes a new branch to GitHub:\n\n```sh"
  },
  {
    "path": "acl_commands.go",
    "chars": 3073,
    "preview": "package redis\n\nimport \"context\"\n\ntype ACLCmdable interface {\n\tACLDryRun(ctx context.Context, username string, command .."
  },
  {
    "path": "acl_commands_test.go",
    "chars": 13895,
    "preview": "package redis_test\n\nimport (\n\t\"context\"\n\n\t\"github.com/redis/go-redis/v9\"\n\n\t. \"github.com/bsm/ginkgo/v2\"\n\t. \"github.com/b"
  },
  {
    "path": "adapters.go",
    "chars": 3900,
    "preview": "package redis\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9/internal/interfaces\"\n\t\"githu"
  },
  {
    "path": "async_handoff_integration_test.go",
    "chars": 12721,
    "preview": "package redis\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9/inte"
  },
  {
    "path": "auth/auth.go",
    "chars": 2551,
    "preview": "// Package auth package provides authentication-related interfaces and types.\n// It also includes a basic implementation"
  },
  {
    "path": "auth/auth_test.go",
    "chars": 8745,
    "preview": "package auth\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n)\n\ntype mockStreamingProvider struct {\n\tcredentia"
  },
  {
    "path": "auth/reauth_credentials_listener.go",
    "chars": 1532,
    "preview": "package auth\n\n// ReAuthCredentialsListener is a struct that implements the CredentialsListener interface.\n// It is used "
  },
  {
    "path": "bench_test.go",
    "chars": 8809,
    "preview": "package redis_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/r"
  },
  {
    "path": "bitmap_commands.go",
    "chars": 7105,
    "preview": "package redis\n\nimport (\n\t\"context\"\n\t\"errors\"\n)\n\ntype BitMapCmdable interface {\n\tGetBit(ctx context.Context, key string, "
  },
  {
    "path": "bitmap_commands_test.go",
    "chars": 2256,
    "preview": "package redis_test\n\nimport (\n\t. \"github.com/bsm/ginkgo/v2\"\n\t. \"github.com/bsm/gomega\"\n\t\"github.com/redis/go-redis/v9\"\n)\n"
  },
  {
    "path": "cluster_commands.go",
    "chars": 6092,
    "preview": "package redis\n\nimport \"context\"\n\ntype ClusterCmdable interface {\n\tClusterMyShardID(ctx context.Context) *StringCmd\n\tClus"
  },
  {
    "path": "command.go",
    "chars": 175722,
    "preview": "package redis\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"maps\"\n\t\"net\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"git"
  },
  {
    "path": "command_digest_test.go",
    "chars": 2411,
    "preview": "package redis\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/redis/go-redis/v9/internal/proto\"\n)\n\nfunc TestDigestC"
  },
  {
    "path": "command_policy_resolver.go",
    "chars": 4657,
    "preview": "package redis\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\t\"github.com/redis/go-redis/v9/internal/routing\"\n)\n\ntype (\n\tmodule      ="
  },
  {
    "path": "command_recorder_test.go",
    "chars": 2036,
    "preview": "package redis_test\n\nimport (\n\t\"context\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\n// commandRecorder record"
  },
  {
    "path": "command_test.go",
    "chars": 2320,
    "preview": "package redis_test\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9\"\n\n\t. \"github.com/bsm/ginkgo/v2\"\n\t. \"githu"
  },
  {
    "path": "commands.go",
    "chars": 22420,
    "preview": "package redis\n\nimport (\n\t\"context\"\n\t\"encoding\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\t"
  },
  {
    "path": "commands_test.go",
    "chars": 294314,
    "preview": "package redis_test\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"crypto/sha1\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"ti"
  },
  {
    "path": "dial_retry_backoff.go",
    "chars": 1063,
    "preview": "package redis\n\nimport (\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9/internal\"\n)\n\n// DialRetryBackoffConstant returns a dial "
  },
  {
    "path": "digest_test.go",
    "chars": 13612,
    "preview": "package redis_test\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/redis/go-redis/v9\"\n\t\"github"
  },
  {
    "path": "doc.go",
    "chars": 61,
    "preview": "/*\nPackage redis implements a Redis client.\n*/\npackage redis\n"
  },
  {
    "path": "docker-compose.yml",
    "chars": 4677,
    "preview": "---\n\nx-default-image: &default-image ${CLIENT_LIBS_TEST_IMAGE:-redislabs/client-libs-test:8.6.0}\n\nservices:\n  redis:\n   "
  },
  {
    "path": "dockers/.gitignore",
    "chars": 59,
    "preview": "osscluster/\nring/\nstandalone/\nsentinel-cluster/\nsentinel/\n\n"
  },
  {
    "path": "dockers/sentinel.conf",
    "chars": 216,
    "preview": "sentinel resolve-hostnames yes\nsentinel monitor go-redis-test 127.0.0.1 9121 2\nsentinel down-after-milliseconds go-redis"
  },
  {
    "path": "doctests/Makefile",
    "chars": 510,
    "preview": "test:\n\t@if [ -z \"$(REDIS_VERSION)\" ]; then \\\n\t\techo \"REDIS_VERSION not set, running all tests\"; \\\n\t\tgo test -v ./...; \\\n"
  },
  {
    "path": "doctests/README.md",
    "chars": 894,
    "preview": "# Command examples for redis.io\n\nThese examples appear on the [Redis documentation](https://redis.io) site as part of th"
  },
  {
    "path": "doctests/bf_tutorial_test.go",
    "chars": 1451,
    "preview": "// EXAMPLE: bf_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-r"
  },
  {
    "path": "doctests/bitfield_tutorial_test.go",
    "chars": 1293,
    "preview": "// EXAMPLE: bitfield_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redi"
  },
  {
    "path": "doctests/bitmap_tutorial_test.go",
    "chars": 1595,
    "preview": "// EXAMPLE: bitmap_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/"
  },
  {
    "path": "doctests/cmds_generic_test.go",
    "chars": 3371,
    "preview": "// EXAMPLE: cmds_generic\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math\"\n\t\"time\"\n\n\t\"gith"
  },
  {
    "path": "doctests/cmds_hash_test.go",
    "chars": 4183,
    "preview": "// EXAMPLE: cmds_hash\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sort\"\n\n\t\"github.com/redi"
  },
  {
    "path": "doctests/cmds_list_test.go",
    "chars": 5421,
    "preview": "// EXAMPLE: cmds_list\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-red"
  },
  {
    "path": "doctests/cmds_servermgmt_test.go",
    "chars": 1370,
    "preview": "// EXAMPLE: cmds_servermgmt\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/"
  },
  {
    "path": "doctests/cmds_set_test.go",
    "chars": 1662,
    "preview": "// EXAMPLE: cmds_set\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-redi"
  },
  {
    "path": "doctests/cmds_sorted_set_test.go",
    "chars": 4070,
    "preview": "// EXAMPLE: cmds_sorted_set\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/"
  },
  {
    "path": "doctests/cmds_string_test.go",
    "chars": 925,
    "preview": "// EXAMPLE: cmds_string\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-r"
  },
  {
    "path": "doctests/cms_tutorial_test.go",
    "chars": 1475,
    "preview": "// EXAMPLE: cms_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-"
  },
  {
    "path": "doctests/cuckoo_tutorial_test.go",
    "chars": 1300,
    "preview": "// EXAMPLE: cuckoo_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/"
  },
  {
    "path": "doctests/geo_index_test.go",
    "chars": 4331,
    "preview": "// EXAMPLE: geoindex\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-redi"
  },
  {
    "path": "doctests/geo_tutorial_test.go",
    "chars": 2509,
    "preview": "// EXAMPLE: geo_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-"
  },
  {
    "path": "doctests/hash_tutorial_test.go",
    "chars": 5140,
    "preview": "// EXAMPLE: hash_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go"
  },
  {
    "path": "doctests/hll_tutorial_test.go",
    "chars": 1241,
    "preview": "// EXAMPLE: hll_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-"
  },
  {
    "path": "doctests/home_json_example_test.go",
    "chars": 6301,
    "preview": "// EXAMPLE: go_home_json\n// HIDE_START\npackage example_commands_test\n\n// HIDE_END\n// STEP_START import\nimport (\n\t\"contex"
  },
  {
    "path": "doctests/home_prob_dts_test.go",
    "chars": 7024,
    "preview": "// EXAMPLE: home_prob_dts\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go"
  },
  {
    "path": "doctests/json_tutorial_test.go",
    "chars": 26925,
    "preview": "// EXAMPLE: json_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go"
  },
  {
    "path": "doctests/list_tutorial_test.go",
    "chars": 13665,
    "preview": "// EXAMPLE: list_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go"
  },
  {
    "path": "doctests/lpush_lrange_test.go",
    "chars": 892,
    "preview": "// EXAMPLE: lpush_and_lrange\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.c"
  },
  {
    "path": "doctests/main_test.go",
    "chars": 293,
    "preview": "package example_commands_test\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nvar RedisVersion float64\n\nfunc init() {\n\t/"
  },
  {
    "path": "doctests/pipe_trans_example_test.go",
    "chars": 3792,
    "preview": "// EXAMPLE: pipe_trans_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/re"
  },
  {
    "path": "doctests/query_agg_test.go",
    "chars": 14053,
    "preview": "// EXAMPLE: query_agg\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sort\"\n\n\t\"github.com/redi"
  },
  {
    "path": "doctests/query_em_test.go",
    "chars": 11543,
    "preview": "// EXAMPLE: query_em\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"git"
  },
  {
    "path": "doctests/query_ft_test.go",
    "chars": 10961,
    "preview": "// EXAMPLE: query_ft\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sort\"\n\n\t\"github.com/redis"
  },
  {
    "path": "doctests/query_geo_test.go",
    "chars": 11223,
    "preview": "// EXAMPLE: query_geo\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sort\"\n\n\t\"github.com/redi"
  },
  {
    "path": "doctests/query_range_test.go",
    "chars": 12482,
    "preview": "// EXAMPLE: query_range\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-r"
  },
  {
    "path": "doctests/search_quickstart_test.go",
    "chars": 9091,
    "preview": "// EXAMPLE: search_quickstart\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redi"
  },
  {
    "path": "doctests/set_get_test.go",
    "chars": 879,
    "preview": "// EXAMPLE: set_and_get\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-r"
  },
  {
    "path": "doctests/sets_example_test.go",
    "chars": 9174,
    "preview": "// EXAMPLE: sets_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sort\"\n\n\t\"github.com/"
  },
  {
    "path": "doctests/ss_tutorial_test.go",
    "chars": 8841,
    "preview": "// EXAMPLE: ss_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-r"
  },
  {
    "path": "doctests/stream_tutorial_test.go",
    "chars": 22113,
    "preview": "// EXAMPLE: stream_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/"
  },
  {
    "path": "doctests/string_example_test.go",
    "chars": 3005,
    "preview": "// EXAMPLE: set_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-"
  },
  {
    "path": "doctests/tdigest_tutorial_test.go",
    "chars": 4386,
    "preview": "// EXAMPLE: tdigest_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis"
  },
  {
    "path": "doctests/timeseries_tut_test.go",
    "chars": 23310,
    "preview": "// EXAMPLE: time_series_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math\"\n\t\"sort\""
  },
  {
    "path": "doctests/topk_tutorial_test.go",
    "chars": 1268,
    "preview": "// EXAMPLE: topk_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go"
  },
  {
    "path": "doctests/vec_set_test.go",
    "chars": 10174,
    "preview": "// EXAMPLE: vecset_tutorial\n// HIDE_START\npackage example_commands_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sort\"\n\n\t\"github.co"
  },
  {
    "path": "error.go",
    "chars": 11153,
    "preview": "package redis\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/redis/go-redis/v9/internal\"\n\t\"github."
  },
  {
    "path": "error_test.go",
    "chars": 1961,
    "preview": "package redis_test\n\nimport (\n\t\"context\"\n\t\"io\"\n\n\t. \"github.com/bsm/ginkgo/v2\"\n\t. \"github.com/bsm/gomega\"\n\t\"github.com/red"
  },
  {
    "path": "error_wrapping_test.go",
    "chars": 23243,
    "preview": "package redis_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/redis/go-redis/v9\"\n\t\""
  },
  {
    "path": "example/cluster-mget/README.md",
    "chars": 3369,
    "preview": "# Redis Cluster MGET Example\n\nThis example demonstrates how to use the Redis Cluster client with the `MGET` command to r"
  },
  {
    "path": "example/cluster-mget/go.mod",
    "chars": 339,
    "preview": "module github.com/redis/go-redis/example/cluster-mget\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nrequire g"
  },
  {
    "path": "example/cluster-mget/go.sum",
    "chars": 1919,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "example/cluster-mget/main.go",
    "chars": 2587,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\nfunc main() {\n\tctx := context.Background()\n"
  },
  {
    "path": "example/del-keys-without-ttl/README.md",
    "chars": 264,
    "preview": "# Delete keys without a ttl\n\nThis example demonstrates how to use `SCAN` and pipelines to efficiently delete keys withou"
  },
  {
    "path": "example/del-keys-without-ttl/go.mod",
    "chars": 418,
    "preview": "module github.com/redis/go-redis/example/del-keys-without-ttl\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nr"
  },
  {
    "path": "example/del-keys-without-ttl/go.sum",
    "chars": 2873,
    "preview": "github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=\ngithub.com/benbjohnson/clock v1.1.0/"
  },
  {
    "path": "example/del-keys-without-ttl/main.go",
    "chars": 2721,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"go.uber.org/zap\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\nfunc ma"
  },
  {
    "path": "example/digest-optimistic-locking/README.md",
    "chars": 5729,
    "preview": "# Redis Digest & Optimistic Locking Example\n\nThis example demonstrates how to use Redis DIGEST command and digest-based "
  },
  {
    "path": "example/digest-optimistic-locking/go.mod",
    "chars": 483,
    "preview": "module github.com/redis/go-redis/example/digest-optimistic-locking\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../"
  },
  {
    "path": "example/digest-optimistic-locking/go.sum",
    "chars": 2084,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "example/digest-optimistic-locking/main.go",
    "chars": 7328,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9\"\n\t\"github.com/redis/go-redis/v9/helper\""
  },
  {
    "path": "example/disable-maintnotifications/README.md",
    "chars": 3934,
    "preview": "# Disable Maintenance Notifications Example\n\nThis example demonstrates how to use the go-redis client with maintenance n"
  },
  {
    "path": "example/disable-maintnotifications/go.mod",
    "chars": 352,
    "preview": "module github.com/redis/go-redis/example/disable-maintnotifications\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => .."
  },
  {
    "path": "example/disable-maintnotifications/go.sum",
    "chars": 1919,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "example/disable-maintnotifications/main.go",
    "chars": 4938,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9\"\n\t\"github.com/redis/go-redis/v9/maintno"
  },
  {
    "path": "example/hll/README.md",
    "chars": 184,
    "preview": "# Redis HyperLogLog example\n\nTo run this example:\n\n```shell\ngo run .\n```\n\nSee [Using HyperLogLog command with go-redis]("
  },
  {
    "path": "example/hll/go.mod",
    "chars": 330,
    "preview": "module github.com/redis/go-redis/example/hll\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nrequire github.com"
  },
  {
    "path": "example/hll/go.sum",
    "chars": 1919,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "example/hll/main.go",
    "chars": 454,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\nfunc main() {\n\tctx := context.Background()\n"
  },
  {
    "path": "example/hset-struct/README.md",
    "chars": 96,
    "preview": "# Example for setting struct fields as hash fields\n\nTo run this example:\n\n```shell\ngo run .\n```\n"
  },
  {
    "path": "example/hset-struct/go.mod",
    "chars": 378,
    "preview": "module github.com/redis/go-redis/example/scan-struct\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nrequire (\n"
  },
  {
    "path": "example/hset-struct/go.sum",
    "chars": 1919,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "example/hset-struct/main.go",
    "chars": 3061,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/davecgh/go-spew/spew\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\ntype M"
  },
  {
    "path": "example/lua-scripting/README.md",
    "chars": 171,
    "preview": "# Redis Lua scripting example\n\nThis is an example for [Redis Lua scripting](https://redis.uptrace.dev/guide/lua-scriptin"
  },
  {
    "path": "example/lua-scripting/go.mod",
    "chars": 340,
    "preview": "module github.com/redis/go-redis/example/lua-scripting\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nrequire "
  },
  {
    "path": "example/lua-scripting/go.sum",
    "chars": 1919,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "example/lua-scripting/main.go",
    "chars": 1047,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\nfunc main() {\n\tctx := context.Background()\n"
  },
  {
    "path": "example/maintnotifiations-pubsub/go.mod",
    "chars": 333,
    "preview": "module github.com/redis/go-redis/example/pubsub\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nrequire github."
  },
  {
    "path": "example/maintnotifiations-pubsub/go.sum",
    "chars": 1919,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "example/maintnotifiations-pubsub/main.go",
    "chars": 4790,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9\"\n\t\"github"
  },
  {
    "path": "example/otel/README.md",
    "chars": 3113,
    "preview": "# go-redis OpenTelemetry Monitoring with Uptrace\n\nThis example demonstrates how to instrument and monitor Redis operatio"
  },
  {
    "path": "example/otel/client.go",
    "chars": 1862,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"sync\"\n\t\"time\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/"
  },
  {
    "path": "example/otel/config/otel-collector.yaml",
    "chars": 1461,
    "preview": "extensions:\n  health_check:\n  pprof:\n    endpoint: 0.0.0.0:1777\n  zpages:\n    endpoint: 0.0.0.0:55679\n\nreceivers:\n  otlp"
  },
  {
    "path": "example/otel/config/vector.toml",
    "chars": 863,
    "preview": "[sources.syslog_logs]\ntype = \"demo_logs\"\nformat = \"syslog\"\n\n[sources.apache_common_logs]\ntype = \"demo_logs\"\nformat = \"ap"
  },
  {
    "path": "example/otel/docker-compose.yml",
    "chars": 2021,
    "preview": "services:\n  clickhouse:\n    image: clickhouse/clickhouse-server:25.3.5\n    restart: on-failure\n    environment:\n      CL"
  },
  {
    "path": "example/otel/go.mod",
    "chars": 2069,
    "preview": "module github.com/redis/go-redis/example/otel\n\ngo 1.24\n\ntoolchain go1.24.1\n\nreplace github.com/redis/go-redis/v9 => ../."
  },
  {
    "path": "example/otel/go.sum",
    "chars": 7646,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "example/otel/uptrace.yml",
    "chars": 18136,
    "preview": "# =============================================================================\n# Uptrace Configuration\n# =============="
  },
  {
    "path": "example/otel-metrics/README.md",
    "chars": 1821,
    "preview": "# OpenTelemetry Metrics Example\n\nThis example demonstrates how to enable OpenTelemetry metrics for Redis operations usin"
  },
  {
    "path": "example/otel-metrics/go.mod",
    "chars": 1562,
    "preview": "module github.com/redis/go-redis/example/otel-metrics\n\ngo 1.24.0\n\ntoolchain go1.24.4\n\nreplace github.com/redis/go-redis/"
  },
  {
    "path": "example/otel-metrics/go.sum",
    "chars": 6196,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "example/otel-metrics/main.go",
    "chars": 3260,
    "preview": "// EXAMPLE: otel_metrics\n// HIDE_START\npackage main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"math/rand\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n"
  },
  {
    "path": "example/redis-bloom/README.md",
    "chars": 312,
    "preview": "# RedisBloom example for go-redis\n\nThis is an example for\n[Bloom, Cuckoo, Count-Min, Top-K](https://redis.uptrace.dev/gu"
  },
  {
    "path": "example/redis-bloom/go.mod",
    "chars": 338,
    "preview": "module github.com/redis/go-redis/example/redis-bloom\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nrequire gi"
  },
  {
    "path": "example/redis-bloom/go.sum",
    "chars": 1919,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "example/redis-bloom/main.go",
    "chars": 3260,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math/rand\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\nfunc main() {\n\tctx := context."
  },
  {
    "path": "example/scan-struct/README.md",
    "chars": 215,
    "preview": "# Example for scanning hash fields into a struct\n\nTo run this example:\n\n```shell\ngo run .\n```\n\nSee\n[Redis: Scanning hash"
  },
  {
    "path": "example/scan-struct/go.mod",
    "chars": 378,
    "preview": "module github.com/redis/go-redis/example/scan-struct\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nrequire (\n"
  },
  {
    "path": "example/scan-struct/go.sum",
    "chars": 1919,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "example/scan-struct/main.go",
    "chars": 1850,
    "preview": "package main\n\nimport (\n\t\"context\"\n\n\t\"github.com/davecgh/go-spew/spew\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\ntype Model str"
  },
  {
    "path": "example/tls-cert-auth/README.md",
    "chars": 2179,
    "preview": "# TLS Certificate Authentication Example\n\nThis example demonstrates how to use TLS client certificates for automatic aut"
  },
  {
    "path": "example/tls-cert-auth/go.mod",
    "chars": 340,
    "preview": "module github.com/redis/go-redis/example/tls-cert-auth\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nrequire "
  },
  {
    "path": "example/tls-cert-auth/go.sum",
    "chars": 1919,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "example/tls-cert-auth/main.go",
    "chars": 3271,
    "preview": "// TLS Certificate Authentication Example\n//\n// This example demonstrates how to use TLS client certificates for\n// auto"
  },
  {
    "path": "example/tls-connection/README.md",
    "chars": 2305,
    "preview": "# TLS Connection Examples\n\nShows different ways to connect to Redis over TLS.\n\n## Running\n\nStart Redis with TLS:\n\n```she"
  },
  {
    "path": "example/tls-connection/go.mod",
    "chars": 341,
    "preview": "module github.com/redis/go-redis/example/tls-connection\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nrequire"
  },
  {
    "path": "example/tls-connection/go.sum",
    "chars": 1919,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "example/tls-connection/main.go",
    "chars": 3567,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\nfunc mai"
  },
  {
    "path": "example_instrumentation_test.go",
    "chars": 3344,
    "preview": "package redis_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\ntype redisHook struct{}\n\nvar _"
  },
  {
    "path": "example_test.go",
    "chars": 14717,
    "preview": "package redis_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\nvar (\n\tctx "
  },
  {
    "path": "export_test.go",
    "chars": 2354,
    "preview": "package redis\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/redis/go-redis/v9/internal\"\n\t\"github.com/redis"
  },
  {
    "path": "extra/rediscensus/go.mod",
    "chars": 751,
    "preview": "module github.com/redis/go-redis/extra/rediscensus/v9\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nreplace g"
  },
  {
    "path": "extra/rediscensus/go.sum",
    "chars": 11156,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/BurntSushi/toml v0.3.1/go."
  },
  {
    "path": "extra/rediscensus/rediscensus.go",
    "chars": 1719,
    "preview": "package rediscensus\n\nimport (\n\t\"context\"\n\t\"net\"\n\n\t\"go.opencensus.io/trace\"\n\n\t\"github.com/redis/go-redis/extra/rediscmd/v"
  },
  {
    "path": "extra/rediscmd/go.mod",
    "chars": 590,
    "preview": "module github.com/redis/go-redis/extra/rediscmd/v9\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nrequire (\n\tg"
  },
  {
    "path": "extra/rediscmd/go.sum",
    "chars": 1919,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "extra/rediscmd/rediscmd.go",
    "chars": 2583,
    "preview": "package rediscmd\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\nfunc"
  },
  {
    "path": "extra/rediscmd/rediscmd_test.go",
    "chars": 675,
    "preview": "package rediscmd\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/bsm/ginkgo/v2\"\n\t. \"github.com/bsm/gomega\"\n)\n\nfunc TestGinkgo(t *te"
  },
  {
    "path": "extra/rediscmd/safe.go",
    "chars": 162,
    "preview": "//go:build appengine\n// +build appengine\n\npackage rediscmd\n\nfunc String(b []byte) string {\n\treturn string(b)\n}\n\nfunc Byt"
  },
  {
    "path": "extra/rediscmd/unsafe.go",
    "chars": 353,
    "preview": "//go:build !appengine\n// +build !appengine\n\npackage rediscmd\n\nimport \"unsafe\"\n\n// String converts byte slice to string.\n"
  },
  {
    "path": "extra/redisotel/README.md",
    "chars": 693,
    "preview": "# OpenTelemetry instrumentation for go-redis\n\n## Installation\n\n```bash\ngo get github.com/redis/go-redis/extra/redisotel/"
  },
  {
    "path": "extra/redisotel/config.go",
    "chars": 5006,
    "preview": "package redisotel\n\nimport (\n\t\"strings\"\n\n\t\"github.com/redis/go-redis/v9\"\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.i"
  },
  {
    "path": "extra/redisotel/go.mod",
    "chars": 925,
    "preview": "module github.com/redis/go-redis/extra/redisotel/v9\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nreplace git"
  },
  {
    "path": "extra/redisotel/go.sum",
    "chars": 3363,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "extra/redisotel/metrics.go",
    "chars": 9406,
    "preview": "package redisotel\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentel"
  },
  {
    "path": "extra/redisotel/metrics_test.go",
    "chars": 1820,
    "preview": "package redisotel\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"go.opentelemetry.io/otel/attribute\"\n)\n\nfunc Test_poolStatsAttrs(t *"
  },
  {
    "path": "extra/redisotel/tracing.go",
    "chars": 5897,
    "preview": "package redisotel\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"go.opentelemetry.io/otel/attrib"
  },
  {
    "path": "extra/redisotel/tracing_test.go",
    "chars": 20510,
    "preview": "package redisotel\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.o"
  },
  {
    "path": "extra/redisotel-native/attributes.go",
    "chars": 2277,
    "preview": "package redisotel\n\n// OpenTelemetry semantic convention attribute keys for Redis client metrics.\n// These constants foll"
  },
  {
    "path": "extra/redisotel-native/config.go",
    "chars": 8254,
    "preview": "package redisotel\n\nimport (\n\t\"strings\"\n\n\t\"go.opentelemetry.io/otel/metric\"\n)\n\ntype MetricGroup string\n\nconst (\n\tMetricGr"
  },
  {
    "path": "extra/redisotel-native/go.mod",
    "chars": 791,
    "preview": "module github.com/redis/go-redis/extra/redisotel-native/v9\n\ngo 1.24.0\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nre"
  },
  {
    "path": "extra/redisotel-native/go.sum",
    "chars": 3894,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "extra/redisotel-native/metrics.go",
    "chars": 26776,
    "preview": "package redisotel\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/redis"
  },
  {
    "path": "extra/redisotel-native/metrics_definitions_test.go",
    "chars": 2337,
    "preview": "package redisotel\n\nimport \"testing\"\n\n// Expected metric names per OTel semantic conventions.\n// Reference: https://opent"
  },
  {
    "path": "extra/redisotel-native/metrics_stress_test.go",
    "chars": 5635,
    "preview": "package redisotel\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/redis"
  },
  {
    "path": "extra/redisotel-native/redisotel.go",
    "chars": 17976,
    "preview": "package redisotel\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemet"
  },
  {
    "path": "extra/redisprometheus/README.md",
    "chars": 1536,
    "preview": "# Prometheus Metric Collector\n\nThis package implements a [`prometheus.Collector`](https://pkg.go.dev/github.com/promethe"
  },
  {
    "path": "extra/redisprometheus/collector.go",
    "chars": 3353,
    "preview": "package redisprometheus\n\nimport (\n\t\"github.com/prometheus/client_golang/prometheus\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\n"
  },
  {
    "path": "extra/redisprometheus/go.mod",
    "chars": 1013,
    "preview": "module github.com/redis/go-redis/extra/redisprometheus/v9\n\ngo 1.24\n\nreplace github.com/redis/go-redis/v9 => ../..\n\nrequi"
  },
  {
    "path": "extra/redisprometheus/go.sum",
    "chars": 4557,
    "preview": "github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:"
  },
  {
    "path": "fuzz/fuzz.go",
    "chars": 1596,
    "preview": "//go:build gofuzz\n// +build gofuzz\n\npackage fuzz\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\nconst "
  },
  {
    "path": "generic_commands.go",
    "chars": 10944,
    "preview": "package redis\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9/internal/hashtag\"\n)\n\ntype GenericCmdable inte"
  },
  {
    "path": "geo_commands.go",
    "chars": 5442,
    "preview": "package redis\n\nimport (\n\t\"context\"\n\t\"errors\"\n)\n\ntype GeoCmdable interface {\n\tGeoAdd(ctx context.Context, key string, geo"
  },
  {
    "path": "go.mod",
    "chars": 803,
    "preview": "module github.com/redis/go-redis/v9\n\ngo 1.24\n\nrequire (\n\tgithub.com/bsm/ginkgo/v2 v2.12.0\n\tgithub.com/bsm/gomega v1.27.1"
  },
  {
    "path": "go.sum",
    "chars": 2084,
    "preview": "github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod"
  },
  {
    "path": "hash_commands.go",
    "chars": 23029,
    "preview": "package redis\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9/internal/hashtag\"\n)\n\ntype HashCmdable interfa"
  },
  {
    "path": "helper/helper.go",
    "chars": 949,
    "preview": "package helper\n\nimport (\n\t\"github.com/redis/go-redis/v9/internal/util\"\n\t\"github.com/zeebo/xxh3\"\n)\n\nfunc ParseFloat(s str"
  },
  {
    "path": "helper/helper_test.go",
    "chars": 2238,
    "preview": "package helper\n\nimport \"testing\"\n\n// Golden values from Redis DIGEST command:\n// redis-cli SET testkey myvalue && redis-"
  },
  {
    "path": "hotkeys_commands.go",
    "chars": 4054,
    "preview": "package redis\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strings\"\n)\n\n// HOTKEYS commands are only available on standalone *Client "
  },
  {
    "path": "hotkeys_commands_test.go",
    "chars": 6733,
    "preview": "package redis_test\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t. \"github.com/bsm/ginkgo/v2\"\n\t. \"github.com/bsm/gomega\"\n\n\t\"github.com/"
  },
  {
    "path": "hset_benchmark_test.go",
    "chars": 9160,
    "preview": "package redis_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9\"\n)\n\n// HSET Be"
  },
  {
    "path": "hyperloglog_commands.go",
    "chars": 1052,
    "preview": "package redis\n\nimport \"context\"\n\ntype HyperLogLogCmdable interface {\n\tPFAdd(ctx context.Context, key string, els ...inte"
  },
  {
    "path": "internal/arg.go",
    "chars": 1327,
    "preview": "package internal\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/redis/go-redis/v9/internal/util\"\n)\n\nfunc AppendArg(b "
  },
  {
    "path": "internal/auth/streaming/conn_reauth_credentials_listener.go",
    "chars": 3984,
    "preview": "package streaming\n\nimport (\n\t\"github.com/redis/go-redis/v9/auth\"\n\t\"github.com/redis/go-redis/v9/internal/pool\"\n)\n\n// Con"
  }
]

// ... and 202 more files (download for full content)

About this extraction

This page contains the full source code of the redis/go-redis GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 402 files (3.8 MB), approximately 1.0M tokens, and a symbol index with 4857 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!