Skip to content

Commit 494581b

Browse files
committed
[manager/service/client] preserve partial cache meta details
1 parent 36ed6f6 commit 494581b

10 files changed

Lines changed: 172 additions & 17 deletions

File tree

docs/api/meta_service.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ Example response:
256256
},
257257
"items": [
258258
{
259+
"status": {
260+
"code": "OK"
261+
},
259262
"request_index": 0,
260263
"block_key": 123,
261264
"prev_block_key": "",
@@ -287,6 +290,9 @@ Example response:
287290
]
288291
},
289292
{
293+
"status": {
294+
"code": "OK"
295+
},
290296
"request_index": 1,
291297
"block_key": 456,
292298
"locations": [
@@ -299,4 +305,4 @@ Example response:
299305
}
300306
```
301307

302-
This diagnostic API returns raw metadata for every unmasked requested key. It does not apply location selection, data-file existence filtering, or lazy prune.
308+
This diagnostic API returns raw metadata for every unmasked requested key. It does not apply location selection, data-file existence filtering, or lazy prune. `prev_block_key` is a convenience projection of `properties["BP#prev_key"]`; the raw property is intentionally retained. A missing key is reported as a successful item with `CLS_NOT_FOUND`. Backend or deserialization failures are reported in that item's `status` while other successful items are still returned. If every item fails to read, the request returns an overall error.

integration_test/meta_service/meta_interface_cases.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,35 @@ def test_basic_smoke(self):
154154

155155
self._client.finish_write_cache(finish_write_data)
156156

157-
# Step 4: Get cache location to verify it was added correctly
157+
# Step 4: Query raw metadata detail for one existing and one missing key.
158+
detail_data = {
159+
"trace_id": self._trace_id,
160+
"instance_id": self._instance_id,
161+
"block_keys": [123, 999],
162+
"block_mask": {
163+
"offset": 0
164+
},
165+
"detail_level": 1
166+
}
167+
detail_response = self._client.get_cache_meta_detail(detail_data)
168+
self.assertIn('items', detail_response)
169+
self.assertEqual(2, len(detail_response['items']))
170+
171+
found_item, missing_item = detail_response['items']
172+
self.assertEqual(0, found_item['request_index'])
173+
self.assertEqual(123, int(found_item['block_key']))
174+
self.assertEqual('OK', found_item['status']['code'])
175+
self.assertGreater(len(found_item['locations']), 0)
176+
self.assertTrue(any(location['status'] == 'CLS_SERVING'
177+
for location in found_item['locations']))
178+
179+
self.assertEqual(1, missing_item['request_index'])
180+
self.assertEqual(999, int(missing_item['block_key']))
181+
self.assertEqual('OK', missing_item['status']['code'])
182+
self.assertEqual(['CLS_NOT_FOUND'],
183+
[location['status'] for location in missing_item['locations']])
184+
185+
# Step 5: Get cache location to verify it was added correctly
158186
get_location_data = {
159187
"trace_id": self._trace_id,
160188
"query_type": "QT_PREFIX_MATCH",

kv_cache_manager/client/include/common.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,30 @@ enum class CacheMetaLocationStatus : int32_t {
9292
CLS_DELETING = 4,
9393
};
9494

95+
enum class CacheMetaStorageType : int32_t {
96+
ST_UNSPECIFIED = 0,
97+
ST_3FS = 1,
98+
ST_MOONCAKE = 2,
99+
ST_TAIRMEMPOOL = 3,
100+
ST_NFS = 4,
101+
ST_VCNS_3FS = 5,
102+
ST_DUMMY = 6,
103+
ST_EVENT_REPORT_L1P5 = 7,
104+
ST_EVENT_REPORT_L2 = 8,
105+
};
106+
95107
struct CacheMetaLocationDetail {
96108
std::string location_id;
97109
CacheMetaLocationStatus status{CacheMetaLocationStatus::CLS_NOT_FOUND};
98-
int32_t storage_type{0};
110+
CacheMetaStorageType storage_type{CacheMetaStorageType::ST_UNSPECIFIED};
99111
int32_t spec_size{0};
100112
int64_t create_time{0};
101113
Location location_specs;
102114
};
103115

104116
struct CacheMetaDetailItem {
117+
ClientErrorCode error_code{ClientErrorCode::ER_OK};
118+
std::string error_message;
105119
int32_t request_index{0};
106120
int64_t block_key{0};
107121
std::string prev_block_key;

kv_cache_manager/client/src/internal/stub/grpc_stub.cc

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@
6565

6666
namespace {
6767

68+
kv_cache_manager::ClientErrorCode ToClientError(kv_cache_manager::proto::meta::ErrorCode service_error);
69+
6870
kv_cache_manager::Locations GenLocations(
6971
const google::protobuf::RepeatedPtrField<::kv_cache_manager::proto::meta::CacheLocation> &proto_locations) {
7072
kv_cache_manager::Locations locations;
@@ -80,13 +82,17 @@ kv_cache_manager::Locations GenLocations(
8082
return locations;
8183
}
8284

83-
kv_cache_manager::CacheMetaDetails GenCacheMetaDetails(
84-
const google::protobuf::RepeatedPtrField<::kv_cache_manager::proto::meta::CacheMetaDetailItem>
85-
&proto_cache_meta_details) {
85+
kv_cache_manager::CacheMetaDetails
86+
GenCacheMetaDetails(const google::protobuf::RepeatedPtrField<::kv_cache_manager::proto::meta::CacheMetaDetailItem>
87+
&proto_cache_meta_details) {
8688
kv_cache_manager::CacheMetaDetails cache_meta_details;
8789
cache_meta_details.reserve(proto_cache_meta_details.size());
8890
for (const auto &proto_item : proto_cache_meta_details) {
8991
kv_cache_manager::CacheMetaDetailItem item;
92+
if (proto_item.has_status() && proto_item.status().code() != kv_cache_manager::proto::meta::OK) {
93+
item.error_code = ToClientError(proto_item.status().code());
94+
item.error_message = proto_item.status().message();
95+
}
9096
item.request_index = proto_item.request_index();
9197
item.block_key = proto_item.block_key();
9298
item.prev_block_key = proto_item.prev_block_key();
@@ -97,9 +103,8 @@ kv_cache_manager::CacheMetaDetails GenCacheMetaDetails(
97103
for (const auto &proto_location : proto_item.locations()) {
98104
kv_cache_manager::CacheMetaLocationDetail location;
99105
location.location_id = proto_location.location_id();
100-
location.status =
101-
static_cast<kv_cache_manager::CacheMetaLocationStatus>(proto_location.status());
102-
location.storage_type = static_cast<int32_t>(proto_location.type());
106+
location.status = static_cast<kv_cache_manager::CacheMetaLocationStatus>(proto_location.status());
107+
location.storage_type = static_cast<kv_cache_manager::CacheMetaStorageType>(proto_location.type());
103108
location.spec_size = proto_location.spec_size();
104109
location.create_time = proto_location.create_time();
105110
location.location_specs.reserve(proto_location.location_specs_size());

kv_cache_manager/manager/cache_location_view.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ struct CacheLocationMetaDetail {
8888
};
8989

9090
struct CacheKeyMetaDetail {
91+
ErrorCode error_code = EC_OK;
9192
size_t request_index = 0;
9293
KeyType block_key = 0;
9394
PropertyMap properties;

kv_cache_manager/manager/cache_manager.cc

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -802,13 +802,25 @@ std::pair<ErrorCode, CacheMetaDetailVec> CacheManager::GetCacheMetaDetail(Reques
802802
CacheKeyMetaDetail item;
803803
item.request_index = request_indices[idx];
804804
item.block_key = query_keys[idx];
805-
if (idx < properties.size()) {
806-
item.properties = properties[idx];
805+
806+
if (idx >= per_key_ecs.size()) {
807+
item.error_code = EC_MISMATCH;
808+
details.push_back(std::move(item));
809+
continue;
810+
}
811+
if (per_key_ecs[idx] != EC_OK && per_key_ecs[idx] != EC_NOENT) {
812+
item.error_code = per_key_ecs[idx];
813+
details.push_back(std::move(item));
814+
continue;
807815
}
816+
if (idx >= location_maps.size() || idx >= properties.size()) {
817+
item.error_code = EC_MISMATCH;
818+
details.push_back(std::move(item));
819+
continue;
820+
}
821+
item.properties = properties[idx];
808822

809-
const bool key_not_found =
810-
idx >= per_key_ecs.size() || per_key_ecs[idx] == ErrorCode::EC_NOENT || idx >= location_maps.size() ||
811-
location_maps[idx].empty();
823+
const bool key_not_found = per_key_ecs[idx] == ErrorCode::EC_NOENT || location_maps[idx].empty();
812824
if (key_not_found) {
813825
CacheLocationMetaDetail not_found;
814826
not_found.status = CacheLocationStatus::CLS_NOT_FOUND;
@@ -848,6 +860,12 @@ std::pair<ErrorCode, CacheMetaDetailVec> CacheManager::GetCacheMetaDetail(Reques
848860
details.push_back(std::move(item));
849861
}
850862

863+
const auto first_item_error =
864+
std::find_if(details.begin(), details.end(), [](const auto &item) { return item.error_code != EC_OK; });
865+
if (first_item_error != details.end() &&
866+
std::all_of(details.begin(), details.end(), [](const auto &item) { return item.error_code != EC_OK; })) {
867+
return {first_item_error->error_code, std::move(details)};
868+
}
851869
return {EC_OK, std::move(details)};
852870
}
853871

kv_cache_manager/manager/test/cache_manager_test.cc

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,38 @@ ErrorCode ReadError_stub(void * /*obj*/,
8585
}
8686
} // namespace mark_query_read_error_stub
8787

88+
namespace raw_meta_partial_error_stub {
89+
ErrorCode BatchGetRawMeta_stub(void * /*obj*/,
90+
RequestContext * /*request_context*/,
91+
const KeyVector &keys,
92+
CacheLocationMapVector &out_location_maps,
93+
PropertyMapVector &out_properties,
94+
std::vector<ErrorCode> &out_error_codes) {
95+
out_location_maps.assign(keys.size(), {});
96+
out_properties.assign(keys.size(), {});
97+
out_error_codes.assign(keys.size(), EC_OK);
98+
99+
for (size_t idx = 0; idx < keys.size(); ++idx) {
100+
if (keys[idx] == 22) {
101+
out_error_codes[idx] = EC_TIMEOUT;
102+
continue;
103+
}
104+
if (keys[idx] == 33) {
105+
out_error_codes[idx] = EC_NOENT;
106+
continue;
107+
}
108+
auto location = std::make_shared<CacheLocation>("location_ok",
109+
CacheLocationStatus::CLS_SERVING,
110+
DataStorageType::DATA_STORAGE_TYPE_NFS,
111+
1,
112+
std::vector<LocationSpec>{{"tp0", "file:///tmp/key?size=1"}});
113+
out_location_maps[idx][location->id()] = std::move(location);
114+
out_properties[idx][PROPERTY_PREV_BLOCK_KEY] = "";
115+
}
116+
return EC_OK;
117+
}
118+
} // namespace raw_meta_partial_error_stub
119+
88120
namespace remove_instance_reclaimer_state_stub {
89121
CacheReclaimer *reclaimer = nullptr;
90122
bool called = false;
@@ -2123,6 +2155,35 @@ TEST_F(CacheManagerTest, TestGetNotExistCacheMeta) {
21232155
}
21242156
}
21252157

2158+
TEST_F(CacheManagerTest, TestGetCacheMetaDetailPreservesPartialResults) {
2159+
Stub stub;
2160+
stub.set(ADDR(MetaSearcher, BatchGetRawMeta), raw_meta_partial_error_stub::BatchGetRawMeta_stub);
2161+
2162+
BlockMask block_mask = static_cast<size_t>(0);
2163+
auto [ec, details] =
2164+
cache_manager_->GetCacheMetaDetail(request_context_.get(), "test_instance", {11, 22, 33}, {}, block_mask, 1);
2165+
2166+
ASSERT_EQ(EC_OK, ec);
2167+
ASSERT_EQ(3, details.size());
2168+
2169+
EXPECT_EQ(EC_OK, details[0].error_code);
2170+
ASSERT_EQ(1, details[0].locations.size());
2171+
EXPECT_EQ(CacheLocationStatus::CLS_SERVING, details[0].locations[0].status);
2172+
2173+
EXPECT_EQ(EC_TIMEOUT, details[1].error_code);
2174+
EXPECT_TRUE(details[1].locations.empty());
2175+
2176+
EXPECT_EQ(EC_OK, details[2].error_code);
2177+
ASSERT_EQ(1, details[2].locations.size());
2178+
EXPECT_EQ(CacheLocationStatus::CLS_NOT_FOUND, details[2].locations[0].status);
2179+
2180+
auto [all_failed_ec, all_failed_details] =
2181+
cache_manager_->GetCacheMetaDetail(request_context_.get(), "test_instance", {22}, {}, block_mask, 1);
2182+
EXPECT_EQ(EC_TIMEOUT, all_failed_ec);
2183+
ASSERT_EQ(1, all_failed_details.size());
2184+
EXPECT_EQ(EC_TIMEOUT, all_failed_details[0].error_code);
2185+
}
2186+
21262187
TEST_F(CacheManagerTest, TestRemoveCache) {
21272188
auto expected = std::pair<ErrorCode, std::string>(EC_OK, default_storage_configs);
21282189
ASSERT_EQ(expected,

kv_cache_manager/protocol/protobuf/meta_service.proto

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,15 @@ message CacheLocationDetail {
432432
message CacheMetaDetailItem {
433433
int32 request_index = 1;
434434
int64 block_key = 2;
435+
// Convenience projection of properties["BP#prev_key"]. The raw property is
436+
// intentionally retained in properties as well.
435437
string prev_block_key = 3;
436438
map<string, string> properties = 4;
437439
repeated CacheLocationDetail locations = 5;
440+
// Per-key raw metadata lookup status. A missing key is a successful lookup
441+
// represented by CLS_NOT_FOUND; backend/read failures are reported here so
442+
// other successful items can still be returned.
443+
Status status = 6;
438444
}
439445

440446
message GetCacheMetaDetailResponse {

kv_cache_manager/service/meta_service_impl.cc

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -727,15 +727,23 @@ void MetaServiceImpl::GetCacheMetaDetail(RequestContext *request_context,
727727
request_context->error_tracer()->ToJsonString());
728728
KVCM_LOG_ERROR("[traceId: %s] GetCacheMetaDetail failed, ec: %d", request->trace_id().c_str(), ec_info);
729729
} else {
730+
size_t item_error_count = 0;
730731
for (const auto &cache_meta_detail : cache_meta_details) {
732+
item_error_count += cache_meta_detail.error_code != EC_OK;
731733
ProtoConvert::CacheKeyMetaDetailToProto(cache_meta_detail, response->add_items());
732734
}
733735
status->set_code(proto::meta::OK);
734736
request_context->set_status_code(status->code());
735-
status->set_message("Cache metadata detail retrieved successfully");
736-
KVCM_LOG_INFO("[traceId: %s] GetCacheMetaDetail succeeded, returned %d items",
737+
if (item_error_count == 0) {
738+
status->set_message("Cache metadata detail retrieved successfully");
739+
} else {
740+
status->set_message("Cache metadata detail retrieved with " + std::to_string(item_error_count) +
741+
" item errors");
742+
}
743+
KVCM_LOG_INFO("[traceId: %s] GetCacheMetaDetail succeeded, returned %d items with %zu item errors",
737744
request->trace_id().c_str(),
738-
response->items_size());
745+
response->items_size(),
746+
item_error_count);
739747
}
740748
SET_SPAN_TRACER_STR_IN_HEADER(request_context);
741749
}

kv_cache_manager/service/util/manager_message_proto_util.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,14 @@ inline void ProtoConvert::CacheLocationMetaDetailToProto(
412412

413413
inline void ProtoConvert::CacheKeyMetaDetailToProto(const CacheKeyMetaDetail &cache_meta_detail,
414414
proto::meta::CacheMetaDetailItem *proto_cache_meta_detail) {
415+
auto *status = proto_cache_meta_detail->mutable_status();
416+
if (cache_meta_detail.error_code == EC_OK) {
417+
status->set_code(proto::meta::OK);
418+
} else {
419+
status->set_code(ToPbError<proto::meta::ErrorCode>(cache_meta_detail.error_code));
420+
status->set_message("Raw metadata lookup failed with internal error code: " +
421+
std::to_string(static_cast<int32_t>(cache_meta_detail.error_code)));
422+
}
415423
proto_cache_meta_detail->set_request_index(static_cast<int32_t>(cache_meta_detail.request_index));
416424
proto_cache_meta_detail->set_block_key(cache_meta_detail.block_key);
417425
auto prev_key_iter = cache_meta_detail.properties.find(PROPERTY_PREV_BLOCK_KEY);

0 commit comments

Comments
 (0)