11#include " AtomDBProxy.h"
22
3+ #include < numeric>
4+
35#include " AtomDBSingleton.h"
46#include " BaseProxy.h"
57#include " Link.h"
@@ -17,22 +19,41 @@ using namespace commons;
1719
1820// -------------------------------------------------------------------------------------------------
1921// Static constants
22+ queue<vector<Atom*>> ready_batches;
2023
21- const size_t AtomDBProxy::BATCH_SIZE = 5000 ;
24+ const size_t AtomDBProxy::BATCH_SIZE = 100000 ;
25+ const size_t AtomDBProxy::NUM_THREADS = 10 ;
2226
2327// Proxy Commands
2428string AtomDBProxy::ADD_ATOMS = " add_atoms" ;
29+ string AtomDBProxy::FLUSH_ATOMS = " flush_atoms" ;
2530
2631// -------------------------------------------------------------------------------------------------
2732// Constructor and destructor
2833
2934AtomDBProxy::AtomDBProxy () : BaseProxy() {
3035 this ->command = ServiceBus::ATOMDB;
3136 this ->atomdb = AtomDBSingleton::get_instance ();
37+
38+ for (int i = 0 ; i < NUM_THREADS; ++i) {
39+ this ->workers .emplace_back (&AtomDBProxy::worker_loop, this );
40+ }
3241}
3342
3443AtomDBProxy::~AtomDBProxy () {
3544 LOG_INFO (" Shutdown AtomDBProxy..." );
45+ flush_atoms ();
46+ {
47+ unique_lock<mutex> lock (this ->queue_mutex );
48+ this ->stop_processing = true ;
49+ }
50+ this ->queue_condition .notify_all ();
51+
52+ for (thread& worker : this ->workers ) {
53+ if (worker.joinable ()) {
54+ worker.join ();
55+ }
56+ }
3657 this ->abort ();
3758}
3859
@@ -85,41 +106,15 @@ bool AtomDBProxy::from_remote_peer(const string& command, const vector<string>&
85106 } else if (command == AtomDBProxy::ADD_ATOMS) {
86107 handle_add_atoms (args);
87108 return true ;
109+ } else if (command == AtomDBProxy::FLUSH_ATOMS) {
110+ flush_atoms ();
111+ return true ;
88112 } else {
89113 Utils::error (" Invalid AtomDBProxy command: <" + command + " >" );
90114 return false ;
91115 }
92116}
93117
94- void AtomDBProxy::handle_add_atoms (const vector<string>& tokens) {
95- vector<Atom*> atoms;
96- try {
97- atoms = build_atoms_from_tokens (tokens);
98- LOG_INFO (" Processing " << atoms.size () << " atoms..." );
99-
100- if (atoms.empty ()) {
101- LOG_INFO (" No atoms were built from tokens. Nothing to process." );
102- return ;
103- }
104-
105- this ->atomdb ->add_atoms (atoms, false , true );
106-
107- LOG_DEBUG (" Cleaning up " << atoms.size () << " atom pointers after successful processing." );
108- for (Atom* atom : atoms) {
109- delete atom;
110- }
111- atoms.clear ();
112-
113- LOG_INFO (" Finished processing all atoms." );
114-
115- } catch (const exception& e) {
116- LOG_ERROR (" Error processing atoms: " << e.what ());
117- for (Atom* atom : atoms) {
118- delete atom;
119- }
120- }
121- }
122-
123118vector<Atom*> AtomDBProxy::build_atoms_from_tokens (const vector<string>& tokens) {
124119 vector<Atom*> atoms;
125120 string current;
@@ -148,3 +143,117 @@ vector<Atom*> AtomDBProxy::build_atoms_from_tokens(const vector<string>& tokens)
148143
149144 return atoms;
150145}
146+
147+ // void AtomDBProxy::handle_add_atoms(const vector<string>& tokens) {
148+ // vector<Atom*> atoms;
149+ // try {
150+ // atoms = build_atoms_from_tokens(tokens);
151+ // LOG_INFO("Processing " << atoms.size() << " atoms...");
152+
153+ // if (atoms.empty()) {
154+ // LOG_INFO("No atoms were built from tokens. Nothing to process.");
155+ // return;
156+ // }
157+
158+ // this->atomdb->add_atoms(atoms, false, true);
159+
160+ // LOG_DEBUG("Cleaning up " << atoms.size() << " atom pointers after successful processing.");
161+ // for (Atom* atom : atoms) {
162+ // delete atom;
163+ // }
164+ // atoms.clear();
165+
166+ // LOG_INFO("Finished processing all atoms.");
167+
168+ // } catch (const exception& e) {
169+ // LOG_ERROR("Error processing atoms: " << e.what());
170+ // for (Atom* atom : atoms) {
171+ // delete atom;
172+ // }
173+ // }
174+ // }
175+
176+ void AtomDBProxy::handle_add_atoms (const vector<string>& tokens) {
177+ vector<Atom*> atoms = build_atoms_from_tokens (tokens);
178+ LOG_INFO (" Received " << atoms.size () << " atoms from peer " << this ->peer_id ());
179+ add_work (move (atoms));
180+ }
181+
182+ void AtomDBProxy::flush_atoms () {
183+ unique_lock<mutex> lock (this ->queue_mutex );
184+
185+ if (this ->work_queue .empty ()) {
186+ LOG_INFO (" [Flush] Received flush command, but accumulator is empty. Nothing to do." );
187+ return ;
188+ }
189+
190+ LOG_INFO (" [Flush] Received flush command. Flushing " << this ->work_queue .size ()
191+ << " remaining batches from accumulator." );
192+
193+ size_t total_remaining = accumulate (
194+ this ->work_queue .begin (), this ->work_queue .end (), size_t {0 }, [](size_t sum, const auto & batch) {
195+ return sum + batch.size ();
196+ });
197+
198+ vector<Atom*> final_batch;
199+ final_batch.reserve (total_remaining);
200+ for (auto & batch : this ->work_queue ) {
201+ final_batch.insert (
202+ final_batch.end (), make_move_iterator (batch.begin ()), make_move_iterator (batch.end ()));
203+ }
204+
205+ this ->work_queue .clear ();
206+ ready_batches.push (move (final_batch));
207+
208+ this ->queue_condition .notify_one ();
209+ }
210+
211+ void AtomDBProxy::add_work (vector<Atom*> atoms) {
212+ if (atoms.empty ()) return ;
213+ unique_lock<mutex> lock (this ->queue_mutex );
214+ this ->work_queue .push_back (move (atoms));
215+
216+ size_t total_in_queue = accumulate (
217+ this ->work_queue .begin (), this ->work_queue .end (), size_t {0 }, [](size_t sum, const auto & batch) {
218+ return sum + batch.size ();
219+ });
220+
221+ if (total_in_queue < BATCH_SIZE) return ;
222+
223+ LOG_DEBUG (" [Accumulator] Batch target reached. Total: " << total_in_queue
224+ << " . Creating super-batch." );
225+
226+ vector<Atom*> final_batch;
227+ final_batch.reserve (total_in_queue);
228+
229+ for (auto & batch : this ->work_queue ) {
230+ final_batch.insert (
231+ final_batch.end (), make_move_iterator (batch.begin ()), make_move_iterator (batch.end ()));
232+ }
233+
234+ this ->work_queue .clear ();
235+ ready_batches.push (move (final_batch));
236+ this ->queue_condition .notify_one ();
237+ }
238+
239+ void AtomDBProxy::worker_loop () {
240+ while (true ) {
241+ vector<Atom*> batch_to_process;
242+ {
243+ unique_lock<mutex> lock (this ->queue_mutex );
244+ this ->queue_condition .wait (
245+ lock, [this ] { return this ->stop_processing || !ready_batches.empty (); });
246+ if (this ->stop_processing && ready_batches.empty ()) return ;
247+ batch_to_process = move (ready_batches.front ());
248+ ready_batches.pop ();
249+ }
250+ LOG_INFO (" [Thread " << this_thread::get_id () << " ] Processing batch with "
251+ << batch_to_process.size () << " atoms." );
252+ try {
253+ this ->atomdb ->add_atoms (batch_to_process, false , true );
254+ LOG_INFO (" [Thread " << this_thread::get_id () << " ] batch processed successfully." );
255+ } catch (const exception& e) {
256+ LOG_ERROR (" Error processing batch: " << e.what ());
257+ }
258+ }
259+ }
0 commit comments