#ifndef STOP_REGISTER_HPP #define STOP_REGISTER_HPP #include #include #include "basic_defs.h" #include "data.h" #include "storage/bpt.hpp" #include "storage/buffer_pool_manager.h" #include "storage/driver.h" struct stop_register_t { hash_t station_ID_hash; hash_t train_ID_hash; uint16_t type : 1; uint16_t startTime : 12; uint8_t stop_id; }; inline bool operator<(const stop_register_t &A, const stop_register_t &B) { if (A.station_ID_hash != B.station_ID_hash) return A.station_ID_hash < B.station_ID_hash; if (A.train_ID_hash != B.train_ID_hash) return A.train_ID_hash < B.train_ID_hash; if (A.type != B.type) return A.type < B.type; return A.startTime < B.startTime; } struct MinimalTrainRecord { uint16_t saleDate_beg : 8, saleDate_end : 8, vis_time_offset : 14; }; static_assert(sizeof(MinimalTrainRecord) == sizeof(default_numeric_index_t)); class StopRegister : public DataDriverBase { std::string bpt_file_identifier; std::string bpt_file_path; DiskManager *bpt_disk_manager; BufferPoolManager *bpt_bpm; BPlusTreeIndexer> *bpt_indexer; public: struct DirectTrainInfo { hash_t train_ID_hash; int actual_start_date; int leave_time_stamp; int arrive_time_stamp; int from_stop_id; int to_stop_id; int saleDate_beg; }; // for satety, all the copy/move operations are deleted, please manage it using pointer StopRegister &operator=(const StopRegister &) = delete; StopRegister(const StopRegister &) = delete; StopRegister &operator=(StopRegister &&) = delete; StopRegister(StopRegister &&) = delete; inline StopRegister(std::string bpt_file_identifier_, std::string bpt_file_path_) : bpt_file_identifier(std::move(bpt_file_identifier_)), bpt_file_path(std::move(bpt_file_path_)) { bpt_disk_manager = new DiskManager(bpt_file_path); bpt_bpm = new BufferPoolManager(100, 5, bpt_disk_manager); bpt_indexer = new BPlusTreeIndexer>(bpt_bpm); } inline ~StopRegister() { delete bpt_indexer; delete bpt_bpm; delete bpt_disk_manager; } inline virtual sjtu::vector ListFiles() override { sjtu::vector res; res.push_back({bpt_file_identifier, bpt_file_path, bpt_disk_manager}); return res; } inline virtual void LockDownForCheckOut() override { delete bpt_indexer; delete bpt_bpm; delete bpt_disk_manager; bpt_indexer = nullptr; bpt_bpm = nullptr; bpt_disk_manager = nullptr; } inline virtual void Flush() override { if (bpt_indexer == nullptr) return; bpt_indexer->Flush(); } inline void AddStopInfo(hash_t station_hash, hash_t train_hash, uint16_t true_saleDate_beg, uint16_t true_saleDate_end, uint16_t startTime, uint16_t arrive_time_offset, uint16_t leave_time_offset, uint8_t stop_id) { LOG->debug( "AddStopInfo: station_hash {} train_hash {} true_saleDate_beg {} true_saleDate_end {} startTime {} " "arrive_time_offset {} leave_time_offset {} stop_id {}", station_hash, train_hash, true_saleDate_beg, true_saleDate_end, startTime, arrive_time_offset, leave_time_offset, stop_id); MinimalTrainRecord record_arrive, record_leave; const static int June_1st_2024 = 152; record_arrive.saleDate_beg = true_saleDate_beg - June_1st_2024; record_arrive.saleDate_end = true_saleDate_end - June_1st_2024; record_arrive.vis_time_offset = arrive_time_offset; record_leave.saleDate_beg = true_saleDate_beg - June_1st_2024; record_leave.saleDate_end = true_saleDate_end - June_1st_2024; record_leave.vis_time_offset = leave_time_offset; if (arrive_time_offset != uint16_t(-1)) bpt_indexer->Put({station_hash, train_hash, 0, startTime, stop_id}, *reinterpret_cast(&record_arrive)); if (leave_time_offset != uint16_t(-1)) bpt_indexer->Put({station_hash, train_hash, 1, startTime, stop_id}, *reinterpret_cast(&record_leave)); } inline void QueryDirectTrains(uint32_t date, hash_t from_station_ID, hash_t to_station_ID, std::vector &res) { const static int June_1st_2024 = 152; auto it_from = bpt_indexer->lower_bound_const({from_station_ID, 0}); auto it_to = bpt_indexer->lower_bound_const({to_station_ID, 0}); while (it_from != bpt_indexer->end_const()) { const auto &key_from = it_from.GetKey(); const auto &value_from = it_from.GetValue(); LOG->debug("it_from now tries to check station_id_hash {} train_id_hash {} stop_id {}", key_from.station_ID_hash, key_from.train_ID_hash, key_from.stop_id); if (key_from.station_ID_hash != from_station_ID) break; if (key_from.type != 1) { ++it_from; continue; } LOG->debug("it_from now checks station_id_hash {} train_id_hash {} stop_id {}", key_from.station_ID_hash, key_from.train_ID_hash, key_from.stop_id); int true_saleDate_beg = (*reinterpret_cast(&value_from)).saleDate_beg + June_1st_2024; int true_saleDate_end = (*reinterpret_cast(&value_from)).saleDate_end + June_1st_2024; int leave_time_offset = (*reinterpret_cast(&value_from)).vis_time_offset; int startTime = key_from.startTime; int actual_time = startTime + leave_time_offset; int delta_days = actual_time / 1440; if (date - delta_days < true_saleDate_beg || date - delta_days > true_saleDate_end) { ++it_from; continue; } StopRegister::DirectTrainInfo entry; entry.train_ID_hash = key_from.train_ID_hash; entry.actual_start_date = date - delta_days; entry.leave_time_stamp = entry.actual_start_date * 1440 + actual_time; entry.from_stop_id = key_from.stop_id; entry.saleDate_beg = true_saleDate_beg; while (it_to != bpt_indexer->end_const()) { const auto &key_to = it_to.GetKey(); const auto &value_to = it_to.GetValue(); if (key_to.station_ID_hash != to_station_ID) break; if (key_to.type != 0) { ++it_to; continue; } LOG->debug("it_to now checks station_id_hash {} train_id_hash {} stop_id {}", key_to.station_ID_hash, key_to.train_ID_hash, key_to.stop_id); if (key_to.train_ID_hash > key_from.train_ID_hash) break; if (key_to.train_ID_hash == key_from.train_ID_hash) { entry.arrive_time_stamp = entry.actual_start_date * 1440 + startTime + (*reinterpret_cast(&value_to)).vis_time_offset; entry.to_stop_id = key_to.stop_id; res.push_back(entry); ++it_to; break; } ++it_to; } ++it_from; } } }; #endif