This document provides practical examples for using the RALE distributed consensus and key-value store system. Examples range from simple single-node setups to complex multi-node distributed applications.
File: examples/hello_world.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <librale.h>
int main() {
printf("RALE Hello World Example\n");
/* Initialize the cluster subsystem */
if (librale_cluster_init() != LIBRALE_SUCCESS) {
fprintf(stderr, "Failed to initialize cluster\n");
return 1;
}
/* Initialize RALE consensus */
if (librale_rale_init(1, "./rale_data") != LIBRALE_SUCCESS) {
fprintf(stderr, "Failed to initialize RALE\n");
return 1;
}
/* Initialize distributed store */
if (librale_dstore_init("./rale_data") != LIBRALE_SUCCESS) {
fprintf(stderr, "Failed to initialize DStore\n");
return 1;
}
/* Start services */
librale_rale_start();
librale_network_start(7400, 7401);
printf("RALE services started\n");
/* Store some data */
const char *key = "greeting";
const char *value = "Hello, RALE World!";
if (librale_dstore_put(key, value, strlen(value)) == LIBRALE_SUCCESS) {
printf("Stored: %s = %s\n", key, value);
}
/* Retrieve the data */
char buffer[256];
size_t len = sizeof(buffer);
if (librale_dstore_get(key, buffer, &len) == LIBRALE_SUCCESS) {
buffer[len] = '\0';
printf("Retrieved: %s = %s\n", key, buffer);
}
/* Run for a few seconds */
printf("Running for 5 seconds...\n");
sleep(5);
/* Cleanup */
librale_cleanup();
printf("RALE services stopped\n");
return 0;
}Build and Run:
# Compile
gcc -o hello_world hello_world.c -lrale
# Run
./hello_worldFile: examples/kv_store.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <librale.h>
void print_help() {
printf("Commands:\n");
printf(" put <key> <value> - Store a key-value pair\n");
printf(" get <key> - Retrieve value by key\n");
printf(" del <key> - Delete a key\n");
printf(" list [prefix] - List keys with optional prefix\n");
printf(" status - Show cluster status\n");
printf(" help - Show this help\n");
printf(" quit - Exit\n");
}
int main() {
char *input;
char *cmd, *key, *value;
char buffer[1024];
size_t len;
/* Initialize RALE */
if (librale_cluster_init() != LIBRALE_SUCCESS ||
librale_rale_init(1, "./kv_data") != LIBRALE_SUCCESS ||
librale_dstore_init("./kv_data") != LIBRALE_SUCCESS) {
fprintf(stderr, "Failed to initialize RALE\n");
return 1;
}
/* Start services */
librale_rale_start();
librale_network_start(7400, 7401);
printf("RALE Key-Value Store\n");
printf("Type 'help' for commands\n\n");
while ((input = readline("rale> ")) != NULL) {
if (strlen(input) > 0) {
add_history(input);
}
/* Parse command */
cmd = strtok(input, " ");
if (cmd == NULL) {
free(input);
continue;
}
if (strcmp(cmd, "quit") == 0 || strcmp(cmd, "exit") == 0) {
free(input);
break;
} else if (strcmp(cmd, "help") == 0) {
print_help();
} else if (strcmp(cmd, "put") == 0) {
key = strtok(NULL, " ");
value = strtok(NULL, "");
if (key && value) {
if (librale_dstore_put(key, value, strlen(value)) == LIBRALE_SUCCESS) {
printf("OK\n");
} else {
printf("ERROR: Failed to store key\n");
}
} else {
printf("Usage: put <key> <value>\n");
}
} else if (strcmp(cmd, "get") == 0) {
key = strtok(NULL, " ");
if (key) {
len = sizeof(buffer);
if (librale_dstore_get(key, buffer, &len) == LIBRALE_SUCCESS) {
buffer[len] = '\0';
printf("%s\n", buffer);
} else {
printf("ERROR: Key not found\n");
}
} else {
printf("Usage: get <key>\n");
}
} else if (strcmp(cmd, "del") == 0) {
key = strtok(NULL, " ");
if (key) {
if (librale_dstore_delete(key) == LIBRALE_SUCCESS) {
printf("OK\n");
} else {
printf("ERROR: Failed to delete key\n");
}
} else {
printf("Usage: del <key>\n");
}
} else if (strcmp(cmd, "status") == 0) {
if (librale_rale_is_leader()) {
printf("Status: Leader\n");
} else {
int leader_id;
if (librale_rale_get_leader(&leader_id) == LIBRALE_SUCCESS) {
printf("Status: Follower (Leader: Node %d)\n", leader_id);
} else {
printf("Status: Unknown\n");
}
}
} else {
printf("Unknown command: %s\n", cmd);
printf("Type 'help' for available commands\n");
}
free(input);
}
printf("\nShutting down...\n");
librale_cleanup();
return 0;
}Build with readline support:
gcc -o kv_store kv_store.c -lrale -lreadlineFile: examples/cluster_node.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <librale.h>
static volatile int running = 1;
void signal_handler(int sig) {
printf("\nReceived signal %d, shutting down...\n", sig);
running = 0;
}
int main(int argc, char *argv[]) {
int node_id;
int rale_port, dstore_port;
char data_dir[256];
if (argc != 2) {
printf("Usage: %s <node_id>\n", argv[0]);
printf("Example: %s 1\n", argv[0]);
return 1;
}
node_id = atoi(argv[1]);
rale_port = 7400 + node_id - 1;
dstore_port = 7500 + node_id - 1;
snprintf(data_dir, sizeof(data_dir), "./node%d_data", node_id);
printf("Starting RALE Node %d\n", node_id);
printf("RALE Port: %d, DStore Port: %d\n", rale_port, dstore_port);
printf("Data Directory: %s\n", data_dir);
/* Set up signal handlers */
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* Initialize RALE */
if (librale_cluster_init() != LIBRALE_SUCCESS) {
fprintf(stderr, "Failed to initialize cluster\n");
return 1;
}
/* Add cluster nodes */
librale_cluster_add_node(1, "node1", "127.0.0.1", 7400, 7500);
librale_cluster_add_node(2, "node2", "127.0.0.1", 7401, 7501);
librale_cluster_add_node(3, "node3", "127.0.0.1", 7402, 7502);
/* Initialize this node */
if (librale_rale_init(node_id, data_dir) != LIBRALE_SUCCESS) {
fprintf(stderr, "Failed to initialize RALE\n");
return 1;
}
if (librale_dstore_init(data_dir) != LIBRALE_SUCCESS) {
fprintf(stderr, "Failed to initialize DStore\n");
return 1;
}
/* Start services */
librale_rale_start();
librale_network_start(rale_port, dstore_port);
printf("Node %d started successfully\n", node_id);
/* Main loop */
while (running) {
/* Check leadership status */
static int last_leader = -1;
int current_leader;
if (librale_rale_get_leader(¤t_leader) == LIBRALE_SUCCESS) {
if (current_leader != last_leader) {
if (current_leader == node_id) {
printf("Node %d: I am now the leader!\n", node_id);
} else {
printf("Node %d: Node %d is the leader\n", node_id, current_leader);
}
last_leader = current_leader;
}
}
sleep(5);
}
printf("Node %d shutting down...\n", node_id);
librale_cleanup();
return 0;
}Start a three-node cluster:
# Terminal 1
./cluster_node 1
# Terminal 2
./cluster_node 2
# Terminal 3
./cluster_node 3File: examples/election_monitor.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <librale.h>
void print_timestamp() {
time_t now = time(NULL);
char *timestr = ctime(&now);
timestr[strlen(timestr) - 1] = '\0'; /* Remove newline */
printf("[%s] ", timestr);
}
int main() {
int current_leader = -1;
int election_count = 0;
printf("RALE Leader Election Monitor\n");
printf("Monitoring leadership changes...\n\n");
/* Initialize cluster for monitoring */
if (librale_cluster_init() != LIBRALE_SUCCESS) {
fprintf(stderr, "Failed to initialize cluster\n");
return 1;
}
/* Connect to cluster */
librale_cluster_add_node(1, "node1", "127.0.0.1", 7400, 7500);
librale_cluster_add_node(2, "node2", "127.0.0.1", 7401, 7501);
librale_cluster_add_node(3, "node3", "127.0.0.1", 7402, 7502);
while (1) {
int leader_id;
if (librale_rale_get_leader(&leader_id) == LIBRALE_SUCCESS) {
if (leader_id != current_leader) {
election_count++;
print_timestamp();
if (current_leader == -1) {
printf("Initial leader: Node %d\n", leader_id);
} else {
printf("Leadership change #%d: Node %d -> Node %d\n",
election_count, current_leader, leader_id);
}
current_leader = leader_id;
}
} else {
if (current_leader != -1) {
print_timestamp();
printf("No leader available\n");
current_leader = -1;
}
}
sleep(1);
}
return 0;
}File: examples/distributed_counter.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <librale.h>
typedef struct {
const char *counter_name;
int increment_count;
int thread_id;
} thread_data_t;
void *increment_worker(void *arg) {
thread_data_t *data = (thread_data_t *)arg;
char key[256];
char value_str[32];
char buffer[32];
size_t len;
int current_value;
snprintf(key, sizeof(key), "counter:%s", data->counter_name);
for (int i = 0; i < data->increment_count; i++) {
/* Read current value */
len = sizeof(buffer);
if (librale_dstore_get(key, buffer, &len) == LIBRALE_SUCCESS) {
buffer[len] = '\0';
current_value = atoi(buffer);
} else {
current_value = 0; /* Counter doesn't exist yet */
}
/* Increment */
current_value++;
/* Write back */
snprintf(value_str, sizeof(value_str), "%d", current_value);
if (librale_dstore_put(key, value_str, strlen(value_str)) == LIBRALE_SUCCESS) {
printf("Thread %d: Counter '%s' = %d\n",
data->thread_id, data->counter_name, current_value);
} else {
printf("Thread %d: Failed to update counter\n", data->thread_id);
}
/* Small delay to see interleaving */
usleep(100000); /* 100ms */
}
return NULL;
}
int main() {
const int NUM_THREADS = 3;
const int INCREMENTS_PER_THREAD = 5;
pthread_t threads[NUM_THREADS];
thread_data_t thread_data[NUM_THREADS];
printf("Distributed Counter Example\n");
printf("Running %d threads, %d increments each\n\n",
NUM_THREADS, INCREMENTS_PER_THREAD);
/* Initialize RALE */
if (librale_cluster_init() != LIBRALE_SUCCESS ||
librale_rale_init(1, "./counter_data") != LIBRALE_SUCCESS ||
librale_dstore_init("./counter_data") != LIBRALE_SUCCESS) {
fprintf(stderr, "Failed to initialize RALE\n");
return 1;
}
librale_rale_start();
librale_network_start(7400, 7401);
/* Create worker threads */
for (int i = 0; i < NUM_THREADS; i++) {
thread_data[i].counter_name = "test_counter";
thread_data[i].increment_count = INCREMENTS_PER_THREAD;
thread_data[i].thread_id = i + 1;
if (pthread_create(&threads[i], NULL, increment_worker, &thread_data[i]) != 0) {
fprintf(stderr, "Failed to create thread %d\n", i);
return 1;
}
}
/* Wait for all threads to complete */
for (int i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
/* Read final counter value */
char buffer[32];
size_t len = sizeof(buffer);
if (librale_dstore_get("counter:test_counter", buffer, &len) == LIBRALE_SUCCESS) {
buffer[len] = '\0';
printf("\nFinal counter value: %s\n", buffer);
printf("Expected value: %d\n", NUM_THREADS * INCREMENTS_PER_THREAD);
}
librale_cleanup();
return 0;
}File: examples/config_manager.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <json-c/json.h>
#include <librale.h>
typedef struct {
char app_name[64];
char environment[32];
char version[16];
} app_config_t;
int store_config(const char *app_name, const app_config_t *config) {
char key[256];
json_object *json_obj, *json_app, *json_env, *json_ver;
const char *json_string;
/* Create JSON object */
json_obj = json_object_new_object();
json_app = json_object_new_string(config->app_name);
json_env = json_object_new_string(config->environment);
json_ver = json_object_new_string(config->version);
json_object_object_add(json_obj, "app_name", json_app);
json_object_object_add(json_obj, "environment", json_env);
json_object_object_add(json_obj, "version", json_ver);
/* Store in distributed store */
json_string = json_object_to_json_string(json_obj);
snprintf(key, sizeof(key), "config:app:%s", app_name);
int result = librale_dstore_put(key, json_string, strlen(json_string));
json_object_put(json_obj);
return result;
}
int load_config(const char *app_name, app_config_t *config) {
char key[256];
char buffer[1024];
size_t len = sizeof(buffer);
json_object *json_obj, *json_field;
const char *str_value;
snprintf(key, sizeof(key), "config:app:%s", app_name);
if (librale_dstore_get(key, buffer, &len) != LIBRALE_SUCCESS) {
return -1;
}
buffer[len] = '\0';
json_obj = json_tokener_parse(buffer);
if (json_obj == NULL) {
return -1;
}
/* Extract fields */
if (json_object_object_get_ex(json_obj, "app_name", &json_field)) {
str_value = json_object_get_string(json_field);
strncpy(config->app_name, str_value, sizeof(config->app_name) - 1);
}
if (json_object_object_get_ex(json_obj, "environment", &json_field)) {
str_value = json_object_get_string(json_field);
strncpy(config->environment, str_value, sizeof(config->environment) - 1);
}
if (json_object_object_get_ex(json_obj, "version", &json_field)) {
str_value = json_object_get_string(json_field);
strncpy(config->version, str_value, sizeof(config->version) - 1);
}
json_object_put(json_obj);
return 0;
}
int main() {
app_config_t config;
printf("Distributed Configuration Manager\n\n");
/* Initialize RALE */
if (librale_cluster_init() != LIBRALE_SUCCESS ||
librale_rale_init(1, "./config_data") != LIBRALE_SUCCESS ||
librale_dstore_init("./config_data") != LIBRALE_SUCCESS) {
fprintf(stderr, "Failed to initialize RALE\n");
return 1;
}
librale_rale_start();
librale_network_start(7400, 7401);
/* Store some configurations */
strcpy(config.app_name, "web_server");
strcpy(config.environment, "production");
strcpy(config.version, "1.2.3");
if (store_config("web_server", &config) == LIBRALE_SUCCESS) {
printf("Stored configuration for web_server\n");
}
strcpy(config.app_name, "database");
strcpy(config.environment, "staging");
strcpy(config.version, "2.1.0");
if (store_config("database", &config) == LIBRALE_SUCCESS) {
printf("Stored configuration for database\n");
}
/* Load and display configurations */
printf("\nStored configurations:\n");
if (load_config("web_server", &config) == 0) {
printf("web_server: %s v%s (%s)\n",
config.app_name, config.version, config.environment);
}
if (load_config("database", &config) == 0) {
printf("database: %s v%s (%s)\n",
config.app_name, config.version, config.environment);
}
librale_cleanup();
return 0;
}File: examples/failover_test.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <librale.h>
void start_node(int node_id) {
char data_dir[256];
int rale_port = 7400 + node_id - 1;
int dstore_port = 7500 + node_id - 1;
snprintf(data_dir, sizeof(data_dir), "./test_node%d", node_id);
printf("Child: Starting node %d (PID %d)\n", node_id, getpid());
librale_cluster_init();
/* Add all cluster nodes */
for (int i = 1; i <= 3; i++) {
librale_cluster_add_node(i,
(i == 1) ? "node1" : (i == 2) ? "node2" : "node3",
"127.0.0.1",
7400 + i - 1,
7500 + i - 1);
}
librale_rale_init(node_id, data_dir);
librale_dstore_init(data_dir);
librale_rale_start();
librale_network_start(rale_port, dstore_port);
/* Keep running until killed */
while (1) {
sleep(1);
}
}
int main() {
pid_t node_pids[3];
int status;
printf("RALE Failover Test\n");
printf("Starting 3-node cluster...\n\n");
/* Start three nodes */
for (int i = 1; i <= 3; i++) {
node_pids[i-1] = fork();
if (node_pids[i-1] == 0) {
/* Child process - run node */
start_node(i);
exit(0);
} else if (node_pids[i-1] < 0) {
fprintf(stderr, "Failed to fork node %d\n", i);
return 1;
}
}
printf("Parent: All nodes started\n");
printf("Waiting 10 seconds for cluster formation...\n");
sleep(10);
printf("Killing node 1 to test failover...\n");
kill(node_pids[0], SIGTERM);
waitpid(node_pids[0], &status, 0);
printf("Node 1 terminated\n");
printf("Waiting 15 seconds for failover...\n");
sleep(15);
printf("Restarting node 1...\n");
node_pids[0] = fork();
if (node_pids[0] == 0) {
start_node(1);
exit(0);
}
printf("Waiting 10 more seconds...\n");
sleep(10);
printf("Terminating all nodes...\n");
for (int i = 0; i < 3; i++) {
if (node_pids[i] > 0) {
kill(node_pids[i], SIGTERM);
waitpid(node_pids[i], &status, 0);
}
}
printf("Failover test completed\n");
return 0;
}File: examples/benchmark.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <librale.h>
double get_time() {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + tv.tv_usec / 1000000.0;
}
void benchmark_writes(int count) {
char key[64], value[64];
double start, end;
int successful = 0;
printf("Benchmarking %d write operations...\n", count);
start = get_time();
for (int i = 0; i < count; i++) {
snprintf(key, sizeof(key), "bench_key_%d", i);
snprintf(value, sizeof(value), "benchmark_value_%d", i);
if (librale_dstore_put(key, value, strlen(value)) == LIBRALE_SUCCESS) {
successful++;
}
}
end = get_time();
printf("Write Results:\n");
printf(" Operations: %d\n", count);
printf(" Successful: %d\n", successful);
printf(" Failed: %d\n", count - successful);
printf(" Time: %.3f seconds\n", end - start);
printf(" Throughput: %.1f ops/sec\n", successful / (end - start));
printf(" Average latency: %.3f ms\n", (end - start) * 1000 / count);
}
void benchmark_reads(int count) {
char key[64], buffer[64];
size_t len;
double start, end;
int successful = 0;
printf("\nBenchmarking %d read operations...\n", count);
start = get_time();
for (int i = 0; i < count; i++) {
snprintf(key, sizeof(key), "bench_key_%d", i % 1000); /* Read existing keys */
len = sizeof(buffer);
if (librale_dstore_get(key, buffer, &len) == LIBRALE_SUCCESS) {
successful++;
}
}
end = get_time();
printf("Read Results:\n");
printf(" Operations: %d\n", count);
printf(" Successful: %d\n", successful);
printf(" Failed: %d\n", count - successful);
printf(" Time: %.3f seconds\n", end - start);
printf(" Throughput: %.1f ops/sec\n", successful / (end - start));
printf(" Average latency: %.3f ms\n", (end - start) * 1000 / count);
}
int main(int argc, char *argv[]) {
int write_count = 1000;
int read_count = 5000;
if (argc >= 2) write_count = atoi(argv[1]);
if (argc >= 3) read_count = atoi(argv[2]);
printf("RALE Benchmark Tool\n");
printf("Write operations: %d\n", write_count);
printf("Read operations: %d\n\n", read_count);
/* Initialize RALE */
if (librale_cluster_init() != LIBRALE_SUCCESS ||
librale_rale_init(1, "./bench_data") != LIBRALE_SUCCESS ||
librale_dstore_init("./bench_data") != LIBRALE_SUCCESS) {
fprintf(stderr, "Failed to initialize RALE\n");
return 1;
}
librale_rale_start();
librale_network_start(7400, 7401);
/* Wait for initialization */
sleep(2);
/* Run benchmarks */
benchmark_writes(write_count);
benchmark_reads(read_count);
printf("\nBenchmark completed\n");
librale_cleanup();
return 0;
}File: examples/Makefile
CC = gcc
CFLAGS = -Wall -Wextra -std=c99 -D_GNU_SOURCE
LIBS = -lrale -lpthread
JSON_LIBS = -ljson-c
READLINE_LIBS = -lreadline
# Default target
all: hello_world kv_store cluster_node election_monitor \
distributed_counter benchmark failover_test
# Basic examples
hello_world: hello_world.c
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
cluster_node: cluster_node.c
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
election_monitor: election_monitor.c
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
benchmark: benchmark.c
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
failover_test: failover_test.c
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
# Examples with additional dependencies
kv_store: kv_store.c
$(CC) $(CFLAGS) -o $@ $< $(LIBS) $(READLINE_LIBS)
distributed_counter: distributed_counter.c
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
config_manager: config_manager.c
$(CC) $(CFLAGS) -o $@ $< $(LIBS) $(JSON_LIBS)
# Clean up
clean:
rm -f hello_world kv_store cluster_node election_monitor \
distributed_counter config_manager benchmark failover_test
rm -rf *_data *.log
# Test targets
test-single: hello_world
./hello_world
test-cluster: cluster_node
@echo "Start each node in a separate terminal:"
@echo "./cluster_node 1"
@echo "./cluster_node 2"
@echo "./cluster_node 3"
.PHONY: all clean test-single test-clusterFile: examples/CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(rale_examples)
# Find required packages
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBRALE REQUIRED librale)
# Find optional packages
find_package(PkgConfig)
pkg_check_modules(JSON_C json-c)
# Set compiler flags
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -D_GNU_SOURCE")
# Include directories
include_directories(${LIBRALE_INCLUDE_DIRS})
# Basic examples
add_executable(hello_world hello_world.c)
target_link_libraries(hello_world ${LIBRALE_LIBRARIES} pthread)
add_executable(cluster_node cluster_node.c)
target_link_libraries(cluster_node ${LIBRALE_LIBRARIES} pthread)
add_executable(benchmark benchmark.c)
target_link_libraries(benchmark ${LIBRALE_LIBRARIES} pthread)
# Examples with readline
find_path(READLINE_INCLUDE_DIR readline/readline.h)
find_library(READLINE_LIBRARY readline)
if(READLINE_INCLUDE_DIR AND READLINE_LIBRARY)
add_executable(kv_store kv_store.c)
target_include_directories(kv_store PRIVATE ${READLINE_INCLUDE_DIR})
target_link_libraries(kv_store ${LIBRALE_LIBRARIES} ${READLINE_LIBRARY} pthread)
endif()
# Examples with JSON-C
if(JSON_C_FOUND)
add_executable(config_manager config_manager.c)
target_include_directories(config_manager PRIVATE ${JSON_C_INCLUDE_DIRS})
target_link_libraries(config_manager ${LIBRALE_LIBRARIES} ${JSON_C_LIBRARIES} pthread)
endif()Build examples:
mkdir build && cd build
cmake ..
make -j$(nproc)# Single node example
./hello_world
# Interactive key-value store
./kv_store
# Three-node cluster (run in separate terminals)
./cluster_node 1
./cluster_node 2
./cluster_node 3
# Monitor leadership changes
./election_monitor
# Performance testing
./benchmark 5000 10000# Failover testing
./failover_test
# Long-running stability test
timeout 3600 ./cluster_node 1 # Run for 1 hour
# Performance under load
./benchmark 50000 100000These examples demonstrate the flexibility and power of the RALE system for building distributed applications with strong consistency guarantees and automatic failover capabilities.