Skip to content

Commit a064730

Browse files
authored
Merge pull request #6247 from makr-code/copilot/deep-dive-raid-sharding
[EPIC] Sharding runtime closes latency, rebalance, and GSI roadmap gaps
2 parents 63cf089 + 04a1105 commit a064730

28 files changed

Lines changed: 893 additions & 269 deletions

.github/workflows/reusable-cmake-build.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ jobs:
141141
THEMIS_BUILD_SIG: ${{ secrets.THEMIS_BUILD_SIG }}
142142
run: |
143143
cd "$WORKING_DIRECTORY"
144+
# Clean stale CMake cache entries before reconfiguring so a previous
145+
# toolchain/bootstrap state cannot poison a later runner build.
146+
find . -maxdepth 2 \( -name CMakeCache.txt -o -name CMakeFiles \) -print
147+
find . -maxdepth 2 -name CMakeCache.txt -delete
148+
find . -maxdepth 2 -type d -name CMakeFiles -prune -exec rm -rf {} +
144149
script_path="$RUNNER_TEMP/cmake-build-configure.sh"
145150
printf '%s\n' "$CONFIGURE_COMMAND" > "$script_path"
146151
bash "$script_path"

cmake/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2854,6 +2854,7 @@ set(THEMIS_CORE_SOURCES
28542854
../src/sharding/distributed_coordinator.cpp
28552855
../src/sharding/shard_resource_manager.cpp
28562856
../src/sharding/locality_aware_router.cpp
2857+
../src/sharding/global_secondary_index.cpp
28572858
../src/sharding/raft_configuration.cpp
28582859
../src/sharding/raft_log.cpp
28592860
../src/sharding/raft_state.cpp

cmake/Dependencies.cmake

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ else()
99
set(_the_vcpkg_root "${CMAKE_SOURCE_DIR}/vcpkg")
1010
endif()
1111

12-
if(EXISTS "${_the_vcpkg_root}")
12+
# Respect the system-package build mode: the community/system presets intentionally
13+
# leave CMAKE_TOOLCHAIN_FILE empty to avoid network-vcpkg bootstrapping. A local
14+
# checkout must not silently override that explicit opt-out.
15+
if(DEFINED CMAKE_TOOLCHAIN_FILE AND "${CMAKE_TOOLCHAIN_FILE}" STREQUAL "")
16+
message(STATUS "CMAKE_TOOLCHAIN_FILE is empty; skipping automatic vcpkg activation (system package mode)")
17+
elseif(EXISTS "${_the_vcpkg_root}")
1318
set(CMAKE_TOOLCHAIN_FILE "${_the_vcpkg_root}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "Vcpkg toolchain file")
1419
set(_vcpkg_prefix_roots)
1520
if(WIN32)

include/cache/grpc_remote_cache_peer.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,12 @@ class GrpcRemoteCachePeer final : public IRemoteCachePeer {
8080
/// RPC deadline in milliseconds (default: 1 000 ms).
8181
int rpc_timeout_ms = 1000;
8282

83-
/// TLS: set to true and provide CA cert path to use SSL credentials.
84-
/// When false, insecure channel credentials are used (not recommended
85-
/// for production).
83+
/// TLS is required for production. Insecure transport is only allowed
84+
/// when a human explicitly opts into a local/test override.
8685
bool tls_enabled = false;
86+
/// Explicit local/dev-only insecure override. Must remain false in
87+
/// production and is rejected by default.
88+
bool allow_insecure = false;
8789
std::string tls_ca_cert; ///< PEM-encoded CA certificate (in-memory)
8890

8991
Config() = default;
@@ -101,9 +103,11 @@ class GrpcRemoteCachePeer final : public IRemoteCachePeer {
101103
explicit GrpcRemoteCachePeer(Config config);
102104

103105
/**
104-
* @brief Convenience constructor: insecure peer at the given address.
106+
* @brief Convenience constructor for a configured peer address.
105107
*
106-
* Equivalent to GrpcRemoteCachePeer(Config(addr)).
108+
* This does not opt into insecure transport; production callers must set
109+
* `tls_enabled=true` or provide an explicit local/test override via
110+
* `Config::allow_insecure`.
107111
*/
108112
explicit GrpcRemoteCachePeer(const std::string& addr);
109113

@@ -178,6 +182,7 @@ class GrpcRemoteCachePeer final : public IRemoteCachePeer {
178182
std::string address;
179183
int rpc_timeout_ms = 1000;
180184
bool tls_enabled = false;
185+
bool allow_insecure = false;
181186
std::string tls_ca_cert;
182187

183188
Config() = default;

include/security/access_control_manager.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,22 @@ struct AccessDecision {
6262
}
6363
};
6464

65+
/// Authorization exception policy. The secure default is fail-closed; explicit
66+
/// fail-open requires a clear justification and is intended only for documented
67+
/// maintenance / local override scenarios.
68+
enum class AuthorizationFailureMode {
69+
DenyOnError, // Default secure behavior: deny access on auth failures.
70+
AllowOnErrorExplicit // Explicit fail-open override: requires an override reason.
71+
};
72+
6573
/// Access control policy configuration
6674
struct AccessControlConfig {
6775
std::string rbac_config_path; // Path to RBAC configuration
6876
std::string user_role_store_path; // Path to user-role mappings
6977
bool enable_audit_logging = true; // Enable access control audit logs
70-
bool fail_closed = true; // Deny access on errors (fail-safe)
78+
bool fail_closed = true; // Legacy compatibility flag; prefer failure_mode.
79+
AuthorizationFailureMode failure_mode = AuthorizationFailureMode::DenyOnError;
80+
std::string fail_open_reason; // Required when failure_mode is AllowOnErrorExplicit.
7181
bool enable_resource_wildcards = true; // Allow wildcards in resources
7282

7383
// ABAC configuration
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#pragma once
2+
3+
#include <chrono>
4+
#include <map>
5+
#include <string>
6+
#include <unordered_map>
7+
#include <vector>
8+
9+
namespace themis::sharding {
10+
11+
class GlobalSecondaryIndexManager {
12+
public:
13+
struct IndexEntry {
14+
std::string index_name;
15+
std::string field_name;
16+
std::string value;
17+
std::string shard_id;
18+
std::string primary_key;
19+
std::chrono::system_clock::time_point updated_at;
20+
};
21+
22+
struct Config {
23+
bool asynchronous_updates = true;
24+
bool eventual_consistency = true;
25+
std::chrono::milliseconds staleness_budget{5000};
26+
};
27+
28+
GlobalSecondaryIndexManager();
29+
explicit GlobalSecondaryIndexManager(const Config& config);
30+
31+
void createIndex(const std::string& index_name, const std::string& field_name);
32+
bool hasIndex(const std::string& index_name) const;
33+
34+
void upsert(const std::string& index_name, const std::string& field_name,
35+
const std::string& shard_id, const std::string& primary_key,
36+
const std::string& value);
37+
void erase(const std::string& index_name, const std::string& shard_id, const std::string& primary_key);
38+
void eraseShard(const std::string& index_name, const std::string& shard_id);
39+
40+
std::vector<IndexEntry> queryEquals(const std::string& index_name, const std::string& value) const;
41+
std::vector<IndexEntry> queryRange(const std::string& index_name,
42+
const std::string& lower_bound,
43+
const std::string& upper_bound) const;
44+
45+
size_t size() const;
46+
47+
private:
48+
struct IndexDefinition {
49+
std::string name;
50+
std::string field_name;
51+
};
52+
53+
Config config_;
54+
std::map<std::string, IndexDefinition> indexes_;
55+
std::map<std::string, std::map<std::string, std::vector<IndexEntry>>> entries_;
56+
};
57+
58+
} // namespace themis::sharding

include/sharding/shard_rpc_client.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class ShardRPCClient {
9393

9494
// mTLS Configuration (optional, required for production)
9595
bool enable_mtls = true; // Enable mutual TLS authentication (default: on)
96+
bool allow_insecure = false; // Explicit local/test-only override; rejected by default
9697
std::string tls_cert_path; // Path to client certificate (PEM format)
9798
std::string tls_key_path; // Path to client private key (PEM format)
9899
std::string tls_ca_cert_path; // Path to CA certificate for server verification (PEM format)

include/transaction/grpc_rpc_adapter.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,9 @@ namespace themis::transaction {
5656
/**
5757
* @brief Mutual-TLS credential bundle for gRPC channel creation.
5858
*
59-
* When all three PEM fields are non-empty the adapters will create a channel
60-
* backed by `grpc::SslCredentials`; if any field is empty (or the struct is
61-
* absent) the adapters fall back to `InsecureChannelCredentials()` and emit a
62-
* `spdlog::warn` so the fallback is always visible in logs.
59+
* This path is fail-closed: the adapter will only create a secure gRPC channel
60+
* when all three PEM fields are present and valid. Missing material is rejected
61+
* unless `allow_insecure` is explicitly set for a local test-only override.
6362
*
6463
* @note For production deployments populate from files or a secret manager —
6564
* never hard-code PEM material in source code.
@@ -79,6 +78,13 @@ struct MtlsConfig {
7978
* match the dial address (e.g. `"localhost"` vs `"127.0.0.1"`).
8079
*/
8180
std::string target_name_override;
81+
/**
82+
* @brief Allow the explicit development/test-only insecure fallback.
83+
*
84+
* This must remain false in production. The distributed transaction path
85+
* treats any other usage as a hard error to avoid silent trust degradation.
86+
*/
87+
bool allow_insecure = false;
8288
};
8389

8490
// ─────────────────────────────────────────────────────────────────────────────
@@ -109,9 +115,9 @@ class GrpcRpcPhase1Adapter {
109115
* @param timeout gRPC deadline applied to every PREPARE call.
110116
* @param mtls Optional mTLS credential bundle. When present and
111117
* all three PEM fields are non-empty, the channel is
112-
* created with `grpc::SslCredentials`. Otherwise
113-
* `InsecureChannelCredentials()` is used and a
114-
* warning is logged.
118+
* created with `grpc::SslCredentials`. Missing PEM
119+
* material is rejected unless `allow_insecure` is
120+
* explicitly set for a local test override.
115121
* @return Callable compatible with
116122
* `DistributedTransactionManager::RpcPhase1Fn`.
117123
*/

include/utils/grpc_channel_pool.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class GrpcChannelPool {
6161
std::chrono::seconds keepalive_time{30}; ///< Keepalive time
6262
std::chrono::seconds keepalive_timeout{10}; ///< Keepalive timeout
6363
int max_concurrent_streams = 100; ///< Max concurrent streams per channel
64+
bool allow_insecure = false; ///< Explicit local/test-only fallback; false by default
6465
};
6566

6667
GrpcChannelPool();
@@ -86,7 +87,8 @@ class GrpcChannelPool {
8687
* - Caller should implement retry logic or fallback strategy
8788
*
8889
* @param target Target address (e.g., "localhost:50051")
89-
* @param credentials Channel credentials (optional, uses insecure if nullptr)
90+
* @param credentials Channel credentials. A null pointer is rejected by default;
91+
* set Config::allow_insecure=true for an explicit local/test override.
9092
* @return Shared pointer to gRPC channel, or nullptr if acquisition failed
9193
*
9294
* @error_contract

src/auth/distributed_token_blacklist.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,16 +336,16 @@ DistributedTokenBlacklist::DistributedTokenBlacklist(
336336
config_.column_family, rocksdb::ColumnFamilyOptions{}));
337337

338338
std::vector<rocksdb::ColumnFamilyHandle*> cf_handles;
339-
std::unique_ptr<rocksdb::DB> db_instance;
339+
rocksdb::DB* db_raw = nullptr;
340340
rocksdb::Status status = rocksdb::DB::Open(
341-
rocksdb::DBOptions{opts}, config_.db_path, cf_descriptors, &cf_handles, &db_instance);
341+
rocksdb::DBOptions{opts}, config_.db_path, cf_descriptors, &cf_handles, &db_raw);
342342

343343
if (!status.ok()) {
344344
throw std::runtime_error(
345345
std::string("Cannot open RocksDB: ") + status.ToString());
346346
}
347347

348-
db_ = std::move(db_instance);
348+
db_ = std::unique_ptr<rocksdb::DB>(db_raw);
349349
cf_ = cf_handles[1]; // Our column family (not default)
350350

351351
// Keep other CF handles alive for proper cleanup

0 commit comments

Comments
 (0)