fixed fatal bugs in query_ticket

This commit is contained in:
2024-05-24 00:11:19 +00:00
parent e15f3ccd1e
commit 0c4c6371a5
4 changed files with 89 additions and 10 deletions

View File

@ -12,6 +12,7 @@ struct stop_register_t {
hash_t train_ID_hash; hash_t train_ID_hash;
uint16_t type : 1; uint16_t type : 1;
uint16_t startTime : 12; uint16_t startTime : 12;
uint8_t stop_id;
}; };
inline bool operator<(const stop_register_t &A, const stop_register_t &B) { 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.station_ID_hash != B.station_ID_hash) return A.station_ID_hash < B.station_ID_hash;
@ -37,6 +38,9 @@ class StopRegister : public DataDriverBase {
int actual_start_date; int actual_start_date;
int leave_time_stamp; int leave_time_stamp;
int arrive_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 // for satety, all the copy/move operations are deleted, please manage it using pointer
StopRegister &operator=(const StopRegister &) = delete; StopRegister &operator=(const StopRegister &) = delete;
@ -73,7 +77,7 @@ class StopRegister : public DataDriverBase {
} }
inline void AddStopInfo(hash_t station_hash, hash_t train_hash, uint16_t true_saleDate_beg, 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 true_saleDate_end, uint16_t startTime, uint16_t arrive_time_offset,
uint16_t leave_time_offset) { uint16_t leave_time_offset, uint8_t stop_id) {
MinimalTrainRecord record_arrive, record_leave; MinimalTrainRecord record_arrive, record_leave;
const static int June_1st_2024 = 152; const static int June_1st_2024 = 152;
record_arrive.saleDate_beg = true_saleDate_beg - June_1st_2024; record_arrive.saleDate_beg = true_saleDate_beg - June_1st_2024;
@ -83,10 +87,10 @@ class StopRegister : public DataDriverBase {
record_leave.saleDate_end = true_saleDate_end - June_1st_2024; record_leave.saleDate_end = true_saleDate_end - June_1st_2024;
record_leave.vis_time_offset = leave_time_offset; record_leave.vis_time_offset = leave_time_offset;
if (arrive_time_offset != uint16_t(-1)) if (arrive_time_offset != uint16_t(-1))
bpt_indexer->Put({station_hash, train_hash, 0, startTime}, bpt_indexer->Put({station_hash, train_hash, 0, startTime, stop_id},
*reinterpret_cast<default_numeric_index_t *>(&record_arrive)); *reinterpret_cast<default_numeric_index_t *>(&record_arrive));
if (leave_time_offset != uint16_t(-1)) if (leave_time_offset != uint16_t(-1))
bpt_indexer->Put({station_hash, train_hash, 1, startTime}, bpt_indexer->Put({station_hash, train_hash, 1, startTime, stop_id},
*reinterpret_cast<default_numeric_index_t *>(&record_leave)); *reinterpret_cast<default_numeric_index_t *>(&record_leave));
} }
inline void QueryDirectTrains(uint32_t date, hash_t from_station_ID, hash_t to_station_ID, inline void QueryDirectTrains(uint32_t date, hash_t from_station_ID, hash_t to_station_ID,
@ -102,17 +106,24 @@ class StopRegister : public DataDriverBase {
++it_from; ++it_from;
continue; 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<const MinimalTrainRecord *>(&value_from)).saleDate_beg + June_1st_2024; int true_saleDate_beg = (*reinterpret_cast<const MinimalTrainRecord *>(&value_from)).saleDate_beg + June_1st_2024;
int true_saleDate_end = (*reinterpret_cast<const MinimalTrainRecord *>(&value_from)).saleDate_end + June_1st_2024; int true_saleDate_end = (*reinterpret_cast<const MinimalTrainRecord *>(&value_from)).saleDate_end + June_1st_2024;
int leave_time_offset = (*reinterpret_cast<const MinimalTrainRecord *>(&value_from)).vis_time_offset; int leave_time_offset = (*reinterpret_cast<const MinimalTrainRecord *>(&value_from)).vis_time_offset;
int startTime = key_from.startTime; int startTime = key_from.startTime;
int actual_time = startTime + leave_time_offset; int actual_time = startTime + leave_time_offset;
int delta_days = actual_time / 1440; int delta_days = actual_time / 1440;
if (date - delta_days < true_saleDate_beg || date - delta_days > true_saleDate_end) continue; if (date - delta_days < true_saleDate_beg || date - delta_days > true_saleDate_end) {
++it_from;
continue;
}
StopRegister::DirectTrainInfo entry; StopRegister::DirectTrainInfo entry;
entry.train_ID_hash = key_from.train_ID_hash; entry.train_ID_hash = key_from.train_ID_hash;
entry.actual_start_date = date - delta_days; entry.actual_start_date = date - delta_days;
entry.leave_time_stamp = true_saleDate_beg * 1440 + actual_time; 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()) { while (it_to != bpt_indexer->end_const()) {
const auto &key_to = it_to.GetKey(); const auto &key_to = it_to.GetKey();
const auto &value_to = it_to.GetValue(); const auto &value_to = it_to.GetValue();
@ -121,10 +132,14 @@ class StopRegister : public DataDriverBase {
++it_to; ++it_to;
continue; 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) break;
if (key_to.train_ID_hash == key_from.train_ID_hash) { if (key_to.train_ID_hash == key_from.train_ID_hash) {
entry.arrive_time_stamp = true_saleDate_beg * 1440 + startTime + entry.arrive_time_stamp = entry.actual_start_date * 1440 + startTime +
(*reinterpret_cast<const MinimalTrainRecord *>(&value_to)).vis_time_offset; (*reinterpret_cast<const MinimalTrainRecord *>(&value_to)).vis_time_offset;
entry.to_stop_id = key_to.stop_id;
res.push_back(entry);
++it_to; ++it_to;
break; break;
} }

View File

@ -234,6 +234,7 @@ std::string TicketSystemEngine::ReleaseTrain(const std::string &command) {
} }
} }
hash_t train_id_hash = SplitMix64Hash(trainID); hash_t train_id_hash = SplitMix64Hash(trainID);
LOG->debug("hash({})={}", trainID, train_id_hash);
CoreTrainData core_train_data; CoreTrainData core_train_data;
try { try {
core_train_data_storage.Get(train_id_hash, core_train_data); core_train_data_storage.Get(train_id_hash, core_train_data);
@ -262,7 +263,7 @@ std::string TicketSystemEngine::ReleaseTrain(const std::string &command) {
} }
stop_register.AddStopInfo(core_train_data.stations_hash[i], train_id_hash, core_train_data.saleDate_beg, stop_register.AddStopInfo(core_train_data.stations_hash[i], train_id_hash, core_train_data.saleDate_beg,
core_train_data.saleDate_end, core_train_data.startTime, arrive_time_offset, core_train_data.saleDate_end, core_train_data.startTime, arrive_time_offset,
leave_time_offset); leave_time_offset, i);
} }
response_stream << '[' << command_id << "] 0"; response_stream << '[' << command_id << "] 0";
return response_stream.str(); return response_stream.str();

