Skip to content

Commit 7004ab7

Browse files
Lijiachen1018lijiachen
andauthored
[feat] capacity check for nfsstore (#315)
* capacity check * recycle --------- Co-authored-by: lijiachen <lijiachen19@huawei.com>
1 parent 9708eee commit 7004ab7

File tree

19 files changed

+918
-13
lines changed

19 files changed

+918
-13
lines changed

ucm/store/infra/file/file.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ Status File::Access(const std::string& path, const int32_t mode)
5353
return FileImpl{path}.Access(mode);
5454
}
5555

56+
Status File::Stat(const std::string& path, IFile::FileStat& st)
57+
{
58+
FileImpl file{path};
59+
auto status = file.Open(IFile::OpenFlag::READ_ONLY);
60+
if (status.Failure()) { return status; }
61+
status = file.Stat(st);
62+
file.Close();
63+
return status;
64+
}
65+
5666
Status File::Read(const std::string& path, const size_t offset, const size_t length,
5767
uintptr_t address, const bool directIo)
5868
{

ucm/store/infra/file/file.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class File {
3636
static Status RmDir(const std::string& path);
3737
static Status Rename(const std::string& path, const std::string& newName);
3838
static Status Access(const std::string& path, const int32_t mode);
39+
static Status Stat(const std::string& path, IFile::FileStat& st);
3940
static Status Read(const std::string& path, const size_t offset, const size_t length,
4041
uintptr_t address, const bool directIo = false);
4142
static Status Write(const std::string& path, const size_t offset, const size_t length,

ucm/store/infra/status/status.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class Status {
4242
ESERIALIZE = UC_MAKE_STATUS_CODE(6),
4343
EDESERIALIZE = UC_MAKE_STATUS_CODE(7),
4444
EUNSUPPORTED = UC_MAKE_STATUS_CODE(8),
45+
ENOSPACE = UC_MAKE_STATUS_CODE(9),
4546
#undef UC_MAKE_STATUS_CODE
4647
};
4748

@@ -101,7 +102,11 @@ class Status {
101102
static Status s{Code::EUNSUPPORTED};
102103
return s;
103104
}
104-
105+
static Status& NoSpace()
106+
{
107+
static Status s{Code::ENOSPACE};
108+
return s;
109+
}
105110
public:
106111
Status(const Status& status) { this->code_ = status.code_; }
107112
Status& operator=(const Status& status)
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/**
2+
* MIT License
3+
*
4+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
* */
24+
25+
#ifndef UNIFIEDCACHE_TOP_N_HEAP_H
26+
#define UNIFIEDCACHE_TOP_N_HEAP_H
27+
28+
#include <algorithm>
29+
#include <cstdint>
30+
31+
namespace UC {
32+
33+
template <typename T, typename Compare = std::less<T>>
34+
class TopNHeap {
35+
public:
36+
using ValueType = T;
37+
using SizeType = uint32_t;
38+
using ConstRef = const T&;
39+
40+
private:
41+
using IndexType = uint32_t;
42+
std::vector<ValueType> val_{};
43+
std::vector<IndexType> idx_{};
44+
SizeType capacity_{0};
45+
SizeType size_{0};
46+
Compare cmp_{};
47+
48+
public:
49+
explicit TopNHeap(const SizeType capacity) noexcept(
50+
std::is_nothrow_default_constructible_v<Compare>)
51+
: capacity_{capacity} {
52+
val_.resize(capacity);
53+
idx_.resize(capacity);
54+
}
55+
TopNHeap(const TopNHeap&) = delete;
56+
TopNHeap(const TopNHeap&&) = delete;
57+
TopNHeap& operator=(const TopNHeap&) = delete;
58+
TopNHeap& operator=(const TopNHeap&&) = delete;
59+
~TopNHeap() { Clear(); }
60+
61+
SizeType Size() const noexcept { return size_; }
62+
SizeType Capacity() const noexcept { return capacity_; }
63+
bool Empty() const noexcept { return size_ == 0; }
64+
65+
void Push(ConstRef value) noexcept {
66+
if (size_ < capacity_) {
67+
val_[size_] = value;
68+
idx_[size_] = size_;
69+
SiftUp(size_);
70+
size_++;
71+
return;
72+
}
73+
if (cmp_(val_[idx_.front()], value)) {
74+
val_[idx_.front()] = value;
75+
SiftDown(0);
76+
}
77+
}
78+
ConstRef Top() const noexcept { return val_[idx_.front()]; }
79+
void Pop() noexcept {
80+
idx_[0] = idx_[--size_];
81+
if (size_) { SiftDown(0); }
82+
}
83+
void Clear() noexcept { size_ = 0; }
84+
private:
85+
static IndexType Parent(IndexType i) noexcept { return (i - 1) / 2; }
86+
static IndexType Left(IndexType i) noexcept { return 2 * i + 1; }
87+
static IndexType Right(IndexType i) noexcept { return 2 * i + 2; }
88+
void SiftUp(IndexType i) noexcept {
89+
auto pos = i;
90+
while (pos > 0) {
91+
auto p = Parent(pos);
92+
if (!cmp_(val_[idx_[pos]], val_[idx_[p]])) { break; }
93+
std::swap(idx_[pos], idx_[p]);
94+
pos = p;
95+
}
96+
}
97+
void SiftDown(IndexType i) noexcept {
98+
auto pos = i;
99+
for (;;) {
100+
auto l = Left(pos);
101+
auto r = Right(pos);
102+
auto best = pos;
103+
if (l < size_ && cmp_(val_[idx_[l]], val_[idx_[best]])) { best = l; }
104+
if (r < size_ && cmp_(val_[idx_[r]], val_[idx_[best]])) { best = r; }
105+
if (best == pos) { break; }
106+
std::swap(idx_[pos], idx_[best]);
107+
pos = best;
108+
}
109+
}
110+
};
111+
112+
template <typename T, size_t N, typename Compare = std::less<T>>
113+
class TopNFixedHeap : public TopNHeap<T, Compare> {
114+
public:
115+
TopNFixedHeap() : TopNHeap<T, Compare>{N} {}
116+
};
117+
118+
} // namespace UC
119+
120+
#endif

ucm/store/nfsstore/cc/api/nfsstore.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ class NFSStoreImpl : public NFSStore {
3535
int32_t Setup(const Config& config)
3636
{
3737
auto status = this->spaceMgr_.Setup(config.storageBackends, config.kvcacheBlockSize,
38-
config.tempDumpDirEnable);
38+
config.tempDumpDirEnable, config.storageCapacity,
39+
config.recycleEnable, config.recycleThresholdRatio);
3940
if (status.Failure()) {
4041
UC_ERROR("Failed({}) to setup SpaceManager.", status);
4142
return status.Underlying();
@@ -120,6 +121,9 @@ class NFSStoreImpl : public NFSStore {
120121
UC_INFO("Set UC::TempDumpDirEnable to {}.", config.tempDumpDirEnable);
121122
UC_INFO("Set UC::HotnessInterval to {}.", config.hotnessInterval);
122123
UC_INFO("Set UC::HotnessEnable to {}.", config.hotnessEnable);
124+
UC_INFO("Set UC::storageCapacity to {}.", config.storageCapacity);
125+
UC_INFO("Set UC::RecycleEnable to {}.", config.recycleEnable);
126+
UC_INFO("Set UC::RecycleThreshold to {}.", config.recycleThresholdRatio);
123127
}
124128

125129
private:

ucm/store/nfsstore/cc/api/nfsstore.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,17 @@ class NFSStore : public CCStore {
4343
bool tempDumpDirEnable;
4444
bool hotnessEnable;
4545
size_t hotnessInterval;
46+
size_t storageCapacity;
47+
bool recycleEnable;
48+
float recycleThresholdRatio;
4649

4750
Config(const std::vector<std::string>& storageBackends, const size_t kvcacheBlockSize,
4851
const bool transferEnable)
4952
: storageBackends{storageBackends}, kvcacheBlockSize{kvcacheBlockSize},
5053
transferEnable{transferEnable}, transferDeviceId{-1}, transferStreamNumber{32},
5154
transferIoSize{262144}, transferBufferNumber{512}, transferTimeoutMs{30000},
52-
tempDumpDirEnable{false}, hotnessEnable{true}, hotnessInterval{60}
55+
tempDumpDirEnable{false}, hotnessEnable{true}, hotnessInterval{60},
56+
storageCapacity{0}, recycleEnable{true}, recycleThresholdRatio{0.7f}
5357
{
5458
}
5559
};

ucm/store/nfsstore/cc/domain/space/space_layout.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,25 @@
2424
#ifndef UNIFIEDCACHE_SPACE_LAYOUT_H
2525
#define UNIFIEDCACHE_SPACE_LAYOUT_H
2626

27+
#include <memory>
2728
#include <string>
2829
#include <vector>
2930
#include "status/status.h"
3031

3132
namespace UC {
3233

3334
class SpaceLayout {
35+
public:
36+
struct DataIterator;
3437
public:
3538
virtual ~SpaceLayout() = default;
3639
virtual Status Setup(const std::vector<std::string>& storageBackends) = 0;
3740
virtual std::string DataFileParent(const std::string& blockId, bool activated) const = 0;
3841
virtual std::string DataFilePath(const std::string& blockId, bool activated) const = 0;
42+
virtual std::string ClusterPropertyFilePath() const = 0;
43+
virtual std::shared_ptr<DataIterator> CreateFilePathIterator() const = 0;
44+
virtual std::string NextDataFilePath(std::shared_ptr<DataIterator> iter) const = 0;
45+
virtual bool IsActivatedFile(const std::string& filePath) const = 0;
3946
};
4047

4148
} // namespace UC

ucm/store/nfsstore/cc/domain/space/space_manager.cc

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ std::unique_ptr<SpaceLayout> MakeSpaceLayout(const bool tempDumpDirEnable)
4040
}
4141

4242
Status SpaceManager::Setup(const std::vector<std::string>& storageBackends, const size_t blockSize,
43-
const bool tempDumpDirEnable)
43+
const bool tempDumpDirEnable, const size_t storageCapacity,
44+
const bool recycleEnable, const float recycleThresholdRatio)
4445
{
4546
if (blockSize == 0) {
4647
UC_ERROR("Invalid block size({}).", blockSize);
@@ -50,20 +51,34 @@ Status SpaceManager::Setup(const std::vector<std::string>& storageBackends, cons
5051
if (!this->layout_) { return Status::OutOfMemory(); }
5152
auto status = this->layout_->Setup(storageBackends);
5253
if (status.Failure()) { return status; }
54+
status = this->property_.Setup(this->layout_->ClusterPropertyFilePath());
55+
if (recycleEnable && storageCapacity > 0) {
56+
auto totalBlocks = storageCapacity / blockSize;
57+
status = this->recycle_.Setup(this->GetSpaceLayout(), totalBlocks, [this] {
58+
this->property_.DecreaseCapacity(this->blockSize_);
59+
});
60+
if (status.Failure()) { return status; }
61+
}
62+
if (status.Failure()) { return status; }
5363
this->blockSize_ = blockSize;
64+
this->capacity_ = storageCapacity;
65+
this->recycleEnable_ = recycleEnable;
66+
this->capacityRecycleThreshold_ = static_cast<size_t>(storageCapacity * recycleThresholdRatio);
5467
return Status::OK();
5568
}
5669

57-
Status SpaceManager::NewBlock(const std::string& blockId) const
70+
Status SpaceManager::NewBlock(const std::string& blockId)
5871
{
72+
Status status = this->CapacityCheck();
73+
if (status.Failure()) { return status; }
5974
constexpr auto activated = true;
6075
auto parent = File::Make(this->layout_->DataFileParent(blockId, activated));
6176
auto file = File::Make(this->layout_->DataFilePath(blockId, activated));
6277
if (!parent || !file) {
6378
UC_ERROR("Failed to new block({}).", blockId);
6479
return Status::OutOfMemory();
6580
}
66-
auto status = parent->MkDir();
81+
status = parent->MkDir();
6782
if (status == Status::DuplicateKey()) { status = Status::OK(); }
6883
if (status.Failure()) {
6984
UC_ERROR("Failed({}) to new block({}).", status, blockId);
@@ -88,10 +103,11 @@ Status SpaceManager::NewBlock(const std::string& blockId) const
88103
UC_ERROR("Failed({}) to new block({}).", status, blockId);
89104
return status;
90105
}
106+
this->property_.IncreaseCapacity(this->blockSize_);
91107
return Status::OK();
92108
}
93109

94-
Status SpaceManager::CommitBlock(const std::string& blockId, bool success) const
110+
Status SpaceManager::CommitBlock(const std::string& blockId, bool success)
95111
{
96112
const auto activatedParent = this->layout_->DataFileParent(blockId, true);
97113
const auto activatedFile = this->layout_->DataFilePath(blockId, true);
@@ -112,6 +128,7 @@ Status SpaceManager::CommitBlock(const std::string& blockId, bool success) const
112128
if (status.Failure()) {
113129
UC_ERROR("Failed({}) to {} block({}).", status, success ? "commit" : "cancel", blockId);
114130
}
131+
this->property_.DecreaseCapacity(this->blockSize_);
115132
return status;
116133
}
117134

@@ -136,4 +153,20 @@ bool SpaceManager::LookupBlock(const std::string& blockId) const
136153

137154
const SpaceLayout* SpaceManager::GetSpaceLayout() const { return this->layout_.get(); }
138155

156+
Status SpaceManager::CapacityCheck()
157+
{
158+
if (this->capacity_ == 0) { return Status::OK(); }
159+
160+
const size_t used = this->property_.GetCapacity();
161+
if (this->recycleEnable_ && used >= this->capacityRecycleThreshold_) {
162+
this->recycle_.Trigger();
163+
}
164+
if (used > this->capacity_ - this->blockSize_) {
165+
UC_ERROR("Capacity is not enough, capacity: {}, current: {}, block size: {}.",
166+
this->capacity_, used, this->blockSize_);
167+
return Status::NoSpace();
168+
}
169+
return Status::OK();
170+
}
171+
139172
} // namespace UC

ucm/store/nfsstore/cc/domain/space/space_manager.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,32 @@
2626

2727
#include <memory>
2828
#include "space_layout.h"
29+
#include "space_property.h"
2930
#include "status/status.h"
31+
#include "space_recycle.h"
3032

3133
namespace UC {
3234

3335
class SpaceManager {
3436
public:
3537
Status Setup(const std::vector<std::string>& storageBackends, const size_t blockSize,
36-
const bool tempDumpDirEnable);
37-
Status NewBlock(const std::string& blockId) const;
38-
Status CommitBlock(const std::string& blockId, bool success = true) const;
38+
const bool tempDumpDirEnable, const size_t storageCapacity = 0,
39+
const bool recycleEnable = false, const float recycleThresholdRatio = 0.7f);
40+
Status NewBlock(const std::string& blockId);
41+
Status CommitBlock(const std::string& blockId, bool success = true);
3942
bool LookupBlock(const std::string& blockId) const;
4043
const SpaceLayout* GetSpaceLayout() const;
4144

45+
private:
46+
Status CapacityCheck();
4247
private:
4348
std::unique_ptr<SpaceLayout> layout_;
49+
SpaceProperty property_;
50+
SpaceRecycle recycle_;
4451
size_t blockSize_;
52+
size_t capacity_;
53+
bool recycleEnable_;
54+
size_t capacityRecycleThreshold_;
4555
};
4656

4757
} // namespace UC

0 commit comments

Comments
 (0)