|
@@ -1420,15 +1420,89 @@ grpc::Status DatabaseGrpcImpl::GetCollectionConfig(
|
|
|
|
|
|
|
|
grpc::Status DatabaseGrpcImpl::MigrateCollectionTimestamps(
|
|
grpc::Status DatabaseGrpcImpl::MigrateCollectionTimestamps(
|
|
|
grpc::ServerContext* /*context*/,
|
|
grpc::ServerContext* /*context*/,
|
|
|
- const pb::MigrateCollectionTimestampsRequest* /*request*/,
|
|
|
|
|
|
|
+ const pb::MigrateCollectionTimestampsRequest* request,
|
|
|
pb::MigrateCollectionTimestampsResponse* response
|
|
pb::MigrateCollectionTimestampsResponse* response
|
|
|
) {
|
|
) {
|
|
|
- // Implemented in v1.6.0 T5 (separate commit)
|
|
|
|
|
- response->set_success(false);
|
|
|
|
|
- response->set_error("not yet implemented — coming in next task");
|
|
|
|
|
- response->set_rows_migrated(0);
|
|
|
|
|
- response->set_rows_skipped(0);
|
|
|
|
|
- return grpc::Status::OK;
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ const std::string& collection = request->collection();
|
|
|
|
|
+ const std::string& from = request->from_precision();
|
|
|
|
|
+ const std::string& to = request->to_precision();
|
|
|
|
|
+
|
|
|
|
|
+ // No-op success when caller supplies identical precisions.
|
|
|
|
|
+ if (from == to) {
|
|
|
|
|
+ response->set_success(true);
|
|
|
|
|
+ response->set_rows_migrated(0);
|
|
|
|
|
+ response->set_rows_skipped(0);
|
|
|
|
|
+ return grpc::Status::OK;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ bool msToNs;
|
|
|
|
|
+ if (from == "ms" && to == "ns") {
|
|
|
|
|
+ msToNs = true;
|
|
|
|
|
+ } else if (from == "ns" && to == "ms") {
|
|
|
|
|
+ msToNs = false;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ response->set_success(false);
|
|
|
|
|
+ response->set_error("from_precision and to_precision must each be 'ms' or 'ns'");
|
|
|
|
|
+ response->set_rows_migrated(0);
|
|
|
|
|
+ response->set_rows_skipped(0);
|
|
|
|
|
+ return grpc::Status::OK;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Idempotency heuristic: any timestamp >= 10^15 is treated as ns
|
|
|
|
|
+ // (10^15 ms = year 33658, no real data is that far in the future;
|
|
|
|
|
+ // 10^15 ns = 1970-01-12, no real data is that old).
|
|
|
|
|
+ constexpr uint64_t NS_THRESHOLD = 1'000'000'000'000'000ULL; // 10^15
|
|
|
|
|
+
|
|
|
|
|
+ Query q;
|
|
|
|
|
+ QueryResult result = store_.find(collection, q);
|
|
|
|
|
+
|
|
|
|
|
+ uint64_t migrated = 0;
|
|
|
|
|
+ uint64_t skipped = 0;
|
|
|
|
|
+
|
|
|
|
|
+ for (const auto& doc : result.documents) {
|
|
|
|
|
+ const uint64_t c = doc.createdAt;
|
|
|
|
|
+ const uint64_t u = doc.updatedAt;
|
|
|
|
|
+
|
|
|
|
|
+ bool cInTarget;
|
|
|
|
|
+ bool uInTarget;
|
|
|
|
|
+ if (msToNs) {
|
|
|
|
|
+ cInTarget = (c >= NS_THRESHOLD);
|
|
|
|
|
+ uInTarget = (u >= NS_THRESHOLD);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ cInTarget = (c < NS_THRESHOLD);
|
|
|
|
|
+ uInTarget = (u < NS_THRESHOLD);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (cInTarget && uInTarget) {
|
|
|
|
|
+ ++skipped;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const uint64_t newC = cInTarget
|
|
|
|
|
+ ? c
|
|
|
|
|
+ : (msToNs ? c * 1'000'000ULL : c / 1'000'000ULL);
|
|
|
|
|
+ const uint64_t newU = uInTarget
|
|
|
|
|
+ ? u
|
|
|
|
|
+ : (msToNs ? u * 1'000'000ULL : u / 1'000'000ULL);
|
|
|
|
|
+
|
|
|
|
|
+ if (store_.updateTimestamps(collection, doc.id, newC, newU)) {
|
|
|
|
|
+ ++migrated;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ response->set_success(true);
|
|
|
|
|
+ response->set_rows_migrated(migrated);
|
|
|
|
|
+ response->set_rows_skipped(skipped);
|
|
|
|
|
+ return grpc::Status::OK;
|
|
|
|
|
+
|
|
|
|
|
+ } catch (const std::exception& e) {
|
|
|
|
|
+ response->set_success(false);
|
|
|
|
|
+ response->set_error(e.what());
|
|
|
|
|
+ response->set_rows_migrated(0);
|
|
|
|
|
+ response->set_rows_skipped(0);
|
|
|
|
|
+ return grpc::Status::OK;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
} // namespace smartbotic::database
|
|
} // namespace smartbotic::database
|