| 
				
				
					
						
					
				
				
				 | 
			
			 | 
			
			@ -12,17 +12,77 @@ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#include <sys/socket.h>
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#include <netinet/in.h>
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#include <string.h>
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#include <atomic>
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#include <thread>
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#include <stdio.h>
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#include "commander.hpp"
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			constexpr auto record_sync_freq = std::chrono::microseconds(500000); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			std::atomic<std::chrono::microseconds> last_cycle_ts; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			std::atomic<std::chrono::microseconds> last_cycle_durr; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			std::atomic<std::chrono::microseconds> max_cycle_durr; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			std::atomic<std::chrono::microseconds> avg_cycle_durr; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			std::atomic<bool> will_stop{false}; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void sync_records_thread(const database& db) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				std::chrono::microseconds total{0}; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				uint16_t count = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				do{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					auto begin = std::chrono::high_resolution_clock::now(); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					fdatasync(db.records.fd_v()); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					auto durr = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - begin); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					total += durr; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					count++; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					auto avg = total/count; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					if(count>20) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						total -= avg; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						count--; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					avg_cycle_durr.store(avg); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					last_cycle_durr.store(durr); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					if(max_cycle_durr.load() < durr) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						max_cycle_durr.store(durr); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					if(durr<record_sync_freq) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						std::this_thread::sleep_for(record_sync_freq - durr); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				}while(!will_stop); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			enum class cleanup_type : size_t { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				normal = sizeof(received_data), | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				complete = sizeof(received_bulk_data) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			}; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			template<cleanup_type mode> | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void buffer_cleanup(received_bulk_data& recv_impl) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				constexpr size_t total = ((size_t)mode)/(((size_t)mode % 8 == 0) ? 8 : 4); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				for( | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					size_t i = 0;  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					i < total;  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					i++ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					if constexpr ((size_t)mode % 8 == 0) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						((uint64_t*)&recv_impl)[i] = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} else { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						((uint32_t*)&recv_impl)[i] = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			int main( | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				[[maybe_unused]] int argc,  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				[[maybe_unused]] char** argv | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				CMD::commander cmd_args(argc, argv); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				std::string database_str = "/data/"; | 
			
		
		
	
	
		
			
				| 
				
					
						
					
				
				
					
						
					
				
				
				 | 
			
			 | 
			
			@ -179,17 +239,20 @@ int main( | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					addr.sin_port = htons(db_port); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					memset((void*)&addr.sin_addr, 0, sizeof(addr.sin_addr)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					bind(soc,(struct sockaddr*)&addr,sizeof(addr)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					std::thread syncher(sync_records_thread, run_db); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					received_bulk_data recv_impl; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					buffer_cleanup<cleanup_type::complete>(recv_impl); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					do{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						received_data recv; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						received_data& recv = *(received_data*)&recv_impl; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						sending_data reply; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						sockaddr_in client; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						socklen_t packet_sz; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						size_t reply_size; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						recvfrom( | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							soc,  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							(void*)&recv,  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							sizeof(received_data),  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							(void*)&recv_impl,  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							sizeof(received_bulk_data),  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							MSG_WAITFORONE,  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							(struct sockaddr*)&client, | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							&packet_sz | 
			
		
		
	
	
		
			
				| 
				
				
				
					
						
					
				
				 | 
			
			 | 
			
			@ -203,6 +266,7 @@ int main( | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								reply.rep_id = recv.rep_id; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								reply.identifier.record_head.split.x = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								reply_size = sizeof(reply.rep_id) + sizeof(reply.identifier.record_head.split.x); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								buffer_cleanup<cleanup_type::normal>(recv_impl); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							case db_op::read: | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								{ | 
			
		
		
	
	
		
			
				| 
				
				
				
					
						
					
				
				 | 
			
			 | 
			
			@ -218,6 +282,7 @@ int main( | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										reply_size = sizeof(reply.rep_id) + sizeof(reply.identifier); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									buffer_cleanup<cleanup_type::normal>(recv_impl); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							case db_op::write: | 
			
		
		
	
	
		
			
				| 
				
				
				
					
						
					
				
				 | 
			
			 | 
			
			@ -230,6 +295,7 @@ int main( | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										std::cerr << "cluster overfull"<< std::endl; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									reply_size = sizeof(reply.rep_id) + sizeof(reply.identifier);  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									buffer_cleanup<cleanup_type::normal>(recv_impl); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							// case db_op::sremove:
 | 
			
		
		
	
	
		
			
				| 
				
				
				
					
						
					
				
				 | 
			
			 | 
			
			@ -239,6 +305,7 @@ int main( | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									run_db.remove(recv.identifier); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									reply.identifier.record_head.split = recv.identifier; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									reply_size = sizeof(reply.rep_id) + sizeof(reply.identifier);  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									buffer_cleanup<cleanup_type::normal>(recv_impl); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							case db_op::stats: | 
			
		
		
	
	
		
			
				| 
				
				
				
					
						
					
				
				 | 
			
			 | 
			
			@ -253,15 +320,25 @@ int main( | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										+ (*run_db.metadata).page_cnt  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										- (*run_db.metadata).last_page; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									uint64_t cow_full = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									uint64_t usable_records = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									for(auto& elem : run_db.records) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										if(elem.second.timestamp == std::numeric_limits<uint64_t>::max()) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										if (elem.second.timestamp == std::numeric_limits<uint64_t>::max()) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
											++cow_full; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
											++usable_records; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										} else if(elem.second.timestamp == 0) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
											++usable_records; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									stats->cow_full = cow_full; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									stats->free_records = usable_records; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									stats->sync_rate_µs = record_sync_freq.count(); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									stats->sync_duration_µs = last_cycle_durr.load().count(); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									stats->max_sync_duration_µs = max_cycle_durr.load().count(); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									stats->avg_sync_duration_µs = avg_cycle_durr.load().count(); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									reply_size = sizeof(reply); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									buffer_cleanup<cleanup_type::normal>(recv_impl); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							case db_op::sallocate: | 
			
		
		
	
	
		
			
				| 
				
				
				
					
						
					
				
				 | 
			
			 | 
			
			@ -269,6 +346,7 @@ int main( | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									reply.rep_id = recv.rep_id; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									reply.identifier = run_db.try_allocate(recv.identifier); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									reply_size = sizeof(reply.rep_id) + sizeof(reply.identifier); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									buffer_cleanup<cleanup_type::normal>(recv_impl); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							case db_op::sread: | 
			
		
		
	
	
		
			
				| 
				
				
				
					
						
					
				
				 | 
			
			 | 
			
			@ -285,6 +363,7 @@ int main( | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									{ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										reply_size = sizeof(reply.rep_id) + sizeof(reply.identifier); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									buffer_cleanup<cleanup_type::normal>(recv_impl); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							case db_op::swrite: | 
			
		
		
	
	
		
			
				| 
				
				
				
					
						
					
				
				 | 
			
			 | 
			
			@ -297,6 +376,7 @@ int main( | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										std::cerr << "cluster overfull"<< std::endl; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									reply_size = sizeof(reply.rep_id) + sizeof(reply.identifier);  | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									buffer_cleanup<cleanup_type::normal>(recv_impl); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							case db_op::confirm: | 
			
		
		
	
	
		
			
				| 
				
				
				
					
						
					
				
				 | 
			
			 | 
			
			@ -304,6 +384,7 @@ int main( | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									reply.rep_id = recv.rep_id; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									run_db.confirm(recv.identifier, *(bitops::regulated<uint64_t>*)&recv.page); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									reply_size = sizeof(reply.rep_id); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									buffer_cleanup<cleanup_type::normal>(recv_impl); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							default: | 
			
		
		
	
	
		
			
				| 
				
					
						
					
				
				
				
				 | 
			
			 | 
			
			
 |