ReductStore

repository·main·Indexed 18 days ago

https://github.com/reductstore/reductstore

A high-performance, time-indexed object storage system designed for robotics and industrial IoT workloads. It enables the storage of multimodal binary data—such as images, logs, and ROS bags—with efficient querying via timestamps and metadata labels. The system includes a Lifecycle Module for automated data maintenance (deletion and compression) and supports integration with Zenoh for routing and authentication.

Tokens
27K
Snippets
85
Records
117
Agent score
63%

What's inside ReductStore

  1. Overview of the Lifecycle Module

    main

    The Lifecycle Module implements background lifecycle policies for buckets to automate data maintenance. It supports two primary actions:

    • delete: Removes records older than a specified older_than duration.
    • compress: Recompresses eligible blocks older than a specified older_than duration.

    The module is organized into three layers:

    1. Repository: Manages lifecycle definitions, validates settings, and controls the lifecycle of workers.
    2. Task: A worker loop that runs a specific policy on a schedule and emits system events.
    3. Action: The execution layer that performs the actual work (deleting or compressing) against storage and reports progress.

    For primary nodes, definitions are persisted in .lifecycles within the data directory. For replica nodes, the module operates in a read-only mode where no workers are started.

  2. How lifecycle tasks and progress work

    main

    Lifecycle tasks use a progress model to avoid processing massive amounts of data in a single run, especially when dealing with large backlogs.

    Progress Calculation

    Tasks determine a processing window defined by a start and stop timestamp:

    • Start: Always the oldest matching record found in the bucket. Tasks scan from the oldest record to ensure that data that became eligible again (e.g., via label updates) is not missed.
    • Stop: The minimum of the effective_cutoff_stop (the point in time defined by older_than) and a forward-moving window.

    Controlling Workload with processing_interval

    You can bound the amount of data processed in a single run using the processing_interval setting:

    • If processing_interval is set: The task advances by this duration per run.
    • If processing_interval is NOT set: The task advances by 24 * interval (where interval is the task's scheduled frequency).

    Progress Persistence

    When system events are enabled, the module uses the last_processed_ts field from the latest lifecycle stats event (found at $system/lifecycle/<instance>/<policy>) to resume work where it left off.

  3. Lifecycle Task Loop Semantics

    main

    The LifecycleTask runs an inner loop with specific retry logic to handle sparse data:

    • If a run completes and returns affected_records == 0 but caught_up == false, the worker does not wait for the full scheduled interval. Instead, it retries after 100 ms.
    • This allows the task to quickly advance through empty time windows until it reaches the current data cutoff.
    • Once the task either finds records to process (affected_records > 0) or reaches the cutoff (caught_up == true), it returns to its normal scheduled interval.
  4. When to use ReductStore

    main

    ReductStore is a high-performance, time-indexed object storage system designed for robotics and industrial IoT.

    Use ReductStore if:

    • You have a continuous stream of binary data (images, video, sensor payloads, logs, ROS bags).
    • You need to query this data by both time range and metadata (labels).
    • You need to manage data lifecycles (e.g., compression or deletion after a certain period).
    • You want to replicate only specific subsets of data (filtered by labels) to the cloud to save bandwidth.

    Do NOT use ReductStore if:

    • You only have numerical data (use a Time-Series Database instead).
    • You only have blob data without a need for historical/time-indexed access (use standard object storage).
    • You need a message broker (ReductStore is for storage and streaming, not message queueing).
  5. Install ReductStore via Docker

    main

    The fastest way to run ReductStore is using Docker. You need to create a local data directory and ensure it has the correct permissions for the container user (UID 10001).

    1. Create a data directory: mkdir -p ./data
    2. Set permissions: sudo chown -R 10001:10001 ./data
    3. Run the container, mapping port 8383 and providing an RS_API_TOKEN via environment variable.
    mkdir -p ./data
    sudo chown -R 10001:10001 ./data
    docker run -p 8383:8383 -v ${PWD}/data:/data \
      -e RS_API_TOKEN=my-secret-token reduct/store:latest
  6. Run ReductStore integration tests locally

    main

    To run the integration tests locally, you must first start a Zenoh router using Docker, then start ReductStore with the necessary Zenoh and feature flags, and finally execute the pytest suite.

    1. Start Zenoh router

    docker run --init -d --name zenoh-router -p 7447:7447/tcp eclipse/zenoh

    2. Start ReductStore

    Run the following command to start the reductstore package with the fs-backend, web-console, and zenoh-api features enabled:

    RS_DATA_PATH=~/data-test RS_DISABLE_AUTH=true RS_ZENOH_ENABLED=1 RS_ZENOH_CONFIG="mode=client;connect/endpoints=[tcp/127.0.0.1:7447]" RS_ZENOH_SUB_KEYEXPRS="**" RS_ZENOH_QUERY_KEYEXPRS="**" RS_CORS_ALLOW_ORIGIN="https://first-allowed-origin.com, https://second-allowed-origin.com" cargo run -p reductstore --features "fs-backend web-console zenoh-api"

    3. Run tests

    pytest integration_tests/zenoh

    Cleanup

    docker rm -f zenoh-router
    rm -rf ~/data-test
    # 1) Start the Zenoh router:
    docker run --init -d --name zenoh-router -p 7447:7447/tcp eclipse/zenoh
    
    # 2) Start ReductStore:
    RS_DATA_PATH=~/data-test RS_DISABLE_AUTH=true RS_ZENOH_ENABLED=1 RS_ZENOH_CONFIG="mode=client;connect/endpoints=[tcp/127.0.0.1:7447]" RS_ZENOH_SUB_KEYEXPRS="**" RS_ZENOH_QUERY_KEYEXPRS="**" RS_CORS_ALLOW_ORIGIN="https://first-allowed-origin.com, https://second-allowed-origin.com" cargo run -p reductstore --features "fs-backend web-console zenoh-api"
    
    # 3) Run tests:
    pytest integration_tests/zenoh
  7. Install ReductStore via Linux Binary

    main

    You can run ReductStore directly on Linux by downloading the binary from the latest release. You must specify the data path using the RS_DATA_PATH environment variable and provide an RS_API_TOKEN.

    curl -LO https://github.com/reductstore/reductstore/releases/latest/download/reductstore.x86_64-unknown-linux-gnu.tar.gz
    tar -xzf reductstore.x86_64-unknown-linux-gnu.tar.gz
    mkdir -p ./data
    RS_DATA_PATH=./data RS_API_TOKEN=my-secret-token ./reductstore
  8. Use specialized suffixes for Batch and Query operations

    main

    The ReductStore HTTP API supports specialized operations by appending suffixes to the entry path. These suffixes allow you to perform batch operations or complex queries on an entry instead of standard single-entry CRUD operations.

    Batch Operations

    Append /batch to the entry path to trigger batch processing for reading, writing, updating, or removing records.

    • Read Batch: GET /{bucket_name}/{entry_name}/batch
    • Write Batch: POST /{bucket_name}/{entry_name}/batch
    • Update Batch: PATCH /{bucket_name}/{entry_name}/batch
    • Remove Batch: DELETE /{bucket_name}/{entry_name}/batch

    Query Operations

    Append /q to the entry path to perform queries or targeted removals using a JSON body.

    • Query/Remove via Query: POST /{bucket_name}/{entry_name}/q
      • Uses a QueryEntry JSON body to specify the QueryType (e.g., Query or Remove).
  9. Use extension attachments from meta entries

    main

    ReductStore can automatically attach metadata from system meta entries (e.g., entry/$meta) to your extension queries. If a meta entry exists for a matching pattern, its contents are parsed as JSON and injected into the extension's configuration under an attachments key.

    To use this, ensure your meta entries have a label key that matches the extension name or the desired attachment key. The system will collect up to MAX_META_ATTACHMENTS (100) records from the meta entry to build the attachment object.

  10. Configure the `processing_interval` for lifecycle tasks

    main

    The processing_interval is an optional setting used to bound the maximum span of data time a single lifecycle run processes. This is useful for keeping individual runs computationally cheap on buckets with large backlogs.

    • Purpose: Limits the data window per run.
    • Requirement: Must be a positive duration.
    • Behavior: When set, it replaces the default 24 * interval window and also bounds the full-range window used when system events are disabled.