Skip to content

Commit 103e86e

Browse files
committed
Added pika_command_collector mechanism
1 parent fda56d8 commit 103e86e

23 files changed

+1825
-270
lines changed

conf/pika.conf

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,25 @@ replication-num : 0
153153
# The default value of consensus-level is 0, which means this feature is not enabled.
154154
consensus-level : 0
155155

156+
# Batch processing configuration (used by both command collection and consensus mechanism)
157+
# The maximum number of items in a batch (both command collection and consensus)
158+
# Default: 100
159+
batch-size : 100
160+
161+
# Batch processing configuration (used by both command collection and consensus mechanism)
162+
# The maximum waiting batch for (both command collection and consensus)
163+
# Default: 5
164+
batch-max-wait-time : 5
165+
166+
# The timeout in milliseconds for waiting for a batch ACK from a slave.
167+
# Default: 500
168+
replication-ack-timeout : 500
169+
170+
# Enable command batch processing for better performance
171+
# When enabled, write commands will be collected and processed in batches
172+
# Default: no
173+
command-batch-enabled : yes
174+
156175
# The Prefix of dump file's name.
157176
# All the files that generated by command "bgsave" will be name with this prefix.
158177
dump-prefix :

include/pika_binlog.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ class Binlog : public pstd::noncopyable {
6161
* Set Producer pro_num and pro_offset with lock
6262
*/
6363
pstd::Status SetProducerStatus(uint32_t pro_num, uint64_t pro_offset, uint32_t term = 0, uint64_t index = 0);
64+
65+
// Force sync data to disk
66+
pstd::Status Sync();
67+
6468
// Need to hold Lock();
6569
pstd::Status Truncate(uint32_t pro_num, uint64_t pro_offset, uint64_t index);
6670

include/pika_command_collector.h

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
// Copyright (c) 2015-present, Qihoo, Inc. All rights reserved.
2+
// This source code is licensed under the BSD-style license found in the
3+
// LICENSE file in the root directory of this source tree. An additional grant
4+
// of patent rights can be found in the PATENTS file in the same directory.
5+
6+
#ifndef PIKA_COMMAND_COLLECTOR_H_
7+
#define PIKA_COMMAND_COLLECTOR_H_
8+
9+
#include <atomic>
10+
#include <condition_variable>
11+
#include <deque>
12+
#include <functional>
13+
#include <list>
14+
#include <map>
15+
#include <memory>
16+
#include <mutex>
17+
#include <string>
18+
#include <thread>
19+
#include <unordered_map>
20+
#include <vector>
21+
#include <chrono>
22+
#include <optional>
23+
24+
#include "include/pika_command.h"
25+
#include "include/pika_define.h"
26+
#include "pstd/include/pstd_status.h"
27+
28+
#include "include/pika_consensus.h"
29+
30+
/**
31+
* @brief PikaCommandCollector is used to collect write commands and process them in batches
32+
*
33+
* Main functions:
34+
* 1. Collect write commands and process them in optimized batches after reaching the threshold
35+
* 2. Handle the conflict of the same key (the later command will overwrite the earlier command)
36+
* 3. Send commands in batches to the consensus coordinator with batch-level synchronization
37+
* 4. Support asynchronous callback notification of command processing results
38+
* 5. Track performance metrics for batch processing
39+
* 6. Provide intelligent retry mechanisms for failed batches
40+
*/
41+
class PikaCommandCollector {
42+
public:
43+
// Callback function type after command processing is completed
44+
using CommandCallback = std::function<void(const LogOffset& offset, pstd::Status status)>;
45+
46+
/**
47+
* @brief constructor
48+
* @param coordinator consensus coordinator reference
49+
* @param batch_size batch size (number of commands)
50+
* @param batch_max_wait_time forced flush interval (milliseconds)
51+
*/
52+
// Constructor with raw pointer (original)
53+
PikaCommandCollector(ConsensusCoordinator* coordinator, size_t batch_size = 100, int batch_max_wait_time = 5);
54+
55+
// Constructor with shared_ptr (for compatibility with make_shared calls)
56+
PikaCommandCollector(std::shared_ptr<ConsensusCoordinator> coordinator, size_t batch_size = 100, int batch_max_wait_time = 5);
57+
58+
~PikaCommandCollector();
59+
60+
/**
61+
* @brief Add command to collector
62+
* @param cmd_ptr command pointer
63+
* @param callback callback function after processing is completed
64+
* @return whether the addition was successful
65+
*/
66+
bool AddCommand(const std::shared_ptr<Cmd>& cmd_ptr, CommandCallback callback);
67+
68+
/**
69+
* @brief Called periodically by external systems to process batches
70+
* @param force Force processing even if batch is not full or timeout not reached
71+
* @return Number of commands processed
72+
*/
73+
74+
/**
75+
* @brief Immediately process all currently collected commands
76+
* @return The number of commands processed
77+
*/
78+
size_t FlushCommands(bool force = false);
79+
80+
81+
/**
82+
* @brief Get the current number of pending commands
83+
* @return number of commands
84+
*/
85+
size_t PendingCommands() const;
86+
87+
/**
88+
* @brief Set the batch size
89+
* @param batch_size batch size
90+
*/
91+
void SetBatchSize(size_t batch_size);
92+
93+
/**
94+
* @brief Set the batch max wait time
95+
* @param batch_max_wait_time maximum wait time in milliseconds
96+
*/
97+
void SetBatchMaxWaitTime(int batch_max_wait_time);
98+
99+
/**
100+
* @brief Get batch processing statistics
101+
* @return Pair of (total_processed_commands, total_batches)
102+
*/
103+
std::pair<uint64_t, uint64_t> GetBatchStats() const;
104+
105+
/**
106+
* @brief Get average batch processing time in milliseconds
107+
* @return Average processing time or nullopt if no batches processed
108+
*/
109+
std::optional<double> GetAverageBatchTime() const;
110+
111+
private:
112+
113+
/**
114+
* @brief batch processing command
115+
* @param batch command batch
116+
* @return Whether the processing is successful
117+
*/
118+
pstd::Status ProcessBatch(const std::vector<std::shared_ptr<Cmd>>& commands,
119+
const std::vector<CommandCallback>& callbacks);
120+
121+
/**
122+
* @brief Check for conflicts based on command type and key name
123+
* @param cmd_ptr command pointer
124+
* @return true if there is a conflict (should be replaced), false if there is no conflict
125+
*/
126+
bool CheckConflict(const std::shared_ptr<Cmd>& cmd_ptr) const;
127+
128+
/**
129+
* @brief Handle key conflicts and remove conflicting commands
130+
* @param cmd_ptr new command
131+
*/
132+
void HandleConflict(const std::shared_ptr<Cmd>& cmd_ptr);
133+
134+
/**
135+
* @brief Retry batch processing commands
136+
* @param commands List of commands to retry
137+
* @param callbacks Corresponding callback function list
138+
* @param priority Priority level for the retry (higher means more urgent)
139+
* @return Whether the commands were successfully requeued
140+
*/
141+
bool RetryBatch(const std::vector<std::shared_ptr<Cmd>>& commands,
142+
const std::vector<CommandCallback>& callbacks,
143+
int priority = 100);
144+
145+
private:
146+
//Consensus coordinator reference
147+
ConsensusCoordinator* coordinator_;
148+
149+
// Batch processing configuration
150+
std::atomic<size_t> batch_size_;
151+
std::atomic<int> batch_max_wait_time_;
152+
153+
// Retry configuration
154+
std::atomic<int> max_retry_attempts_{3};
155+
std::atomic<int> retry_backoff_ms_{50};
156+
157+
// Command collection and processing
158+
mutable std::mutex mutex_;
159+
160+
// Pending command queue and callbacks
161+
std::list<std::pair<std::shared_ptr<Cmd>, CommandCallback>> pending_commands_;
162+
163+
// Priority queue for retries
164+
std::deque<std::tuple<int, std::vector<std::shared_ptr<Cmd>>, std::vector<CommandCallback>>> retry_queue_;
165+
166+
// Command key mapping, used to handle same-key conflicts
167+
std::unordered_map<std::string, std::list<std::pair<std::shared_ptr<Cmd>, CommandCallback>>::iterator> key_map_;
168+
169+
// Batch statistics
170+
std::atomic<uint64_t> total_processed_{0};
171+
std::atomic<uint64_t> total_batches_{0};
172+
std::atomic<uint64_t> total_retries_{0};
173+
std::atomic<uint64_t> total_conflicts_{0};
174+
std::atomic<uint64_t> total_batch_time_ms_{0};
175+
std::chrono::time_point<std::chrono::steady_clock> batch_start_time_;
176+
177+
// Performance tracking
178+
struct BatchMetrics {
179+
uint64_t batch_size;
180+
uint64_t processing_time_ms;
181+
uint64_t wait_time_ms;
182+
bool successful;
183+
};
184+
185+
// Circular buffer for recent batch metrics
186+
static constexpr size_t kMetricsBufferSize = 100;
187+
std::vector<BatchMetrics> recent_metrics_;
188+
std::mutex metrics_mutex_;
189+
};
190+
191+
#endif // PIKA_COMMAND_COLLECTOR_H_

include/pika_conf.h

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,21 @@ class PikaConf : public pstd::BaseConf {
6969
std::shared_lock l(rwlock_);
7070
return sync_thread_num_;
7171
}
72+
73+
bool command_batch_enabled() {
74+
std::shared_lock l(rwlock_);
75+
return command_batch_enabled_;
76+
}
77+
78+
int batch_size() {
79+
std::shared_lock l(rwlock_);
80+
return batch_size_;
81+
}
82+
83+
int batch_max_wait_time() {
84+
std::shared_lock l(rwlock_);
85+
return batch_max_wait_time_;
86+
}
7287
int sync_binlog_thread_num() {
7388
std::shared_lock l(rwlock_);
7489
return sync_binlog_thread_num_;
@@ -350,6 +365,16 @@ class PikaConf : public pstd::BaseConf {
350365
int max_conn_rbuf_size() { return max_conn_rbuf_size_.load(); }
351366
int consensus_level() { return consensus_level_.load(); }
352367
int replication_num() { return replication_num_.load(); }
368+
int replication_ack_timeout() {
369+
std::shared_lock l(rwlock_);
370+
return replication_ack_timeout_;
371+
}
372+
373+
// Function to set replication acknowledgment timeout (used by batch system)
374+
void SetReplicationAckTimeout(int timeout) {
375+
std::lock_guard l(rwlock_);
376+
replication_ack_timeout_ = timeout;
377+
}
353378
int rate_limiter_mode() {
354379
std::shared_lock l(rwlock_);
355380
return rate_limiter_mode_;
@@ -436,7 +461,6 @@ class PikaConf : public pstd::BaseConf {
436461
bool is_admin_cmd(const std::string& cmd) {
437462
return admin_cmd_set_.find(cmd) != admin_cmd_set_.end();
438463
}
439-
440464
// Immutable config items, we don't use lock.
441465
bool daemonize() { return daemonize_; }
442466
bool rtc_cache_read_enabled() { return rtc_cache_read_enabled_; }
@@ -462,6 +486,23 @@ class PikaConf : public pstd::BaseConf {
462486
std::lock_guard l(rwlock_);
463487
thread_num_ = value;
464488
}
489+
490+
void SetCommandBatchEnabled(const bool value) {
491+
std::lock_guard l(rwlock_);
492+
TryPushDiffCommands("command-batch-enabled", value ? "yes" : "no");
493+
command_batch_enabled_ = value;
494+
}
495+
496+
void SetCommandBatchSize(const int value) {
497+
std::lock_guard l(rwlock_);
498+
TryPushDiffCommands("batch-size", std::to_string(value));
499+
batch_size_ = value;
500+
}
501+
void SetCommandBatchMaxWaitTime(const int value) {
502+
std::lock_guard l(rwlock_);
503+
TryPushDiffCommands("batch-max-wait-time", std::to_string(value));
504+
batch_max_wait_time_ = value;
505+
}
465506
void SetTimeout(const int value) {
466507
std::lock_guard l(rwlock_);
467508
TryPushDiffCommands("timeout", std::to_string(value));
@@ -665,6 +706,17 @@ class PikaConf : public pstd::BaseConf {
665706
TryPushDiffCommands("max-conn-rbuf-size", std::to_string(value));
666707
max_conn_rbuf_size_.store(value);
667708
}
709+
void SetConsensusBatchSize(const int value) {
710+
std::lock_guard l(rwlock_);
711+
TryPushDiffCommands("batch-size", std::to_string(value));
712+
batch_size_ = value;
713+
}
714+
// This method is used by config update system
715+
void UpdateReplicationAckTimeout(const int value) {
716+
std::lock_guard l(rwlock_);
717+
TryPushDiffCommands("replication-ack-timeout", std::to_string(value));
718+
replication_ack_timeout_ = value;
719+
}
668720
void SetMaxCacheFiles(const int& value) {
669721
std::lock_guard l(rwlock_);
670722
TryPushDiffCommands("max-cache-files", std::to_string(value));
@@ -929,6 +981,12 @@ class PikaConf : public pstd::BaseConf {
929981
std::string server_id_;
930982
std::string run_id_;
931983
std::string replication_id_;
984+
985+
// 命令批处理相关配置
986+
bool command_batch_enabled_ = true;
987+
int batch_size_ = 100;
988+
int batch_max_wait_time_ = 5;
989+
int replication_ack_timeout_ = 5000;
932990
std::string requirepass_;
933991
std::string masterauth_;
934992
std::string userpass_;
@@ -1047,7 +1105,7 @@ class PikaConf : public pstd::BaseConf {
10471105
int throttle_bytes_per_second_ = 200 << 20; // 200MB/s
10481106
int max_rsync_parallel_num_ = kMaxRsyncParallelNum;
10491107
std::atomic_int64_t rsync_timeout_ms_ = 1000;
1050-
1108+
10511109
/*
10521110
kUninitialized = 0, // unknown setting
10531111
kDisable = 1, // disable perf stats

0 commit comments

Comments
 (0)