#include #include #include #include #include #include #include "database.hpp" #include "network.hpp" #include #include #include #include #include #include #include #include "commander.hpp" int main( [[maybe_unused]] int argc, [[maybe_unused]] char** argv ) { CMD::commander cmd_args(argc, argv); std::string database_str = "/data/"; if(cmd_args.isFlagSet("-database")) { database_str = cmd_args.getFlagValue("-database"); } std::string utest_str = "/tmp/"; if(cmd_args.isFlagSet("-utest")) { utest_str = cmd_args.getFlagValue("-utest"); } size_t database_size = 4096; if(cmd_args.isFlagSet("-page-count")) { try{ database_size = std::stoll(cmd_args.getFlagValue("-page-count")); } catch (...) { std::cerr << "Invalid page-count value" << std::endl; return 1; } } size_t db_port = 20450; if(cmd_args.isFlagSet("-port")) { try{ db_port = std::stoi(cmd_args.getFlagValue("-port")); if(db_port>std::numeric_limits::max()) throw std::runtime_error("invalid_port"); } catch (...) { std::cerr << "Invalid port value" << std::endl; return 1; } } #ifdef UNITTEST size_t utest_size = 4096; if(cmd_args.isFlagSet("-utest-count")) { try{ utest_size = std::stoll(cmd_args.getFlagValue("-utest-count")); } catch (...) { std::cerr << "Invalid utest-count value" << std::endl; return 1; } } { database db(database::create(utest_str, utest_size*2)); db_page v; v.fill(1); record_identifier tar; auto begin = std::chrono::high_resolution_clock::now(); for(size_t idx=0;idx(std::chrono::high_resolution_clock::now() - begin)/utest_size; std::cerr << "durr/elem = " << durr.count() << "ns/op" << std::endl; auto a = db.read(tar); if(a.second[0] != 1) { std::cerr << "read failed" << std::endl; } db.remove(tar); a = db.read(tar); if(a.second[0] == 1) { std::cerr << "remove failed" << std::endl; } { db.write(tar, v); a = db.read(tar); if(a.second[0] != 1) { std::cerr << "read failed" << std::endl; } db.remove(tar); a = db.read(tar); if(a.second[0] != 0) { std::cerr << "remove failed" << std::endl; } v.fill(2); db.write(tar, v); } database reop(database::open(utest_str)); { a = reop.read(tar); if(a.second[0] != 2) { std::cerr << "reopen read failed" << std::endl; } v.fill(3); reop.write(tar, v); a = reop.read(tar); if(a.second[0] != 3) { std::cerr << "reopen write failed" << std::endl; } } reop.pages.clear(); reop.metadata.clear(); reop.records.clear(); reop.delete_table.clear(); db.pages.clear(); db.metadata.clear(); db.records.clear(); db.delete_table.clear(); } #endif if(cmd_args.isFlagSet("-create")) { try{ database creat(database::create(database_str, database_size)); std::cout << "Created" << std::endl; return 0; } catch (...) { std::cerr << "Creating of " << database_str << " of " << database_size << " pages failed" << std::endl; return 1; } } try{ database run_db(database::open(database_str)); auto soc = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(db_port); memset((void*)&addr.sin_addr, 0, sizeof(addr.sin_addr)); bind(soc,(struct sockaddr*)&addr,sizeof(addr)); do{ received_data recv; sending_data reply; sockaddr_in client; socklen_t packet_sz; size_t reply_size; recvfrom( soc, (void*)&recv, sizeof(received_data), MSG_WAITFORONE, (struct sockaddr*)&client, &packet_sz ); if(packet_sz < sizeof(db_op)) continue; switch (static_cast(recv.op)) { case db_op::version: 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); break; case db_op::read: { reply.rep_id = recv.rep_id; auto req = run_db.read(recv.identifier); if(req.first.timestamp != 0) { reply.identifier = req.first; reply.page = req.second; reply_size = sizeof(reply); } else { reply_size = sizeof(reply.rep_id) + sizeof(reply.identifier); } } break; case db_op::write: { reply.rep_id = recv.rep_id; try{ auto req = run_db.write(recv.identifier, recv.page); reply.identifier = req; } catch (...) { std::cerr << "cluster overfull"<< std::endl; } reply_size = sizeof(reply.rep_id) + sizeof(reply.identifier); } break; // case db_op::sremove: case db_op::remove: { reply.rep_id = recv.rep_id; run_db.remove(recv.identifier); reply.identifier.record_head.split = recv.identifier; reply_size = sizeof(reply.rep_id) + sizeof(reply.identifier); } break; case db_op::stats: { reply.rep_id = recv.rep_id; auto stats = (stats_data*)&reply.page; stats->total_pages = (*run_db.metadata).page_cnt; stats->total_records = (*run_db.metadata).record_cnt; stats->free_deleted = (*run_db.metadata).last_delete; stats->free = (*run_db.metadata).last_delete + (*run_db.metadata).page_cnt - (*run_db.metadata).last_page; uint64_t cow_full = 0; for(auto& elem : run_db.records) { if(elem.second.timestamp == std::numeric_limits::max()) { ++cow_full; } } stats->cow_full = cow_full; reply_size = sizeof(reply); } break; case db_op::sallocate: { reply.rep_id = recv.rep_id; reply.identifier = run_db.try_allocate(recv.identifier); reply_size = sizeof(reply.rep_id) + sizeof(reply.identifier); } break; case db_op::sread: { reply.rep_id = recv.rep_id; auto req = run_db.stepped_read(recv.identifier); if(req.first.timestamp != 0) { reply.identifier = req.first; reply.page = req.second; reply_size = sizeof(reply); } else { reply_size = sizeof(reply.rep_id) + sizeof(reply.identifier); } } break; case db_op::swrite: { reply.rep_id = recv.rep_id; try{ auto req = run_db.stepped_write(recv.identifier, recv.page); reply.identifier = req; } catch (...) { std::cerr << "cluster overfull"<< std::endl; } reply_size = sizeof(reply.rep_id) + sizeof(reply.identifier); } break; case db_op::confirm: { reply.rep_id = recv.rep_id; run_db.confirm(recv.identifier, *(bitops::regulated*)&recv.page); reply_size = sizeof(reply.rep_id); } break; default: std::cerr << "bad_request " << (uint32_t)static_cast(recv.op) << std::endl; continue; break; } sendto( soc, (void*)&reply, reply_size, 0, (struct sockaddr*)&client, (socklen_t)sizeof(client) ); //std::cerr << "reply to " << (uint32_t)static_cast(recv.op) << std::endl; }while(true); } catch (...) { std::cerr << "GoJDB crashed !" << std::endl; return 1; } }