diff --git a/Makefile b/Makefile index 452a652..c605a84 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,7 @@ $(TARGET): $(OBJECTS) $(TJS_OBJECTS) build @mkdir -p $(@D) $(CXX) $(CXXFLAGS) $(INCLUDE) $(LDFLAGS) -o $(APP_DIR)/$(TARGETNAME) src/$(TARGET) $(OBJECTS) $(TJS_OBJECTS) $(CXX) $(CXXFLAGS) $(INCLUDE) $(LDFLAGS) -o $(APP_DIR)/test_client src/test_client.cpp + $(CXX) $(CXXFLAGS) $(INCLUDE) $(LDFLAGS) -o $(APP_DIR)/db_stats src/db_stats.cpp .PHONY: all build clean diff --git a/include/network.hpp b/include/network.hpp index fac2f9a..73ac0ee 100644 --- a/include/network.hpp +++ b/include/network.hpp @@ -7,7 +7,8 @@ enum class db_op : uint32_t { version = 0, read = 1, write = 2, - remove = 3 + remove = 3, + stats = 4 }; struct [[gnu::packed]] received_data { @@ -21,4 +22,13 @@ struct [[gnu::packed]] sending_data { bitops::regulated rep_id = 0; record_identifier identifier = record_identifier{}; db_page page = {0}; +}; + +struct [[gnu::packed]] stats_data { + bitops::regulated free; + bitops::regulated free_deleted; + bitops::regulated total_pages; + bitops::regulated total_records; + bitops::regulated total_delete; + bitops::regulated cow_full; }; \ No newline at end of file diff --git a/src/db_stats.cpp b/src/db_stats.cpp new file mode 100644 index 0000000..b3ad6e4 --- /dev/null +++ b/src/db_stats.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include +#include "database.hpp" +#include "network.hpp" +#include +#include +#include +#include +#include +#include +#include +#include "commander.hpp" + + +int main(int argc, char** argv) +{ + try{ + while(argc == 3) + { + std::stringstream ip_stream{argv[1]}; + std::array ip; + std::string token; + std::getline(ip_stream, token, '.'); + ip[0] = std::stoi(token); + std::getline(ip_stream, token, '.'); + ip[1] = std::stoi(token); + std::getline(ip_stream, token, '.'); + ip[2] = std::stoi(token); + std::getline(ip_stream, token, '.'); + ip[3] = std::stoi(token); + + uint16_t port = std::stoi(argv[2]); + + + auto soc = socket(AF_INET, SOCK_DGRAM, 0); + struct sockaddr_in server; + server.sin_family = AF_INET; + server.sin_addr.s_addr = *(in_addr_t*)ip.data(); + server.sin_port = htons(port); + + connect(soc, (struct sockaddr*)&server, sizeof(server)); + + + sending_data reply; + received_data request; + + request.op = db_op::stats; + + send(soc, (void*)&request, (socklen_t)sizeof(request), 0); + recv(soc, (void*)&reply, (socklen_t)sizeof(reply), 0); + + auto stats = (stats_data*)&reply.page; + + std::cout << "free_pages\t" << stats->free << std::endl; + std::cout << "deleted_pages\t" << stats->free_deleted << std::endl; + std::cout << "total_pages\t" << stats->total_pages << std::endl; + std::cout << "total_records\t" << stats->total_records << std::endl; + std::cout << "delete_cache\t" << stats->total_delete << std::endl; + std::cout << "inaccessible\t" << stats->cow_full << std::endl; + + return 0; + } + }catch(...) {} + std::cerr << "Invalid command, expects ``db_stats IPV4 PORT''" << std::endl; + return 1; +} \ No newline at end of file diff --git a/src/izaro-storage.cpp b/src/izaro-storage.cpp index 89ad791..8f83d74 100644 --- a/src/izaro-storage.cpp +++ b/src/izaro-storage.cpp @@ -65,6 +65,20 @@ int main( } + 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 { database db(database::create(utest_str, utest_size*2)); @@ -163,7 +177,7 @@ int main( auto soc = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in addr; addr.sin_family = AF_INET; - addr.sin_port = htons(20450); + addr.sin_port = htons(db_port); memset((void*)&addr.sin_addr, 0, sizeof(addr.sin_addr)); bind(soc,(struct sockaddr*)&addr,sizeof(addr)); @@ -227,6 +241,29 @@ int main( 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; default: std::cerr << "bad_request " << (uint32_t)static_cast(recv.op) << std::endl; continue; diff --git a/src/test_client.cpp b/src/test_client.cpp index 8b54f66..c45bd8f 100644 --- a/src/test_client.cpp +++ b/src/test_client.cpp @@ -2,9 +2,14 @@ #include #include #include +#include int main(int, char** argv) { { + std::random_device hrng{}; + + std::minstd_rand srng{hrng()}; + auto soc = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in server; server.sin_family = AF_INET; @@ -32,7 +37,7 @@ int main(int, char** argv) { for(size_t idx=0;idx