已合并
fix:修复检视bug #416
fix:修复检视bug #416
已合并
dajiang创建于 7月28日
17 个文件变更+225-102
@@ -1 +1 @@
1-Subproject commit ba113e7a70552778de53dd633d886f6823a562ab1+Subproject commit 8a8699dce340c7488aea9b133877624d002cbf9f
@@ -110,6 +110,7 @@ constexpr uint16_t DEFAULT_REWARM_WATERMARK_VAL = 95U;
110constexpr auto OCK_MMC_REWARM_DRAM_WATERMARK =110constexpr auto OCK_MMC_REWARM_DRAM_WATERMARK =
111 std::make_pair("ock.mmc.rewarm.dram_watermark", DEFAULT_REWARM_WATERMARK_VAL);111 std::make_pair("ock.mmc.rewarm.dram_watermark", DEFAULT_REWARM_WATERMARK_VAL);
112constexpr auto OCK_MMC_PREFETCH_ENABLED = std::make_pair("ock.mmc.storage.prefetch.enabled", false);112constexpr auto OCK_MMC_PREFETCH_ENABLED = std::make_pair("ock.mmc.storage.prefetch.enabled", false);
113+constexpr auto OCK_MMC_PENDING_WAIT_TIMEOUT_MS = std::make_pair("ock.mmc.storage.pending_wait.timeout", 300U);
113constexpr auto OCK_MMC_LOCAL_SERVICE_STORAGE_ENABLED = std::make_pair("ock.mmc.local_service.storage.enabled", false);114constexpr auto OCK_MMC_LOCAL_SERVICE_STORAGE_ENABLED = std::make_pair("ock.mmc.local_service.storage.enabled", false);
114constexpr auto OCK_MMC_LOCAL_SERVICE_DRAM_BEST_EFFORT =115constexpr auto OCK_MMC_LOCAL_SERVICE_DRAM_BEST_EFFORT =
115 std::make_pair("ock.mmc.local_service.dram.best_effort.enabled", false);116 std::make_pair("ock.mmc.local_service.dram.best_effort.enabled", false);
@@ -218,6 +218,8 @@ public:
218 AddIntConf(OCK_MMC_REWARM_DRAM_WATERMARK,218 AddIntConf(OCK_MMC_REWARM_DRAM_WATERMARK,
219 VIntRange::Create(OCK_MMC_REWARM_DRAM_WATERMARK.first, MIN_PERCENT, MAX_PERCENT), 0);219 VIntRange::Create(OCK_MMC_REWARM_DRAM_WATERMARK.first, MIN_PERCENT, MAX_PERCENT), 0);
220 AddBoolConf(OCK_MMC_PREFETCH_ENABLED, VStrEnum::Create(OCK_MMC_PREFETCH_ENABLED.first, BOOL_ENUM_STR), 0);220 AddBoolConf(OCK_MMC_PREFETCH_ENABLED, VStrEnum::Create(OCK_MMC_PREFETCH_ENABLED.first, BOOL_ENUM_STR), 0);
221+ AddIntConf(OCK_MMC_PENDING_WAIT_TIMEOUT_MS, VIntRange::Create(OCK_MMC_PENDING_WAIT_TIMEOUT_MS.first, 1, 60000U),
222+ 0);
221 AddIntConf(OCK_MMC_META_LEASE_TTL_MS,223 AddIntConf(OCK_MMC_META_LEASE_TTL_MS,
222 VIntRange::Create(OCK_MMC_META_LEASE_TTL_MS.first, MIN_LEASE_TTL_MS, MAX_LEASE_TTL_MS), 0);224 VIntRange::Create(OCK_MMC_META_LEASE_TTL_MS.first, MIN_LEASE_TTL_MS, MAX_LEASE_TTL_MS), 0);
223 225 
@@ -287,6 +289,7 @@ public:
287 config.evictThresholdLow = GetInt(ConfConstant::OKC_MMC_EVICT_THRESHOLD_LOW);289 config.evictThresholdLow = GetInt(ConfConstant::OKC_MMC_EVICT_THRESHOLD_LOW);
288 config.rewarmDramWatermark = GetInt(ConfConstant::OCK_MMC_REWARM_DRAM_WATERMARK);290 config.rewarmDramWatermark = GetInt(ConfConstant::OCK_MMC_REWARM_DRAM_WATERMARK);
289 config.prefetchEnabled = GetBool(ConfConstant::OCK_MMC_PREFETCH_ENABLED);291 config.prefetchEnabled = GetBool(ConfConstant::OCK_MMC_PREFETCH_ENABLED);
292+ config.pendingWaitTimeoutMs = static_cast<uint64_t>(GetInt(ConfConstant::OCK_MMC_PENDING_WAIT_TIMEOUT_MS));
290 config.leaseTtlMs = static_cast<uint64_t>(GetInt(ConfConstant::OCK_MMC_META_LEASE_TTL_MS));293 config.leaseTtlMs = static_cast<uint64_t>(GetInt(ConfConstant::OCK_MMC_META_LEASE_TTL_MS));
291 config.logRotationFileSize = GetInt(ConfConstant::OCK_MMC_LOG_ROTATION_FILE_SIZE) * MB_NUM;294 config.logRotationFileSize = GetInt(ConfConstant::OCK_MMC_LOG_ROTATION_FILE_SIZE) * MB_NUM;
292 config.logRotationFileCount = GetInt(ConfConstant::OCK_MMC_LOG_ROTATION_FILE_COUNT);295 config.logRotationFileCount = GetInt(ConfConstant::OCK_MMC_LOG_ROTATION_FILE_COUNT);
@@ -22,13 +22,17 @@ static const uint16_t MAX_NUM_BLOB_CHAINS = 5; // to make sure MmcMemObjMeta <=
22 22 
23Result MmcMemObjMeta::AddBlob(const MmcMemBlobPtr &blob)23Result MmcMemObjMeta::AddBlob(const MmcMemBlobPtr &blob)
24{24{
25+ if (blob == nullptr) {
26+ MMC_LOG_ERROR("add blob: blob is nullptr");
27+ return MMC_ERROR;
28+ }
25 if (numBlobs_ != 0 && size_ != blob->Size()) {29 if (numBlobs_ != 0 && size_ != blob->Size()) {
26 MMC_LOG_ERROR("add blob size:" << blob->Size() << " != meta size:" << size_);30 MMC_LOG_ERROR("add blob size:" << blob->Size() << " != meta size:" << size_);
27 return MMC_ERROR;31 return MMC_ERROR;
28 }32 }
29 for (const auto &old : blobs_) {33 for (const auto &old : blobs_) {
30- if (old == nullptr || blob == nullptr) {34+ if (old == nullptr) {
31- MMC_LOG_ERROR("null ptr find: " << (old == nullptr));35+ MMC_LOG_ERROR("null ptr find in blobs_");
32 return MMC_ERROR;36 return MMC_ERROR;
33 }37 }
34 if (old->GetDesc() == blob->GetDesc()) {38 if (old->GetDesc() == blob->GetDesc()) {
@@ -86,6 +86,10 @@ Result MmcLocalServiceDefault::Start(const mmc_local_service_config_t &config)
86 86 
87 if (RegisterBm() != MMC_OK) {87 if (RegisterBm() != MMC_OK) {
88 MMC_LOG_ERROR("Failed to register bm, name=" << name_ << ", bmRankId=" << options_.rankId);88 MMC_LOG_ERROR("Failed to register bm, name=" << name_ << ", bmRankId=" << options_.rankId);
89+ if (ubsIoProxyPtr_ != nullptr) {
90+ ubsIoProxyPtr_->SetMetaEventCallback(nullptr);
91+ ubsIoProxyPtr_->DestroyUbsIo();
92+ }
89 ubsioEventPool_->Destroy();93 ubsioEventPool_->Destroy();
90 DestroyBm();94 DestroyBm();
91 metaNetClient_->Stop();95 metaNetClient_->Stop();
@@ -116,20 +120,34 @@ void MmcLocalServiceDefault::Stop()
116 MMC_LOG_WARN("MmcLocalServiceDefault has not been started" << ", rank: " << options_.rankId);120 MMC_LOG_WARN("MmcLocalServiceDefault has not been started" << ", rank: " << options_.rankId);
117 return;121 return;
118 }122 }
123+ started_ = false;
119 StopConfigPolling();124 StopConfigPolling();
125+ 
126+ // 先解绑 UBSIO callback,防止 UBSIO 线程继续投递新事件
127+ if (ubsIoProxyPtr_ != nullptr) {
128+ ubsIoProxyPtr_->SetMetaEventCallback(nullptr);
129+ }
130+ 
131+ // 排空已入队的事件
132+ if (ubsioEventPool_ != nullptr) {
133+ ubsioEventPool_->Destroy();
134+ }
135+ 
136+ // 回调已解绑、事件已排空,安全停止 UBSIO
137+ if (ubsIoProxyPtr_ != nullptr) {
138+ ubsIoProxyPtr_->DestroyUbsIo();
139+ ubsIoProxyPtr_ = nullptr;
140+ }
141+ 
120 DestroyBm();142 DestroyBm();
121 if (metaNetClient_ != nullptr) {143 if (metaNetClient_ != nullptr) {
122 metaNetClient_->Stop();144 metaNetClient_->Stop();
123 metaNetClient_ = nullptr;145 metaNetClient_ = nullptr;
124 }146 }
125- if (ubsioEventPool_ != nullptr) {
126- ubsioEventPool_->Destroy();
127- }
128 std::lock_guard<std::mutex> guardBlob(blobMutex_);147 std::lock_guard<std::mutex> guardBlob(blobMutex_);
129 blobMap_.clear();148 blobMap_.clear();
130 MMC_LOG_INFO("Stop MmcLocalServiceDefault (" << name_ << ") server " << options_.discoveryURL149 MMC_LOG_INFO("Stop MmcLocalServiceDefault (" << name_ << ") server " << options_.discoveryURL
131 << ", rank: " << options_.rankId);150 << ", rank: " << options_.rankId);
132- started_ = false;
133}151}
134 152 
135Result MmcLocalServiceDefault::InitBm()153Result MmcLocalServiceDefault::InitBm()
@@ -234,15 +252,17 @@ Result MmcLocalServiceDefault::RegisterBm()
234 }252 }
235 }253 }
236 254 
237- for (auto &desc : descs) {255+ for (auto descIt = descs.begin(); descIt != descs.end();) {
238- if (desc.mediaType_ == MEDIA_SSD) {256+ if (descIt->mediaType_ == MEDIA_SSD) {
239 if (ubsIoProxyPtr_ != nullptr && !ubsIoProxyPtr_->Exist(key)) {257 if (ubsIoProxyPtr_ != nullptr && !ubsIoProxyPtr_->Exist(key)) {
240 MMC_LOG_WARN("SSD blob " << key << " no longer exists on SSD, removing from rebuild");258 MMC_LOG_WARN("SSD blob " << key << " no longer exists on SSD, removing from rebuild");
259+ descIt = descs.erase(descIt);
241 continue;260 continue;
242 }261 }
243 }262 }
244- req.blobList_.push_back({key, desc});263+ req.blobList_.push_back({key, *descIt});
245 ++count;264 ++count;
265+ ++descIt;
246 }266 }
247 267 
248 if (!hasSsdInMap && ubsIoProxyPtr_ != nullptr && ubsIoProxyPtr_->Exist(key)) {268 if (!hasSsdInMap && ubsIoProxyPtr_ != nullptr && ubsIoProxyPtr_->Exist(key)) {
@@ -257,7 +277,11 @@ Result MmcLocalServiceDefault::RegisterBm()
257 }277 }
258 }278 }
259 }279 }
260- ++it;280+ if (descs.empty()) {
281+ it = blobMap_.erase(it);
282+ } else {
283+ ++it;
284+ }
261 285 
262 if (count >= blobRebuildSendMaxCount || it == end) {286 if (count >= blobRebuildSendMaxCount || it == end) {
263 MMC_LOG_INFO("mmc meta blob rebuild count " << req.blobList_.size());287 MMC_LOG_INFO("mmc meta blob rebuild count " << req.blobList_.size());
@@ -282,12 +306,15 @@ Result MmcLocalServiceDefault::InitUbsIo(int32_t deviceId, const std::string &co
282 "metaNetClient_ not ready when registering UBS IO callback", MMC_NOT_INITIALIZED);306 "metaNetClient_ not ready when registering UBS IO callback", MMC_NOT_INITIALIZED);
283 ubsIoProxyPtr_ = ubsIoProxy;307 ubsIoProxyPtr_ = ubsIoProxy;
284 308 
285- // Register UBS IO metadata event callback (before InitUbsIo to avoid missing recovery events)
286 ubsIoProxy->SetMetaEventCallback([this](int type, const std::vector<std::string> &keys) {309 ubsIoProxy->SetMetaEventCallback([this](int type, const std::vector<std::string> &keys) {
287 ubsioEventPool_->Enqueue([this, type, keys]() { HandleUbsIoMetaEvents(type, keys); });310 ubsioEventPool_->Enqueue([this, type, keys]() { HandleUbsIoMetaEvents(type, keys); });
288 });311 });
289 312 
290- return ubsIoProxy->InitUbsIo(deviceId, confPath);313+ auto ret = ubsIoProxy->InitUbsIo(deviceId, confPath);
314+ if (ret != MMC_OK) {
315+ ubsIoProxy->SetMetaEventCallback(nullptr);
316+ }
317+ return ret;
291}318}
292 319 
293Result MmcLocalServiceDefault::UpdateMetaBackup(const std::vector<uint32_t> &ops, const std::vector<std::string> &keys,320Result MmcLocalServiceDefault::UpdateMetaBackup(const std::vector<uint32_t> &ops, const std::vector<std::string> &keys,
@@ -146,11 +146,13 @@ static BlobClassification ClassifyBlobs(const MmcMemObjMetaPtr &objMeta, MmcBlob
146}146}
147 147 
148static Result WaitPendingRewarm(const std::string &key, MmcMemBlobPtr &selectedBlob, const MmcMemBlobPtr &pendingBlob,148static Result WaitPendingRewarm(const std::string &key, MmcMemBlobPtr &selectedBlob, const MmcMemBlobPtr &pendingBlob,
149- const MmcMemBlobPtr &lowerBlob, std::unique_lock<std::mutex> &guard, int waitMs)149+ const MmcMemBlobPtr &lowerBlob, std::unique_lock<std::mutex> &guard,
150+ const MmcMetaExtConfig &extConfig)
150{151{
151- MMC_LOG_DEBUG("rewarm in progress for key " << key << ", waiting " << waitMs << "ms");152+ auto timeout = std::chrono::milliseconds(extConfig.pendingWaitTimeoutMs);
153+ MMC_LOG_DEBUG("rewarm in progress for key " << key << ", waiting " << timeout.count() << "ms");
152 TP_TRACE_BEGIN(TP_MMC_META_GET_WAIT_REWARM);154 TP_TRACE_BEGIN(TP_MMC_META_GET_WAIT_REWARM);
153- bool waitOk = pendingBlob->WaitUntilReadable(guard, std::chrono::milliseconds(waitMs));155+ bool waitOk = pendingBlob->WaitUntilReadable(guard, timeout);
154 TP_TRACE_END(TP_MMC_META_GET_WAIT_REWARM, waitOk ? MMC_OK : MMC_TIMEOUT);156 TP_TRACE_END(TP_MMC_META_GET_WAIT_REWARM, waitOk ? MMC_OK : MMC_TIMEOUT);
155 if (!waitOk) {157 if (!waitOk) {
156 MMC_LOG_ERROR("rewarm wait timeout for key " << key);158 MMC_LOG_ERROR("rewarm wait timeout for key " << key);
@@ -207,8 +209,6 @@ Result MmcMetaManager::TryRewarmForGet(const std::string &key, uint64_t operateI
207Result MmcMetaManager::ResolveAndFillMetaDesc(const std::string &key, uint64_t operateId, MmcBlobFilterPtr filterPtr,209Result MmcMetaManager::ResolveAndFillMetaDesc(const std::string &key, uint64_t operateId, MmcBlobFilterPtr filterPtr,
208 const MmcMemObjMetaPtr &memObj, MmcMemMetaDesc &objMeta)210 const MmcMemObjMetaPtr &memObj, MmcMemMetaDesc &objMeta)
209{211{
210- constexpr int rewarmWaitMs = 500;
211- 
212 MMC_LOG_DEBUG("ResolveAndFillMetaDesc key=" << key);212 MMC_LOG_DEBUG("ResolveAndFillMetaDesc key=" << key);
213 213 
214 std::unique_lock<std::mutex> guard(memObj->Mutex());214 std::unique_lock<std::mutex> guard(memObj->Mutex());
@@ -222,7 +222,7 @@ Result MmcMetaManager::ResolveAndFillMetaDesc(const std::string &key, uint64_t o
222 }222 }
223 223 
224 if (selectedBlob == nullptr && pendingBlob != nullptr && lowerBlob != nullptr) {224 if (selectedBlob == nullptr && pendingBlob != nullptr && lowerBlob != nullptr) {
225- auto waitRet = WaitPendingRewarm(key, selectedBlob, pendingBlob, lowerBlob, guard, rewarmWaitMs);225+ auto waitRet = WaitPendingRewarm(key, selectedBlob, pendingBlob, lowerBlob, guard, extConfig_);
226 if (waitRet != MMC_OK) {226 if (waitRet != MMC_OK) {
227 return waitRet;227 return waitRet;
228 }228 }
@@ -245,6 +245,15 @@ Result MmcMetaManager::ResolveAndFillMetaDesc(const std::string &key, uint64_t o
245 }245 }
246 }246 }
247 247 
248+ if (selectedBlob == nullptr) {
249+ MMC_LOG_WARN("Get: no blob available for key " << key);
250+ objMeta.prot_ = memObj->Prot();
251+ objMeta.priority_ = memObj->Priority();
252+ objMeta.size_ = memObj->Size();
253+ objMeta.numBlobs_ = 0;
254+ return MMC_OK;
255+ }
256+ 
248 objMeta.prot_ = memObj->Prot();257 objMeta.prot_ = memObj->Prot();
249 objMeta.priority_ = memObj->Priority();258 objMeta.priority_ = memObj->Priority();
250 objMeta.size_ = memObj->Size();259 objMeta.size_ = memObj->Size();
@@ -274,74 +283,37 @@ Result MmcMetaManager::GetByRank(const std::vector<std::string> &keys, uint64_t
274 uint32_t opRankId = GetRankIdByOperateId(operateId);283 uint32_t opRankId = GetRankIdByOperateId(operateId);
275 uint32_t opSeq = GetSequenceByOperateId(operateId);284 uint32_t opSeq = GetSequenceByOperateId(operateId);
276 285 
286+ CheckAndEvict(MEDIA_DRAM, 0);
287+ 
277 std::map<uint32_t, std::vector<RewarmEntry>> rankGroups;288 std::map<uint32_t, std::vector<RewarmEntry>> rankGroups;
278 std::vector<PendingRewarmWait> pendingWaitList;289 std::vector<PendingRewarmWait> pendingWaitList;
290+ std::vector<DeferredLockEntry> deferredLockList;
279 TP_TRACE_BEGIN(TP_MMC_META_BATCH_GET_CLASSIFY);291 TP_TRACE_BEGIN(TP_MMC_META_BATCH_GET_CLASSIFY);
280- ClassifyAndGroupKeys(keys, opRankId, opSeq, objMetas, rankGroups, pendingWaitList);292+ ClassifyAndGroupKeys(keys, opRankId, opSeq, objMetas, rankGroups, pendingWaitList, deferredLockList);
281 TP_TRACE_END(TP_MMC_META_BATCH_GET_CLASSIFY, MMC_OK);293 TP_TRACE_END(TP_MMC_META_BATCH_GET_CLASSIFY, MMC_OK);
282 294 
295+ // 先异步提交 rewarm/pendingWait,后台启动 RPC;主线程同步给 selectedBlob 加读锁,两者并行缩小时隙
283 std::vector<std::future<void>> futures;296 std::vector<std::future<void>> futures;
284- if (!rankGroups.empty() || !pendingWaitList.empty()) {297+ for (auto &[rank, group] : rankGroups) {
285- TP_TRACE_BEGIN(TP_MMC_META_BATCH_GET_REWARM_WAIT);298+ futures.push_back(rewarmThreadPool_->Enqueue([this, rank, &group, &keys, opRankId, opSeq, &objMetas]() {
286- for (auto &[rank, group] : rankGroups) {299+ RewarmRankGroup(rank, group, keys, opRankId, opSeq, objMetas);
287- futures.push_back(rewarmThreadPool_->Enqueue([this, rank, &group, &keys, opRankId, opSeq, &objMetas]() {300+ }));
288- RewarmRankGroup(rank, group, keys, opRankId, opSeq, objMetas);301+ }
289- }));302+ for (auto &w : pendingWaitList) {
290- }303+ futures.push_back(rewarmThreadPool_->Enqueue([this, &keys, opRankId, opSeq, &objMetas, &w]() {
291- 304+ PendingWaitAndFill(keys, opRankId, opSeq, objMetas, w);
292- for (auto &w : pendingWaitList) {305+ }));
293- futures.push_back(rewarmThreadPool_->Enqueue([this, &keys, opRankId, opSeq, &objMetas, &w]() {
294- PendingWaitAndFill(keys, opRankId, opSeq, objMetas, w);
295- }));
296- }
297- 
298- for (auto &f : futures) {
299- try {
300- f.get();
301- } catch (const std::exception &e) {
302- MMC_LOG_WARN("GetByRank future failed: " << e.what());
303- }
304- }
305- TP_TRACE_END(TP_MMC_META_BATCH_GET_REWARM_WAIT, MMC_OK);
306 }306 }
307 307 
308- size_t metaCount = objMetas.size();308+ AttachReadLocks(keys, opRankId, opSeq, objMetas, deferredLockList);
309- TP_TRACE_BEGIN(TP_MMC_META_BATCH_GET_READ_START);309+ 
310- for (size_t i = 0; i < keys.size() && i < metaCount; ++i) {310+ for (auto &f : futures) {
311- auto &objMeta = objMetas[i];311+ try {
312- if (objMeta.numBlobs_ == 0 || objMeta.blobs_.empty()) {312+ f.get();
313- continue;313+ } catch (const std::exception &e) {
314- }314+ MMC_LOG_WARN("GetByRank future failed: " << e.what());
315- MmcMemObjMetaPtr memObj;
316- if (metaContainer_->Get(keys[i], memObj) != MMC_OK || memObj == nullptr) {
317- MMC_LOG_WARN("GetByRank: deferred READ_START memObj not found for key=" << keys[i]);
318- objMeta.blobs_.clear();
319- objMeta.numBlobs_ = 0;
320- continue;
321- }
322- {
323- std::unique_lock<std::mutex> guard(memObj->Mutex());
324- for (auto &desc : objMeta.blobs_) {
325- MmcBlobFilterPtr filter =
326- MmcMakeRef<MmcBlobFilter>(desc.rank_, static_cast<MediaType>(desc.mediaType_), READABLE);
327- auto blobs = memObj->GetBlobs(filter);
328- if (blobs.empty()) {
329- MMC_LOG_WARN("GetByRank: deferred READ_START blob not found for key=" << keys[i]);
330- objMeta.blobs_.clear();
331- objMeta.numBlobs_ = 0;
332- break;
333- }
334- auto ret = blobs[0]->UpdateState(keys[i], opRankId, opSeq, MMC_READ_START);
335- if (ret != MMC_OK) {
336- MMC_LOG_WARN("GetByRank: deferred READ_START failed for key=" << keys[i] << ", ret=" << ret);
337- objMeta.blobs_.clear();
338- objMeta.numBlobs_ = 0;
339- break;
340- }
341- }
342 }315 }
343 }316 }
344- TP_TRACE_END(TP_MMC_META_BATCH_GET_READ_START, MMC_OK);
345 317 
346 return MMC_OK;318 return MMC_OK;
347}319}
@@ -349,7 +321,8 @@ Result MmcMetaManager::GetByRank(const std::vector<std::string> &keys, uint64_t
349void MmcMetaManager::ClassifyAndGroupKeys(const std::vector<std::string> &keys, uint32_t opRankId, uint32_t opSeq,321void MmcMetaManager::ClassifyAndGroupKeys(const std::vector<std::string> &keys, uint32_t opRankId, uint32_t opSeq,
350 std::vector<MmcMemMetaDesc> &objMetas,322 std::vector<MmcMemMetaDesc> &objMetas,
351 std::map<uint32_t, std::vector<RewarmEntry>> &rankGroups,323 std::map<uint32_t, std::vector<RewarmEntry>> &rankGroups,
352- std::vector<PendingRewarmWait> &pendingWaitList)324+ std::vector<PendingRewarmWait> &pendingWaitList,
325+ std::vector<DeferredLockEntry> &deferredLockList)
353{326{
354 size_t keyCount = keys.size();327 size_t keyCount = keys.size();
355 328 
@@ -395,11 +368,8 @@ void MmcMetaManager::ClassifyAndGroupKeys(const std::vector<std::string> &keys,
395 368 
396 if (selectedBlob != nullptr) {369 if (selectedBlob != nullptr) {
397 MmcMetaMetricManager::GetInstance().IncrementGetHitDramCounter(selectedBlob->GetDesc().rank_);370 MmcMetaMetricManager::GetInstance().IncrementGetHitDramCounter(selectedBlob->GetDesc().rank_);
398- objMetas[i].prot_ = memObj->Prot();371+ objMetas[i].FillFrom(memObj, selectedBlob);
399- objMetas[i].priority_ = memObj->Priority();372+ deferredLockList.push_back({i, memObj});
400- objMetas[i].size_ = memObj->Size();
401- objMetas[i].blobs_.push_back(selectedBlob->GetDesc());
402- objMetas[i].numBlobs_ = 1;
403 } else if (pendingBlob != nullptr) {373 } else if (pendingBlob != nullptr) {
404 // rewarm already in progress by another thread, wait concurrently374 // rewarm already in progress by another thread, wait concurrently
405 pendingWaitList.push_back({i, memObj, pendingBlob});375 pendingWaitList.push_back({i, memObj, pendingBlob});
@@ -408,11 +378,8 @@ void MmcMetaManager::ClassifyAndGroupKeys(const std::vector<std::string> &keys,
408 MediaType dstMedia = MoveUp(srcMedia);378 MediaType dstMedia = MoveUp(srcMedia);
409 if (dstMedia == MEDIA_HBM || dstMedia == MEDIA_NONE) {379 if (dstMedia == MEDIA_HBM || dstMedia == MEDIA_NONE) {
410 MmcMetaMetricManager::GetInstance().IncrementGetHitDramCounter(lowerBlob->GetDesc().rank_);380 MmcMetaMetricManager::GetInstance().IncrementGetHitDramCounter(lowerBlob->GetDesc().rank_);
411- objMetas[i].prot_ = memObj->Prot();381+ objMetas[i].FillFrom(memObj, lowerBlob);
412- objMetas[i].priority_ = memObj->Priority();382+ deferredLockList.push_back({i, memObj});
413- objMetas[i].size_ = memObj->Size();
414- objMetas[i].blobs_.push_back(lowerBlob->GetDesc());
415- objMetas[i].numBlobs_ = 1;
416 } else {383 } else {
417 auto readRet = lowerBlob->UpdateState(keys[i], opRankId, opSeq, MMC_READ_START);384 auto readRet = lowerBlob->UpdateState(keys[i], opRankId, opSeq, MMC_READ_START);
418 if (readRet != MMC_OK) {385 if (readRet != MMC_OK) {
@@ -438,6 +405,18 @@ void MmcMetaManager::ClassifyAndGroupKeys(const std::vector<std::string> &keys,
438 continue;405 continue;
439 }406 }
440 newBlobs[0]->SetRewarmOrigin();407 newBlobs[0]->SetRewarmOrigin();
408+ auto statusRet = newBlobs[0]->UpdateState(keys[i], lowerBlob->GetDesc().rank_, 0, MMC_ALLOCATED_OK);
409+ if (statusRet != MMC_OK) {
410+ MMC_LOG_WARN("key: " << keys[i] << " rewarm ALLOCATED_OK failed, ret: " << statusRet);
411+ globalAllocator_->Free(newBlobs);
412+ auto finishRet = lowerBlob->UpdateState(keys[i], opRankId, opSeq, MMC_READ_FINISH);
413+ if (finishRet != MMC_OK) {
414+ MMC_LOG_WARN("key: " << keys[i]
415+ << " READ_FINISH rollback after ALLOCATED_OK fail, ret: " << finishRet);
416+ }
417+ MmcMetaMetricManager::GetInstance().IncrementRewarmFailCounter(lowerBlob->GetDesc().rank_);
418+ continue;
419+ }
441 auto addRet = memObj->AddBlob(newBlobs[0]);420 auto addRet = memObj->AddBlob(newBlobs[0]);
442 if (addRet != MMC_OK) {421 if (addRet != MMC_OK) {
443 MMC_LOG_WARN("key: " << keys[i] << " rewarm AddBlob failed, ret: " << addRet);422 MMC_LOG_WARN("key: " << keys[i] << " rewarm AddBlob failed, ret: " << addRet);
@@ -450,7 +429,6 @@ void MmcMetaManager::ClassifyAndGroupKeys(const std::vector<std::string> &keys,
450 MmcMetaMetricManager::GetInstance().IncrementRewarmFailCounter(lowerBlob->GetDesc().rank_);429 MmcMetaMetricManager::GetInstance().IncrementRewarmFailCounter(lowerBlob->GetDesc().rank_);
451 continue;430 continue;
452 }431 }
453- // 与 FreeBlobs 的 DecrementRewarmBytesCurrent 配对,否则量表下溢
454 MmcMetaMetricManager::GetInstance().IncrementRewarmBytesCurrent(newBlobs[0]->Size(),432 MmcMetaMetricManager::GetInstance().IncrementRewarmBytesCurrent(newBlobs[0]->Size(),
455 newBlobs[0]->GetDesc().rank_);433 newBlobs[0]->GetDesc().rank_);
456 RewarmEntry entry;434 RewarmEntry entry;
@@ -539,6 +517,19 @@ Result MmcMetaManager::ApplyRewarm(const std::string &key, RewarmEntry &entry, M
539 return ret;517 return ret;
540 }518 }
541 519 
520+ auto readStartRet = dstBlob->UpdateState(key, ctx.opRankId, ctx.opSeq, MMC_READ_START);
521+ if (readStartRet != MMC_OK) {
522+ MMC_LOG_WARN("READ_START failed after rewarm, key=" << key << ", ret=" << readStartRet);
523+ MmcBlobFilterPtr rbFilter = MmcMakeRef<MmcBlobFilter>(dstBlob->GetDesc().rank_, ctx.dstMedia, NONE);
524+ entry.memObj->FreeBlobs(key, globalAllocator_, rbFilter, false);
525+ auto finishRet = entry.ssdBlob->UpdateState(key, entry.opRankId, entry.opSeq, MMC_READ_FINISH);
526+ if (finishRet != MMC_OK) {
527+ MMC_LOG_WARN("Failed to release SSD read lease after READ_START failed, key=" << key
528+ << ", ret=" << finishRet);
529+ }
530+ return readStartRet;
531+ }
532+ 
542 // 保留源 SSD blob 作为冗余副本,若 DRAM 被淘汰则无需重复 CopyBlob533 // 保留源 SSD blob 作为冗余副本,若 DRAM 被淘汰则无需重复 CopyBlob
543 objMeta.prot_ = entry.memObj->Prot();534 objMeta.prot_ = entry.memObj->Prot();
544 objMeta.priority_ = entry.memObj->Priority();535 objMeta.priority_ = entry.memObj->Priority();
@@ -615,21 +606,55 @@ void MmcMetaManager::RewarmRankGroup(uint32_t rank, std::vector<RewarmEntry> &gr
615 MMC_LOG_DEBUG("finalized " << okCnt << "/" << groupSize << " keys for rank=" << rank);606 MMC_LOG_DEBUG("finalized " << okCnt << "/" << groupSize << " keys for rank=" << rank);
616}607}
617 608 
609+void MmcMetaManager::AttachReadLocks(const std::vector<std::string> &keys, uint32_t opRankId, uint32_t opSeq,
610+ std::vector<MmcMemMetaDesc> &objMetas,
611+ std::vector<DeferredLockEntry> &deferredLockList)
612+{
613+ TP_TRACE_BEGIN(TP_MMC_META_BATCH_GET_READ_START);
614+ for (auto &entry : deferredLockList) {
615+ auto &objMeta = objMetas[entry.index];
616+ if (objMeta.numBlobs_ == 0 || objMeta.blobs_.empty()) {
617+ continue;
618+ }
619+ std::unique_lock<std::mutex> guard(entry.memObj->Mutex());
620+ for (auto &desc : objMeta.blobs_) {
621+ MmcBlobFilterPtr filter =
622+ MmcMakeRef<MmcBlobFilter>(desc.rank_, static_cast<MediaType>(desc.mediaType_), READABLE);
623+ auto blobs = entry.memObj->GetBlobs(filter);
624+ if (blobs.empty()) {
625+ MMC_LOG_WARN("GetByRank: deferred READ_START blob not found for key=" << keys[entry.index]);
626+ objMeta.blobs_.clear();
627+ objMeta.numBlobs_ = 0;
628+ break;
629+ }
630+ auto ret = blobs[0]->UpdateState(keys[entry.index], opRankId, opSeq, MMC_READ_START);
631+ if (ret != MMC_OK) {
632+ MMC_LOG_WARN("GetByRank: deferred READ_START failed for key=" << keys[entry.index] << ", ret=" << ret);
633+ objMeta.blobs_.clear();
634+ objMeta.numBlobs_ = 0;
635+ break;
636+ }
637+ }
638+ }
639+ TP_TRACE_END(TP_MMC_META_BATCH_GET_READ_START, MMC_OK);
640+}
641+ 
618void MmcMetaManager::PendingWaitAndFill(const std::vector<std::string> &keys, uint32_t opRankId, uint32_t opSeq,642void MmcMetaManager::PendingWaitAndFill(const std::vector<std::string> &keys, uint32_t opRankId, uint32_t opSeq,
619 std::vector<MmcMemMetaDesc> &objMetas, PendingRewarmWait &w)643 std::vector<MmcMemMetaDesc> &objMetas, PendingRewarmWait &w)
620{644{
621- static constexpr auto kPendingWaitTimeout = std::chrono::milliseconds(300);645+ auto timeout = std::chrono::milliseconds(extConfig_.pendingWaitTimeoutMs);
622 std::unique_lock<std::mutex> guard(w.memObj->Mutex());646 std::unique_lock<std::mutex> guard(w.memObj->Mutex());
623 if (w.pendingBlob->State() != READABLE) {647 if (w.pendingBlob->State() != READABLE) {
624- w.pendingBlob->WaitUntilReadable(guard, kPendingWaitTimeout);648+ w.pendingBlob->WaitUntilReadable(guard, timeout);
625 }649 }
626 650 
627 if (w.pendingBlob->State() == READABLE) {651 if (w.pendingBlob->State() == READABLE) {
628- objMetas[w.index].prot_ = w.memObj->Prot();652+ auto readStartRet = w.pendingBlob->UpdateState(keys[w.index], opRankId, opSeq, MMC_READ_START);
629- objMetas[w.index].priority_ = w.memObj->Priority();653+ if (readStartRet != MMC_OK) {
630- objMetas[w.index].size_ = w.memObj->Size();654+ MMC_LOG_WARN("key: " << keys[w.index] << " READ_START failed after pending rewarm, ret=" << readStartRet);
631- objMetas[w.index].blobs_.push_back(w.pendingBlob->GetDesc());655+ return;
632- objMetas[w.index].numBlobs_ = 1;656+ }
657+ objMetas[w.index].FillFrom(w.memObj, w.pendingBlob);
633 MmcMetaMetricManager::GetInstance().IncrementGetHitDramCounter(w.pendingBlob->GetDesc().rank_);658 MmcMetaMetricManager::GetInstance().IncrementGetHitDramCounter(w.pendingBlob->GetDesc().rank_);
634 } else {659 } else {
635 MMC_LOG_WARN("key: " << keys[w.index] << " pending rewarm timeout or state not readable, state="660 MMC_LOG_WARN("key: " << keys[w.index] << " pending rewarm timeout or state not readable, state="
@@ -82,6 +82,16 @@ struct MmcMemMetaDesc {
82 }82 }
83 }83 }
84 84 
85+ void FillFrom(const MmcMemObjMetaPtr &memObj, const MmcMemBlobPtr &blob)
86+ {
87+ prot_ = memObj->Prot();
88+ priority_ = memObj->Priority();
89+ size_ = memObj->Size();
90+ blobs_.clear();
91+ blobs_.push_back(blob->GetDesc());
92+ numBlobs_ = static_cast<uint8_t>(blobs_.size());
93+ }
94+ 
85 uint16_t Prot()95 uint16_t Prot()
86 {96 {
87 return prot_;97 return prot_;
@@ -105,6 +115,7 @@ struct MmcMemMetaDesc {
105 115 
106struct MmcMetaExtConfig {116struct MmcMetaExtConfig {
107 bool prefetchEnabled = false;117 bool prefetchEnabled = false;
118+ uint64_t pendingWaitTimeoutMs = 300U;
108};119};
109 120 
110class MmcMetaManager : public MmcReferable {121class MmcMetaManager : public MmcReferable {
@@ -425,6 +436,11 @@ private:
425 MmcMemBlobPtr pendingBlob;436 MmcMemBlobPtr pendingBlob;
426 };437 };
427 438 
439+ struct DeferredLockEntry {
440+ size_t index;
441+ MmcMemObjMetaPtr memObj;
442+ };
443+ 
428 struct BatchRpcData {444 struct BatchRpcData {
429 std::vector<std::string> keys;445 std::vector<std::string> keys;
430 std::vector<MmcMemBlobDesc> srcBlobs;446 std::vector<MmcMemBlobDesc> srcBlobs;
@@ -442,11 +458,15 @@ private:
442 void ClassifyAndGroupKeys(const std::vector<std::string> &keys, uint32_t opRankId, uint32_t opSeq,458 void ClassifyAndGroupKeys(const std::vector<std::string> &keys, uint32_t opRankId, uint32_t opSeq,
443 std::vector<MmcMemMetaDesc> &objMetas,459 std::vector<MmcMemMetaDesc> &objMetas,
444 std::map<uint32_t, std::vector<RewarmEntry>> &rankGroups,460 std::map<uint32_t, std::vector<RewarmEntry>> &rankGroups,
445- std::vector<PendingRewarmWait> &pendingWaitList);461+ std::vector<PendingRewarmWait> &pendingWaitList,
462+ std::vector<DeferredLockEntry> &deferredLockList);
446 463 
447 void RewarmRankGroup(uint32_t rank, std::vector<RewarmEntry> &group, const std::vector<std::string> &keys,464 void RewarmRankGroup(uint32_t rank, std::vector<RewarmEntry> &group, const std::vector<std::string> &keys,
448 uint32_t opRankId, uint32_t opSeq, std::vector<MmcMemMetaDesc> &objMetas);465 uint32_t opRankId, uint32_t opSeq, std::vector<MmcMemMetaDesc> &objMetas);
449 466 
467+ void AttachReadLocks(const std::vector<std::string> &keys, uint32_t opRankId, uint32_t opSeq,
468+ std::vector<MmcMemMetaDesc> &objMetas, std::vector<DeferredLockEntry> &deferredLockList);
469+ 
450 void PendingWaitAndFill(const std::vector<std::string> &keys, uint32_t opRankId, uint32_t opSeq,470 void PendingWaitAndFill(const std::vector<std::string> &keys, uint32_t opRankId, uint32_t opSeq,
451 std::vector<MmcMemMetaDesc> &objMetas, PendingRewarmWait &w);471 std::vector<MmcMemMetaDesc> &objMetas, PendingRewarmWait &w);
452 472 
@@ -81,6 +81,7 @@ Result MmcMetaService::Start(const mmc_meta_service_config_t &options)
81 metaMgrProxy_ = MmcMakeRef<MmcMetaMgrProxy>(metaNetServer_).Get();81 metaMgrProxy_ = MmcMakeRef<MmcMetaMgrProxy>(metaNetServer_).Get();
82 MmcMetaExtConfig extConfig{};82 MmcMetaExtConfig extConfig{};
83 extConfig.prefetchEnabled = options.prefetchEnabled;83 extConfig.prefetchEnabled = options.prefetchEnabled;
84+ extConfig.pendingWaitTimeoutMs = options.pendingWaitTimeoutMs;
84 MMC_RETURN_ERROR(metaMgrProxy_->Start(options_.leaseTtlMs, options.evictThresholdHigh, options.evictThresholdLow,85 MMC_RETURN_ERROR(metaMgrProxy_->Start(options_.leaseTtlMs, options.evictThresholdHigh, options.evictThresholdLow,
85 options.rewarmDramWatermark, extConfig),86 options.rewarmDramWatermark, extConfig),
86 "Failed to start meta mgr proxy of meta service " << name_);87 "Failed to start meta mgr proxy of meta service " << name_);
@@ -48,6 +48,7 @@ mmc_meta_service_config_t create_default_meta_config()
48 config.evictThresholdLow = 80U;48 config.evictThresholdLow = 80U;
49 config.rewarmDramWatermark = DEFAULT_REWARM_HIGH_WATERMARK;49 config.rewarmDramWatermark = DEFAULT_REWARM_HIGH_WATERMARK;
50 config.prefetchEnabled = false;50 config.prefetchEnabled = false;
51+ config.pendingWaitTimeoutMs = 300U;
51 config.leaseTtlMs = MMC_DATA_TTL_MS;52 config.leaseTtlMs = MMC_DATA_TTL_MS;
52 config.accTlsConfig.tlsEnable = false;53 config.accTlsConfig.tlsEnable = false;
53 config.configStoreTlsConfig.tlsEnable = false;54 config.configStoreTlsConfig.tlsEnable = false;
@@ -460,6 +460,7 @@ MMC_API int32_t mmcc_batch_get(const char **keys, uint32_t keys_count, mmc_buffe
460 MMC_VALIDATE_RETURN(keys != nullptr, "invalid param, keys is null", MMC_INVALID_PARAM);460 MMC_VALIDATE_RETURN(keys != nullptr, "invalid param, keys is null", MMC_INVALID_PARAM);
461 MMC_VALIDATE_RETURN(keys_count != 0, "invalid param, keys_count: " << keys_count, MMC_INVALID_PARAM);461 MMC_VALIDATE_RETURN(keys_count != 0, "invalid param, keys_count: " << keys_count, MMC_INVALID_PARAM);
462 MMC_VALIDATE_RETURN(bufs != nullptr, "invalid param, bufs is null", MMC_INVALID_PARAM);462 MMC_VALIDATE_RETURN(bufs != nullptr, "invalid param, bufs is null", MMC_INVALID_PARAM);
463+ MMC_VALIDATE_RETURN(results != nullptr, "invalid param, results is null", MMC_INVALID_PARAM);
463 MMC_VALIDATE_RETURN(MmcClientDefault::GetInstance() != nullptr, "client is not initialize", MMC_CLIENT_NOT_INIT);464 MMC_VALIDATE_RETURN(MmcClientDefault::GetInstance() != nullptr, "client is not initialize", MMC_CLIENT_NOT_INIT);
464 465 
465 std::vector<std::string> keys_vector;466 std::vector<std::string> keys_vector;
@@ -495,6 +496,7 @@ MMC_API int32_t mmcc_batch_put(const char **keys, uint32_t keys_count, const mmc
495 MMC_VALIDATE_RETURN(keys != nullptr, "invalid param, keys is null", MMC_INVALID_PARAM);496 MMC_VALIDATE_RETURN(keys != nullptr, "invalid param, keys is null", MMC_INVALID_PARAM);
496 MMC_VALIDATE_RETURN(keys_count != 0, "invalid param, keys_count: " << keys_count, MMC_INVALID_PARAM);497 MMC_VALIDATE_RETURN(keys_count != 0, "invalid param, keys_count: " << keys_count, MMC_INVALID_PARAM);
497 MMC_VALIDATE_RETURN(bufs != nullptr, "invalid param, bufs is null", MMC_INVALID_PARAM);498 MMC_VALIDATE_RETURN(bufs != nullptr, "invalid param, bufs is null", MMC_INVALID_PARAM);
499+ MMC_VALIDATE_RETURN(results != nullptr, "invalid param, results is null", MMC_INVALID_PARAM);
498 MMC_VALIDATE_RETURN(MmcClientDefault::GetInstance() != nullptr, "client is not initialize", MMC_CLIENT_NOT_INIT);500 MMC_VALIDATE_RETURN(MmcClientDefault::GetInstance() != nullptr, "client is not initialize", MMC_CLIENT_NOT_INIT);
499 501 
500 std::vector<std::string> keys_vector;502 std::vector<std::string> keys_vector;
@@ -914,6 +914,10 @@ std::vector<mmc_buffer> MmcacheStore::GetBatch(const std::vector<std::string> &k
914 914 
915 // 1. Query KeyInfo for all keys915 // 1. Query KeyInfo for all keys
916 auto keyInfos = BatchGetKeyInfo(keys);916 auto keyInfos = BatchGetKeyInfo(keys);
917+ if (keyInfos.size() != count) {
918+ MMC_LOG_ERROR("BatchGetKeyInfo returned " << keyInfos.size() << " results, expected " << count);
919+ return {};
920+ }
917 921 
918 // 2. alloc memory and assign value to the buffers922 // 2. alloc memory and assign value to the buffers
919 for (size_t i = 0; i < count; ++i) {923 for (size_t i = 0; i < count; ++i) {
@@ -929,7 +933,7 @@ std::vector<mmc_buffer> MmcacheStore::GetBatch(const std::vector<std::string> &k
929 buffers[j].len = 0;933 buffers[j].len = 0;
930 }934 }
931 MMC_LOG_ERROR("Failed to allocate dynamic memory for key: " << keys[i].c_str());935 MMC_LOG_ERROR("Failed to allocate dynamic memory for key: " << keys[i].c_str());
932- return buffers;936+ return {};
933 }937 }
934 buffers[i] = {938 buffers[i] = {
935 .addr = reinterpret_cast<uint64_t>(dataPtr),939 .addr = reinterpret_cast<uint64_t>(dataPtr),
@@ -942,7 +946,23 @@ std::vector<mmc_buffer> MmcacheStore::GetBatch(const std::vector<std::string> &k
942 TP_TRACE_BEGIN(TP_MMC_PY_BATCH_GET);946 TP_TRACE_BEGIN(TP_MMC_PY_BATCH_GET);
943 auto ret = mmcc_batch_get(keyArray.data(), count, buffers.data(), 0, results.data());947 auto ret = mmcc_batch_get(keyArray.data(), count, buffers.data(), 0, results.data());
944 TP_TRACE_END(TP_MMC_PY_BATCH_GET, ret);948 TP_TRACE_END(TP_MMC_PY_BATCH_GET, ret);
945- (void)ret;949+ if (ret != MMC_OK) {
950+ for (size_t i = 0; i < count; ++i) {
951+ auto tmpPtr = reinterpret_cast<char *>(buffers[i].addr);
952+ delete[] tmpPtr;
953+ buffers[i] = {0, 0, 0, 0};
954+ }
955+ MMC_LOG_ERROR("mmcc_batch_get failed, ret=" << ret);
956+ return {};
957+ }
958+ // 4. zero out buffers for individually failed keys
959+ for (size_t i = 0; i < count; ++i) {
960+ if (results[i] != MMC_OK) {
961+ auto tmpPtr = reinterpret_cast<char *>(buffers[i].addr);
962+ delete[] tmpPtr;
963+ buffers[i] = {0, 0, 0, 0};
964+ }
965+ }
946 return buffers;966 return buffers;
947}967}
948 968 
@@ -20,7 +20,7 @@ namespace mmc {
20bool DlUbsioApi::gLoaded = false;20bool DlUbsioApi::gLoaded = false;
21std::mutex DlUbsioApi::gMutex;21std::mutex DlUbsioApi::gMutex;
22void *DlUbsioApi::ubsioHandle = nullptr;22void *DlUbsioApi::ubsioHandle = nullptr;
23-const std::string DlUbsioApi::gUbsioLibName = "libubsio_kvc.so";23+const std::string DlUbsioApi::gUbsioLibName = "libubsio_kvc.so.1";
24 24 
25ubsio_client_initFunc DlUbsioApi::pUbsioClientInit = nullptr;25ubsio_client_initFunc DlUbsioApi::pUbsioClientInit = nullptr;
26ubsio_putFunc DlUbsioApi::pUbsioPut = nullptr;26ubsio_putFunc DlUbsioApi::pUbsioPut = nullptr;
@@ -36,6 +36,7 @@ ubsio_batch_deleteFunc DlUbsioApi::pUbsioBatchDelete = nullptr;
36ubsio_batch_get_lengthFunc DlUbsioApi::pUbsioBatchGetLength = nullptr;36ubsio_batch_get_lengthFunc DlUbsioApi::pUbsioBatchGetLength = nullptr;
37ubsio_batch_free_addressFunc DlUbsioApi::pUbsioBatchFreeAddress = nullptr;37ubsio_batch_free_addressFunc DlUbsioApi::pUbsioBatchFreeAddress = nullptr;
38ubsio_register_meta_event_callbackFunc DlUbsioApi::pUbsioRegisterMetaEventCallback = nullptr;38ubsio_register_meta_event_callbackFunc DlUbsioApi::pUbsioRegisterMetaEventCallback = nullptr;
39+ubsio_kv_cache_exitFunc DlUbsioApi::pUbsioKvCacheExit = nullptr;
39ubsio_get_resource_infoFunc DlUbsioApi::pUbsioGetResourceInfo = nullptr;40ubsio_get_resource_infoFunc DlUbsioApi::pUbsioGetResourceInfo = nullptr;
40 41 
41Result DlUbsioApi::UbsioClientInit(int32_t deviceId, const std::string &confPath)42Result DlUbsioApi::UbsioClientInit(int32_t deviceId, const std::string &confPath)
@@ -83,6 +84,7 @@ Result DlUbsioApi::LoadLibrary()
83 DL_LOAD_SYM(pUbsioBatchFreeAddress, ubsio_batch_free_addressFunc, ubsioHandle, "UbsioKvCacheBatchFree");84 DL_LOAD_SYM(pUbsioBatchFreeAddress, ubsio_batch_free_addressFunc, ubsioHandle, "UbsioKvCacheBatchFree");
84 DL_LOAD_SYM(pUbsioRegisterMetaEventCallback, ubsio_register_meta_event_callbackFunc, ubsioHandle,85 DL_LOAD_SYM(pUbsioRegisterMetaEventCallback, ubsio_register_meta_event_callbackFunc, ubsioHandle,
85 "UbsioKvCacheRegisterMetaEventCallback");86 "UbsioKvCacheRegisterMetaEventCallback");
87+ DL_LOAD_SYM(pUbsioKvCacheExit, ubsio_kv_cache_exitFunc, ubsioHandle, "UbsioKvCacheExit");
86 DlLoadSymOptional(pUbsioGetResourceInfo, ubsioHandle, "UbsioGetResourceInfo");88 DlLoadSymOptional(pUbsioGetResourceInfo, ubsioHandle, "UbsioGetResourceInfo");
87 89 
88 gLoaded = true;90 gLoaded = true;
@@ -112,6 +114,10 @@ void DlUbsioApi::CleanupLibrary()
112 pUbsioRegisterMetaEventCallback = nullptr;114 pUbsioRegisterMetaEventCallback = nullptr;
113 pUbsioGetResourceInfo = nullptr;115 pUbsioGetResourceInfo = nullptr;
114 116 
117+ if (pUbsioKvCacheExit != nullptr) {
118+ pUbsioKvCacheExit();
119+ pUbsioKvCacheExit = nullptr;
120+ }
115 if (ubsioHandle != nullptr) {121 if (ubsioHandle != nullptr) {
116 dlclose(ubsioHandle);122 dlclose(ubsioHandle);
117 ubsioHandle = nullptr;123 ubsioHandle = nullptr;
@@ -55,6 +55,7 @@ typedef struct {
55typedef void (*UbsioMetaEventCallbackC)(void *context, const UbsioMetaEventC *events, uint32_t count);55typedef void (*UbsioMetaEventCallbackC)(void *context, const UbsioMetaEventC *events, uint32_t count);
56 56 
57using ubsio_register_meta_event_callbackFunc = int32_t (*)(UbsioMetaEventCallbackC callback, void *context);57using ubsio_register_meta_event_callbackFunc = int32_t (*)(UbsioMetaEventCallbackC callback, void *context);
58+using ubsio_kv_cache_exitFunc = void (*)();
58 59 
59class DlUbsioApi {60class DlUbsioApi {
60public:61public:
@@ -200,6 +201,7 @@ private:
200 static ubsio_batch_get_lengthFunc pUbsioBatchGetLength;201 static ubsio_batch_get_lengthFunc pUbsioBatchGetLength;
201 static ubsio_batch_free_addressFunc pUbsioBatchFreeAddress;202 static ubsio_batch_free_addressFunc pUbsioBatchFreeAddress;
202 static ubsio_register_meta_event_callbackFunc pUbsioRegisterMetaEventCallback;203 static ubsio_register_meta_event_callbackFunc pUbsioRegisterMetaEventCallback;
204+ static ubsio_kv_cache_exitFunc pUbsioKvCacheExit;
203 static ubsio_get_resource_infoFunc pUbsioGetResourceInfo;205 static ubsio_get_resource_infoFunc pUbsioGetResourceInfo;
204};206};
205} // namespace mmc207} // namespace mmc
@@ -76,6 +76,7 @@ typedef struct {
76 mmc_kv_events_config_t kvEvents;76 mmc_kv_events_config_t kvEvents;
77 uint16_t rewarmDramWatermark;77 uint16_t rewarmDramWatermark;
78 bool prefetchEnabled;78 bool prefetchEnabled;
79+ uint64_t pendingWaitTimeoutMs;
79} mmc_meta_service_config_t;80} mmc_meta_service_config_t;
80 81 
81typedef struct {82typedef struct {
@@ -45,7 +45,7 @@ lib_dir = os.path.join(current_dir, "lib")
45# Preload with absolute paths so that subsequent dlopen can resolve without LD_LIBRARY_PATH.45# Preload with absolute paths so that subsequent dlopen can resolve without LD_LIBRARY_PATH.
46_preload_list = [46_preload_list = [
47 "libmf_memcache.so",47 "libmf_memcache.so",
48- "libubsio_kvc.so",48+ "libubsio_kvc.so.1",
49]49]
50for lib_name in _preload_list:50for lib_name in _preload_list:
51 so_path = os.path.join(lib_dir, lib_name)51 so_path = os.path.join(lib_dir, lib_name)
@@ -10,4 +10,8 @@
10 10 
11add_library(mock_ubsio SHARED mock_ubsio_api.cpp)11add_library(mock_ubsio SHARED mock_ubsio_api.cpp)
12target_include_directories(mock_ubsio PRIVATE ${CMAKE_SOURCE_DIR}/src/memcache/csrc/under_api/ubs_io)12target_include_directories(mock_ubsio PRIVATE ${CMAKE_SOURCE_DIR}/src/memcache/csrc/under_api/ubs_io)
13-set_target_properties(mock_ubsio PROPERTIES OUTPUT_NAME "ubsio_kvc")13+set_target_properties(mock_ubsio PROPERTIES
14+ OUTPUT_NAME "ubsio_kvc"
15+ VERSION 1.0.0
16+ SOVERSION 1
17+)
@@ -301,6 +301,12 @@ extern "C" int32_t UbsioKvCacheBatchFree(void **bufs, uint32_t keys_count)
301 return 0;301 return 0;
302}302}
303 303 
304+// 退出清理函数
305+extern "C" int32_t UbsioKvCacheExit()
306+{
307+ return 0;
308+}
309+ 
304// 批量直接读取函数(带HBM)310// 批量直接读取函数(带HBM)
305extern "C" int32_t UbsioKvCacheBatchGetDirect(const char **keys, uint32_t keys_count, void ***bufs, size_t **lengths,311extern "C" int32_t UbsioKvCacheBatchGetDirect(const char **keys, uint32_t keys_count, void ***bufs, size_t **lengths,
306 uint32_t lengths_rows, uint32_t lengths_cols, int *results,312 uint32_t lengths_rows, uint32_t lengths_cols, int *results,