View File

@ -1,3 +1,4 @@
#include <algorithm>
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
@ -51,12 +52,74 @@ std::string TicketSystemEngine::QueryTicket(const std::string &command) {
hash_t from_hash = SplitMix64Hash(from), to_hash = SplitMix64Hash(to); hash_t from_hash = SplitMix64Hash(from), to_hash = SplitMix64Hash(to);
std::vector<StopRegister::DirectTrainInfo> valid_trains; std::vector<StopRegister::DirectTrainInfo> valid_trains;
stop_register.QueryDirectTrains(date, from_hash, to_hash, valid_trains); stop_register.QueryDirectTrains(date, from_hash, to_hash, valid_trains);
std::vector<std::pair<StopRegister::DirectTrainInfo, AdditionalTrainInfo>> valid_trains_full;
size_t len = valid_trains.size(); size_t len = valid_trains.size();
std::vector<std::pair<StopRegister::DirectTrainInfo, AdditionalTrainInfo>> valid_trains_full(len);
LOG->debug("retrieving full data");
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
valid_trains_full[i].first = valid_trains[i]; valid_trains_full[i].first = valid_trains[i];
TicketPriceData ticket_price_data;
SeatsData seats_data;
int from_station_id = valid_trains[i].from_stop_id;
int to_station_id = valid_trains[i].to_stop_id;
ticket_price_data_storage.Get(valid_trains[i].train_ID_hash, ticket_price_data);
LOG->debug("analyzing train {} from {} to {}", ticket_price_data.trainID, from_station_id, to_station_id);
seats_data_storage.Get(
{valid_trains[i].train_ID_hash, valid_trains[i].actual_start_date - valid_trains[i].saleDate_beg}, seats_data);
strcpy(valid_trains_full[i].second.trainID, ticket_price_data.trainID);
int total_price = 0;
for (int j = from_station_id; j < to_station_id; j++) {
total_price += ticket_price_data.price[j];
}
valid_trains_full[i].second.price = total_price;
int seats = seats_data.seat[from_station_id];
for (int j = from_station_id + 1; j < to_station_id; j++) {
seats = std::min(seats, (int)seats_data.seat[j]);
}
valid_trains_full[i].second.seats = seats;
}
LOG->debug("successfully retrieved full data");
std::vector<int> valid_trains_full_index(len);
for (size_t i = 0; i < len; i++) {
valid_trains_full_index[i] = i;
}
if (order_by == "time") {
auto cmp = [&valid_trains_full](int a, int b) {
int time_cost_a = valid_trains_full[a].first.arrive_time_stamp - valid_trains_full[a].first.leave_time_stamp;
int time_cost_b = valid_trains_full[b].first.arrive_time_stamp - valid_trains_full[b].first.leave_time_stamp;
if (time_cost_a != time_cost_b) return time_cost_a < time_cost_b;
return strcmp(valid_trains_full[a].second.trainID, valid_trains_full[b].second.trainID) < 0;
};
std::sort(valid_trains_full_index.begin(), valid_trains_full_index.end(), cmp);
} else {
// order by price
auto cmp = [&valid_trains_full](int a, int b) {
if (valid_trains_full[a].second.price != valid_trains_full[b].second.price)
return valid_trains_full[a].second.price < valid_trains_full[b].second.price;
return strcmp(valid_trains_full[a].second.trainID, valid_trains_full[b].second.trainID) < 0;
};
std::sort(valid_trains_full_index.begin(), valid_trains_full_index.end(), cmp);
}
response_stream << "[" << command_id << "] " << len;
for (int i = 0; i < len; i++) {
response_stream << '\n';
response_stream << valid_trains_full[valid_trains_full_index[i]].second.trainID << ' ' << from << ' ';
int leave_time_stamp = valid_trains_full[valid_trains_full_index[i]].first.leave_time_stamp;
int leave_time_month, leave_time_day, leave_time_hour, leave_time_minute;
RetrieveReadableTimeStamp(leave_time_stamp, leave_time_month, leave_time_day, leave_time_hour, leave_time_minute);
response_stream << std::setw(2) << std::setfill('0') << leave_time_month << '-' << std::setw(2) << std::setfill('0')
<< leave_time_day << ' ' << std::setw(2) << std::setfill('0') << leave_time_hour << ':'
<< std::setw(2) << std::setfill('0') << leave_time_minute;
response_stream << " -> " << to << ' ';
int arrive_time_stamp = valid_trains_full[valid_trains_full_index[i]].first.arrive_time_stamp;
int arrive_time_month, arrive_time_day, arrive_time_hour, arrive_time_minute;
RetrieveReadableTimeStamp(arrive_time_stamp, arrive_time_month, arrive_time_day, arrive_time_hour,
arrive_time_minute);
response_stream << std::setw(2) << std::setfill('0') << arrive_time_month << '-' << std::setw(2)
<< std::setfill('0') << arrive_time_day << ' ' << std::setw(2) << std::setfill('0')
<< arrive_time_hour << ':' << std::setw(2) << std::setfill('0') << arrive_time_minute;
response_stream << ' ' << valid_trains_full[valid_trains_full_index[i]].second.price << ' '
<< valid_trains_full[valid_trains_full_index[i]].second.seats;
} }
response_stream << "[" << command_id << "] QueryTicket";
return response_stream.str(); return response_stream.str();
} }

