Logo

dev-resources.site

for different kinds of informations.

Getting Started with ReductStore in C++

Published at
8/15/2024
Categories
cpp
tutorial
database
reductstore
Author
atimin
Categories
4 categories in total
cpp
open
tutorial
open
database
open
reductstore
open
Author
6 person written this
atimin
open
Getting Started with ReductStore in C++

This quick start guide will walk you through the process of installing and using the ReductStore C++ Client SDK to read and write data to a ReductStore instance.

Installing the C++ SDK

The ReductStore C++ SDK requires the following dependencies:

  • GCC 11.2 or higher (support C++20)
  • CMake 3.18 or higher
  • ZLib
  • OpenSSL 1.1 or 3.0
  • Conan 1.58 (optionally)

To install the ReductStore C++ SDK, follow these steps:

git clone https://github.com/reductstore/reduct-cpp.git
cd reduct-cpp
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
sudo cmake --build . --target install

Enter fullscreen mode Exit fullscreen mode

CMake tries to use the conan package manager if it is installed. If it isn't, it downloads all the dependencies by using FetchContent. To use ReductStore SDK you need only to use find_pacakge in your cmake lists:

After installing the SDK, you need to link the ReductCpp library to your project. The following example shows how to do this using CMake:

cmake_minimum_required(VERSION 3.18)

project(ReductCppExample)
set(CMAKE_CXX_STANDARD 20)

find_package(ZLIB)
find_package(OpenSSL)

find_package(ReductCpp)

