Skip to content

Commit be9a2fe

Browse files
committed
[manager/service/client] preserve partial cache meta details
1 parent bd3dbbd commit be9a2fe

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
@@ -770,13 +770,25 @@ std::pair<ErrorCode, CacheMetaDetailVec> CacheManager::GetCacheMetaDetail(Reques
770770
CacheKeyMetaDetail item;
771771
item.request_index = request_indices[idx];
772772
item.block_key = query_keys[idx];
773-
if (idx < properties.size()) {
774-
item.properties = properties[idx];
773+
774+
if (idx >= per_key_ecs.size()) {
775+
item.error_code = EC_MISMATCH;
776+
details.push_back(std::move(item));
777+
continue;
778+
}
779+
if (per_key_ecs[idx] != EC_OK && per_key_ecs[idx] != EC_NOENT) {
780+
item.error_code = per_key_ecs[idx];
781+
details.push_back(std::move(item));
782+
continue;
775783
}
784+
if (idx >= location_maps.size() || idx >= properties.size()) {
785+
item.error_code = EC_MISMATCH;
786+
details.push_back(std::move(item));
787+
continue;
788+
}
789+
item.properties = properties[idx];
776790

777-
const bool key_not_found =
778-
idx >= per_key_ecs.size() || per_key_ecs[idx] == ErrorCode::EC_NOENT || idx >= location_maps.size() ||
779-
location_maps[idx].empty();
791+
const bool key_not_found = per_key_ecs[idx] == ErrorCode::EC_NOENT || location_maps[idx].empty();
780792
if (key_not_found) {
781793
CacheLocationMetaDetail not_found;
782794
not_found.status = CacheLocationStatus::CLS_NOT_FOUND;
@@ -816,6 +828,12 @@ std::pair<ErrorCode, CacheMetaDetailVec> CacheManager::GetCacheMetaDetail(Reques
816828
details.push_back(std::move(item));
817829
}
818830

831+
const auto first_item_error =
832+
std::find_if(details.begin(), details.end(), [](const auto &item) { return item.error_code != EC_OK; });
833+
if (first_item_error != details.end() &&
834+
std::all_of(details.begin(), details.end(), [](const auto &item) { return item.error_code != EC_OK; })) {
835+
return {first_item_error->error_code, std::move(details)};
836+
}
819837
return {EC_OK, std::move(details)};
820838
}
821839

kv_cache_manager/manager/test/cache_manager_test.cc

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,38 @@ ErrorCode ReadError_stub(void * /*obj*/,
8282
}
8383
} // namespace mark_query_read_error_stub
8484

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

2012+
TEST_F(CacheManagerTest, TestGetCacheMetaDetailPreservesPartialResults) {
2013+
Stub stub;
2014+
stub.set(ADDR(MetaSearcher, BatchGetRawMeta), raw_meta_partial_error_stub::BatchGetRawMeta_stub);
2015+
2016+
BlockMask block_mask = static_cast<size_t>(0);
2017+
auto [ec, details] =
2018+
cache_manager_->GetCacheMetaDetail(request_context_.get(), "test_instance", {11, 22, 33}, {}, block_mask, 1);
2019+
2020+
ASSERT_EQ(EC_OK, ec);
2021+
ASSERT_EQ(3, details.size());
2022+
2023+
EXPECT_EQ(EC_OK, details[0].error_code);
2024+
ASSERT_EQ(1, details[0].locations.size());
2025+
EXPECT_EQ(CacheLocationStatus::CLS_SERVING, details[0].locations[0].status);
2026+
2027+
EXPECT_EQ(EC_TIMEOUT, details[1].error_code);
2028+
EXPECT_TRUE(details[1].locations.empty());
2029+
2030+
EXPECT_EQ(EC_OK, details[2].error_code);
2031+
ASSERT_EQ(1, details[2].locations.size());
2032+
EXPECT_EQ(CacheLocationStatus::CLS_NOT_FOUND, details[2].locations[0].status);
2033+
2034+
auto [all_failed_ec, all_failed_details] =
2035+
cache_manager_->GetCacheMetaDetail(request_context_.get(), "test_instance", {22}, {}, block_mask, 1);
2036+
EXPECT_EQ(EC_TIMEOUT, all_failed_ec);
2037+
ASSERT_EQ(1, all_failed_details.size());
2038+
EXPECT_EQ(EC_TIMEOUT, all_failed_details[0].error_code);
2039+
}
2040+
19802041
TEST_F(CacheManagerTest, TestRemoveCache) {
19812042
auto expected = std::pair<ErrorCode, std::string>(EC_OK, default_storage_configs);
19822043
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
@@ -426,9 +426,15 @@ message CacheLocationDetail {
426426
message CacheMetaDetailItem {
427427
int32 request_index = 1;
428428
int64 block_key = 2;
429+
// Convenience projection of properties["BP#prev_key"]. The raw property is
430+
// intentionally retained in properties as well.
429431
string prev_block_key = 3;
430432
map<string, string> properties = 4;
431433
repeated CacheLocationDetail locations = 5;
434+
// Per-key raw metadata lookup status. A missing key is a successful lookup
435+
// represented by CLS_NOT_FOUND; backend/read failures are reported here so
436+
// other successful items can still be returned.
437+
Status status = 6;
432438
}
433439

434440
message GetCacheMetaDetailResponse {

kv_cache_manager/service/meta_service_impl.cc

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -665,15 +665,23 @@ void MetaServiceImpl::GetCacheMetaDetail(RequestContext *request_context,
665665
request_context->error_tracer()->ToJsonString());
666666
KVCM_LOG_ERROR("[traceId: %s] GetCacheMetaDetail failed, ec: %d", request->trace_id().c_str(), ec_info);
667667
} else {
668+
size_t item_error_count = 0;
668669
for (const auto &cache_meta_detail : cache_meta_details) {
670+
item_error_count += cache_meta_detail.error_code != EC_OK;
669671
ProtoConvert::CacheKeyMetaDetailToProto(cache_meta_detail, response->add_items());
670672
}
671673
status->set_code(proto::meta::OK);
672674
request_context->set_status_code(status->code());
673-
status->set_message("Cache metadata detail retrieved successfully");
674-
KVCM_LOG_INFO("[traceId: %s] GetCacheMetaDetail succeeded, returned %d items",
675+
if (item_error_count == 0) {
676+
status->set_message("Cache metadata detail retrieved successfully");
677+
} else {
678+
status->set_message("Cache metadata detail retrieved with " + std::to_string(item_error_count) +
679+
" item errors");
680+
}
681+
KVCM_LOG_INFO("[traceId: %s] GetCacheMetaDetail succeeded, returned %d items with %zu item errors",
675682
request->trace_id().c_str(),
676-
response->items_size());
683+
response->items_size(),
684+
item_error_count);
677685
}
678686
SET_SPAN_TRACER_STR_IN_HEADER(request_context);
679687
}

kv_cache_manager/service/util/manager_message_proto_util.h

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

409409
inline void ProtoConvert::CacheKeyMetaDetailToProto(const CacheKeyMetaDetail &cache_meta_detail,
410410
proto::meta::CacheMetaDetailItem *proto_cache_meta_detail) {
411+
auto *status = proto_cache_meta_detail->mutable_status();
412+
if (cache_meta_detail.error_code == EC_OK) {
413+
status->set_code(proto::meta::OK);
414+
} else {
415+
status->set_code(ToPbError<proto::meta::ErrorCode>(cache_meta_detail.error_code));
416+
status->set_message("Raw metadata lookup failed with internal error code: " +
417+
std::to_string(static_cast<int32_t>(cache_meta_detail.error_code)));
418+
}
411419
proto_cache_meta_detail->set_request_index(static_cast<int32_t>(cache_meta_detail.request_index));
412420
proto_cache_meta_detail->set_block_key(cache_meta_detail.block_key);
413421
auto prev_key_iter = cache_meta_detail.properties.find(PROPERTY_PREV_BLOCK_KEY);

0 commit comments

Comments
 (0)