View File

@ -4,7 +4,7 @@ add_test(NAME basic_3 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_3 --ski
add_test(NAME basic_4 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_4 --skip-check --ignore-first-dependency --enable-tested-program-logging) add_test(NAME basic_4 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_4 --skip-check --ignore-first-dependency --enable-tested-program-logging)
add_test(NAME basic_5 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_5 --skip-check --ignore-first-dependency --enable-tested-program-logging) add_test(NAME basic_5 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_5 --skip-check --ignore-first-dependency --enable-tested-program-logging)
add_test(NAME basic_6 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_6 --skip-check --ignore-first-dependency --enable-tested-program-logging) add_test(NAME basic_6 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_6 --skip-check --ignore-first-dependency --enable-tested-program-logging)
add_test(NAME basic_extra COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_extra --skip-check --ignore-first-dependency --enable-tested-program-logging) add_test(NAME basic_extra COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_extra --skip-check --ignore-first-dependency)
add_test(NAME pressure_1_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_1_easy --skip-check --ignore-first-dependency) add_test(NAME pressure_1_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_1_easy --skip-check --ignore-first-dependency)
add_test(NAME pressure_2_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_2_easy --skip-check --ignore-first-dependency) add_test(NAME pressure_2_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_2_easy --skip-check --ignore-first-dependency)
add_test(NAME pressure_3_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_3_easy --skip-check --ignore-first-dependency) add_test(NAME pressure_3_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_3_easy --skip-check --ignore-first-dependency)