add_executable(quick_start quick_start.cc)
target_link_libraries(quick_start ${REDUCT_CPP_LIBRARIES} ${ZLIB_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)

Enter fullscreen mode Exit fullscreen mode

Running ReductStore

If you don't already have a ReductStore instance running, you can easily spin up one as a Docker container. To do this, run the following command:

docker run -p 8383:8383 -e RS_API_TOKEN="my-token" reduct/store:latest

Enter fullscreen mode Exit fullscreen mode

This will start a ReductStore instance listening on port 8383 on your local machine. The RS_API_TOKEN environment variable is used to authenticate requests to the ReductStore instance. You can set it to any value you like, but you will need to use the same value when creating a Client object in your code.

If Docker is not an option, you can also download the ReductStore binaries. Check the Download Page.

Hello World Example

Now when you have the SDK installed and a ReductStore instance running, you can start using the SDK to interact with the ReductStore database. Here is an example of using the SDK to perform basic operations on a ReductStore instance:

#include <reduct/client.h>

#include <iostream>

using reduct::IBucket;
using reduct::IClient;
using sec = std::chrono::seconds;

int main() {
    // 1. Create a ReductStore client
    auto client = IClient::Build("http://127.0.0.1:8383",{
        .api_token = "my-token"
    });

    // 2. Get or create a bucket with 1Gb quota
    auto [bucket, create_err] = client->GetOrCreateBucket("my-bucket", {
        .quota_type = IBucket::QuotaType::kFifo,
        .quota_size = 1'000'000'000
    });

    if (create_err) {
        std::cerr << "Error: " << create_err;
        return -1;
    }

    // 3. Write some data with timestamps in the 'sensor-1' entry
    IBucket::Time start = IBucket::Time::clock::now();
    [[maybe_unused]] auto write_err =
            bucket->Write("sensor-1", start, [](auto rec) { rec->WriteAll("Record #1"); });
    write_err = bucket->Write("sensor-1", start + sec(1), [](auto rec) { rec->WriteAll("Record #2"); });

    // 4. Query the data by time range
    auto err = bucket->Query("sensor-1", start,  start + sec(2), {}, [](auto&& record) {
        std::cout << "Timestamp: " << record.timestamp.time_since_epoch().count() << std::endl;
        std::cout << "Content Length: " << record.size << std::endl;

        auto [blob, read_err] = record.ReadAll();
        if (!read_err) {
            std::cout << "Read blob: " << blob << std::endl;
        }

        return true;
    });

    if (err) {
        std::cerr << "Error: " << err;
        return -1;
    }

    // 5. End
    return 0;
}

Enter fullscreen mode Exit fullscreen mode

Let's break down what this example is doing.

Creating a Client

Before you can interact with a ReductStore instance, you must create a Client object that represents a connection to the ReductStore instance.

To create a ReductStore client, you can use the IClient::Build fabric method from the reduct namespace. Pass the URL of the ReductStore instance you want to connect to as an argument to the method.

auto client = IClient::Build("http://127.0.0.1:8383",{
    .api_token = "my-token"
});

Enter fullscreen mode Exit fullscreen mode

Creating a Bucket

ReductStore organizes data into buckets, each of which has its own quota and settings. It's a necessary step to create a bucket before writing data to it. You can read more about buckets in the Buckets Guide, but for now, let's just create one.

To create a bucket, you should use the GetOrCreateBucket method on a Client instance. Pass the name of the bucket you want to create as an argument, along with settings. If the bucket already exists, the GetOrCreateBucket method will return it:

auto [bucket, create_err] = client->GetOrCreateBucket("my-bucket", {
    .quota_type = IBucket::QuotaType::kFifo,
    .quota_size = 1'000'000'000
});

if (create_err) {
    std::cerr << "Error: " << create_err;
    return -1;
}

Enter fullscreen mode Exit fullscreen mode

In this example we create a bucket with a FIFO quota of 1GB. This means that the oldest data will be deleted when the bucket reaches 1GB.

Data Ingestion

Time series data is stored in entries within a bucket. An entry is a collection of records with unique timestamps. It must have a unique name within the bucket and usually represents a data source, such as a vibration sensor or a CV camera.

To write a timestamped record to an entry in a bucket, you should use the Write method on a Bucket instance. Pass the name of the entry you want to write to as an argument, along with the timestamp you want to write. The Write method will call a callback function with the WritableRecord instance to write to the entry:

IBucket::Time start = IBucket::Time::clock::now();
[[maybe_unused]] auto write_err =
        bucket->Write("sensor-1", start, [](auto rec) { rec->WriteAll("Record #1"); });
write_err = bucket->Write("sensor-1", start + sec(1), [](auto rec) { rec->WriteAll("Record #2"); });

Enter fullscreen mode Exit fullscreen mode

This is the simplest case of writing data using the Python SDK. You can also write data in chunks and annotate records with labels. You can find more information and examples in the Data Ingestion Guide.

Data Querying

Usually, we don't read a particular record by its timestamp, but query records in a time range.

To iterate over all records in a given time range, you should use the Query method on a bucket instance. Pass the name of the entry to iterate over, and start and stop arguments to specify the time interval. The method will return a callback function with the ReadableRecord instance for each record in the time range:

auto err = bucket->Query("sensor-1", start,  start + sec(2), {}, [](auto&& record) {
    std::cout << "Timestamp: " << record.timestamp.time_since_epoch().count() << std::endl;
    std::cout << "Content Length: " << record.size << std::endl;

    auto [blob, read_err] = record.ReadAll();
    if (!read_err) {
        std::cout << "Read blob: " << blob << std::endl;
    }

    return true;
});

if (err) {
    std::cerr << "Error: " << err;
    return -1;
}

Enter fullscreen mode Exit fullscreen mode

The query method has many parameters for filtering and returning sample records. For more information and examples, see the Data Querying Guide.

Next Steps[​]

As you can see to get started with the Client SDK is very easy. However,it doesn't cover all the features of the SDK and the database. Check our Guides to learn more about the ReductStore features and how to use them.

reductstore Article's
30 articles in total
Favicon
ReductStore v1.13.0 Released With New Conditional Query API
Favicon
Keeping MQTT Data History with Node.js
Favicon
ReductStore v1.12.0 released: record deletion API and storage engine optimization
Favicon
3 Ways to Store Computer Vision Data
Favicon
ReductStore v1.11.0: Changing labels and storage engine optimization
Favicon
Getting Started with ReductStore in C++
Favicon
How to Keep a History of MQTT Data With Rust
Favicon
Deploy ReductStore as Azure Virtual Machine
Favicon
Getting Started with ReductStore in Node.js
Favicon
Getting Started with ReductStore in Python
Favicon
ReductStore v1.10.0: downsampling and optimization
Favicon
ReductStore CLI Client now in Rust
Favicon
Time Series Blob Data: ReductStore vs. MongoDB
Favicon
Time Series Blob Data: ReductStore vs. TimescaleDB
Favicon
ReductStore v1.9.0 Released
Favicon
How to Keep a History of MQTT Data With Python
Favicon
Performance comparison: ReductStore Vs. Minio
Favicon
ReductStore v1.8.0 Has Been Released with Data Replication
Favicon
ReductStore v1.7.0 has been released with provisioning and batch writing
Favicon
ReductStore 1.6.0 has been released with new license and client SDK for Rust
Favicon
ReductStore v1.5.0 has been released
Favicon
ReductStore v1.4.0 in Rust has been released
Favicon
Subscribing new records with Reduct C++ SDK
Favicon
6 weeks with Rust
Favicon
Data Reduction and Why It Is Important For Edge Computing
Favicon
We Are Moving to Rust
Favicon
CLI Client for ReductStore v0.8.0 has been released
Favicon
How to Use "Cats" dataset with Python ReductStore SDK
Favicon
Streamline your edge computing workflows with ReductStore, now available on Snap
Favicon
ReductStore Client SDK for C++ v1.3.0 with Labels Support

Featured ones: