Skip to content

Commit b5ebca1

Browse files
authored
[Feat] Next Store Interface (#510)
Define the StoreV1 interface, see issue #490 for details.
1 parent 9a0b3ba commit b5ebca1

File tree

91 files changed

+1611
-2861
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+1611
-2861
lines changed

.clang-format

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
BasedOnStyle: LLVM
1+
BasedOnStyle: Google
22
IndentWidth: 4
33
ColumnLimit: 100
44
AccessModifierOffset: -4

.github/workflows/cpp-linter.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
files-changed-only: true
2626
lines-changed-only: diff
2727
format-review: true
28-
thread-comments: ${{ github.event_name == 'pull_request' && 'update' }}
28+
version: 20
2929

3030
- name: Fail fast?!
3131
if: steps.linter.outputs.checks-failed != 0

.github/workflows/ucmstore.yml

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ env:
1313
BUILD_TYPE: Debug
1414

1515
jobs:
16-
ci:
16+
cc_gtest:
1717
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
1818
# You can convert this to a matrix build if you need cross-platform coverage.
1919
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
@@ -24,28 +24,20 @@ jobs:
2424

2525
- name: Install googletest
2626
run: |
27-
git clone https://github.com/google/googletest.git --depth=1 --branch=v1.12.0
27+
git clone https://github.com/google/googletest.git --depth=1 --branch=v1.17.0
2828
cd googletest
2929
mkdir build && cd build
3030
cmake -DCMAKE_CXX_FLAGS="-fPIC" -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=True ..
3131
sudo make install -j
3232
33-
- name: Install mockcpp
34-
run: |
35-
git clone https://github.com/sinojelly/mockcpp.git --depth=1
36-
cd mockcpp
37-
mkdir build && cd build
38-
cmake -DCMAKE_CXX_FLAGS="-fPIC" -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=True -DMOCKCPP_XUNIT="gtest" -DMOCKCPP_XUNIT_HOME=/usr/local/ ..
39-
sudo make install -j
40-
4133
- name: Configure CMake
4234
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
4335
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
4436
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_UCM_SPARSE=OFF -DBUILD_UNIT_TESTS=ON -DRUNTIME_ENVIRONMENT=simu
4537

4638
- name: Build
4739
# Build your program with the given configuration
48-
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
40+
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j
4941

5042
- name: Test
5143
working-directory: ${{github.workspace}}/build

ucm/shared/infra/status/status.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <cstdint>
2828
#include <fmt/format.h>
2929
#include <string>
30+
#include <variant>
3031

3132
namespace UC {
3233

@@ -49,6 +50,7 @@ class Status {
4950
static constexpr int32_t EDESERIALIZE_ = __MakeStatusCode<7>();
5051
static constexpr int32_t EUNSUPPORTED_ = __MakeStatusCode<8>();
5152
static constexpr int32_t ENOSPACE_ = __MakeStatusCode<9>();
53+
static constexpr int32_t ETIMEOUT_ = __MakeStatusCode<10>();
5254
int32_t code_;
5355
std::string message_;
5456
explicit Status(int32_t code) : code_(code) {}
@@ -72,19 +74,41 @@ class Status {
7274
static Status Error(std::string message) { return {ERROR_, std::move(message)}; }
7375
static Status Error() { return Status{ERROR_}; }
7476
static Status InvalidParam() { return Status{EPARAM_}; }
77+
static Status InvalidParam(std::string message) { return {EPARAM_, std::move(message)}; }
78+
template <typename... Args>
79+
static Status InvalidParam(fmt::format_string<Args...> fmt, Args&&... args)
80+
{
81+
return InvalidParam(fmt::format(fmt, std::forward<Args>(args)...));
82+
}
7583
static Status OutOfMemory() { return Status{EOOM_}; }
7684
static Status OsApiError() { return Status{EOSERROR_}; }
85+
static Status OsApiError(std::string message) { return Status{EOSERROR_, std::move(message)}; }
7786
static Status DuplicateKey() { return Status{EDUPLICATE_}; }
7887
static Status Retry() { return Status{ERETRY_}; }
7988
static Status NotFound() { return Status{ENOOBJ_}; }
8089
static Status SerializeFailed() { return Status{ESERIALIZE_}; }
8190
static Status DeserializeFailed() { return Status{EDESERIALIZE_}; }
8291
static Status Unsupported() { return Status{EUNSUPPORTED_}; }
8392
static Status NoSpace() { return Status{ENOSPACE_}; }
93+
static Status Timeout() { return Status{ETIMEOUT_}; }
94+
};
95+
96+
template <class T>
97+
class Expected {
98+
std::variant<Status, T> v_;
99+
100+
public:
101+
Expected(T&& val) : v_(std::move(val)) {}
102+
Expected(Status err) : v_(err) {}
103+
bool HasValue() const noexcept { return v_.index() == 1; }
104+
explicit operator bool() const noexcept { return HasValue(); }
105+
T& Value() & { return std::get<T>(v_); }
106+
T&& Value() && { return std::get<T>(std::move(v_)); }
107+
Status Error() const { return std::get<Status>(v_); }
84108
};
85109

86110
inline std::string format_as(const Status& status) { return status.ToString(); }
87111

88-
} // namespace UC
112+
} // namespace UC
89113

90114
#endif
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
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+
#ifndef UNIFIEDCACHE_INFRA_SPSC_RING_QUEUE_H
25+
#define UNIFIEDCACHE_INFRA_SPSC_RING_QUEUE_H
26+
27+
#include <atomic>
28+
#include <climits>
29+
#include <cstddef>
30+
#include <functional>
31+
#include <memory>
32+
#include <thread>
33+
34+
namespace UC {
35+
36+
template <typename T>
37+
class SpscRingQueue {
38+
alignas(64) std::atomic<size_t> head_ = 0;
39+
alignas(64) std::atomic<size_t> tail_ = 0;
40+
bool pow2_{false};
41+
size_t mask_{0};
42+
size_t capacity_{0};
43+
std::unique_ptr<T[]> buffer_;
44+
45+
size_t Mod(size_t n) { return pow2_ ? (n & mask_) : (n % capacity_); }
46+
47+
public:
48+
void Setup(size_t capacity)
49+
{
50+
capacity_ = capacity;
51+
mask_ = capacity_ - 1;
52+
pow2_ = (capacity_ & mask_) == 0;
53+
buffer_ = std::make_unique<T[]>(capacity_);
54+
}
55+
56+
void Push(T&& value)
57+
{
58+
while (true) {
59+
const size_t currentHead = head_.load(std::memory_order_relaxed);
60+
const size_t nextHead = Mod(currentHead + 1);
61+
if (nextHead != tail_.load(std::memory_order_acquire)) {
62+
buffer_[currentHead] = std::move(value);
63+
head_.store(nextHead, std::memory_order_release);
64+
return;
65+
}
66+
std::this_thread::yield();
67+
}
68+
}
69+
70+
bool TryPush(T&& value)
71+
{
72+
const size_t currentHead = head_.load(std::memory_order_relaxed);
73+
const size_t nextHead = Mod(currentHead + 1);
74+
const size_t currentTail = tail_.load(std::memory_order_acquire);
75+
if (nextHead == currentTail) { return false; }
76+
buffer_[currentHead] = std::move(value);
77+
head_.store(nextHead, std::memory_order_release);
78+
return true;
79+
}
80+
81+
bool TryPop(T& value)
82+
{
83+
const size_t currentHead = head_.load(std::memory_order_acquire);
84+
const size_t currentTail = tail_.load(std::memory_order_relaxed);
85+
if (currentTail == currentHead) { return false; }
86+
value = std::move(buffer_[currentTail]);
87+
tail_.store(Mod(currentTail + 1), std::memory_order_release);
88+
return true;
89+
}
90+
91+
template <typename ConsumerHandler, typename... Args>
92+
void ConsumerLoop(const std::atomic_bool& stop, ConsumerHandler&& handler, Args&&... args)
93+
{
94+
constexpr size_t kSpinLimit = 16;
95+
constexpr size_t kTaskBatch = 64;
96+
size_t spinCount = 0;
97+
size_t taskCount = 0;
98+
T task;
99+
while (!stop.load(std::memory_order_relaxed)) {
100+
if (TryPop(task)) {
101+
spinCount = 0;
102+
std::invoke(handler, std::forward<Args>(args)..., std::move(task));
103+
if (++taskCount % kTaskBatch == 0) {
104+
if (stop.load(std::memory_order_acquire)) { break; }
105+
}
106+
continue;
107+
}
108+
if (++spinCount < kSpinLimit) {
109+
std::this_thread::yield();
110+
} else {
111+
if (stop.load(std::memory_order_acquire)) { break; }
112+
std::this_thread::sleep_for(std::chrono::microseconds(100));
113+
spinCount = 0;
114+
}
115+
}
116+
}
117+
};
118+
119+
} // namespace UC
120+
121+
#endif

ucm/shared/infra/thread/latch.h

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,25 @@
2828
#include <condition_variable>
2929
#include <functional>
3030
#include <mutex>
31+
#include "time/now_time.h"
3132

3233
namespace UC {
3334

3435
class Latch {
3536
public:
36-
explicit Latch(const size_t expected = 0) : counter_{expected} {}
37+
Latch() : startTp{NowTime::Now()} {}
38+
void Set(size_t expected) noexcept { this->counter_.store(expected); }
39+
void SetEpilog(std::function<void(void)> finish) noexcept { finish_ = std::move(finish); }
3740
void Up() { ++this->counter_; }
38-
void Done(std::function<void(void)> finish) noexcept
41+
void Done(std::function<void(void)>&& finish = nullptr) noexcept
3942
{
4043
auto counter = this->counter_.load(std::memory_order_acquire);
4144
while (counter > 0) {
4245
auto desired = counter - 1;
4346
if (this->counter_.compare_exchange_weak(counter, desired, std::memory_order_acq_rel)) {
4447
if (desired == 0) {
45-
if (finish) { finish(); }
48+
auto& fn = finish ? finish : finish_;
49+
if (fn) { fn(); }
4650
std::lock_guard<std::mutex> lg(this->mutex_);
4751
this->cv_.notify_all();
4852
}
@@ -57,13 +61,33 @@ class Latch {
5761
if (this->counter_ == 0) { return; }
5862
this->cv_.wait(lk, [this] { return this->counter_ == 0; });
5963
}
64+
bool WaitFor(size_t timeoutMs) noexcept
65+
{
66+
if (timeoutMs == 0) {
67+
this->Wait();
68+
return true;
69+
}
70+
std::unique_lock<std::mutex> lk(this->mutex_);
71+
if (this->counter_ == 0) { return true; }
72+
auto elapsed = std::chrono::duration<double>(NowTime::Now() - startTp);
73+
auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed);
74+
auto timeMs = std::chrono::milliseconds(timeoutMs);
75+
if (timeMs <= elapsedMs) { return false; }
76+
auto remainMs = timeMs - elapsedMs;
77+
return this->cv_.wait_for(lk, remainMs, [this] { return this->counter_ == 0; });
78+
}
79+
bool Check() noexcept { return this->counter_ == 0; }
80+
81+
public:
82+
double startTp{0};
6083

6184
protected:
6285
std::mutex mutex_;
6386
std::condition_variable cv_;
64-
std::atomic<size_t> counter_;
87+
std::atomic<size_t> counter_{0};
88+
std::function<void(void)> finish_{nullptr};
6589
};
6690

67-
} // namespace UC
91+
} // namespace UC
6892

69-
#endif // UNIFIEDCACHE_INFRA_LATCH_H
93+
#endif // UNIFIEDCACHE_INFRA_LATCH_H

ucm/store/localstore/cc/domain/cache/cache_layout.h renamed to ucm/shared/infra/time/now_time.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,22 @@
2121
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2222
* SOFTWARE.
2323
* */
24-
#ifndef UNIFIEDCACHE_CACHE_LAYOUT_H
25-
#define UNIFIEDCACHE_CACHE_LAYOUT_H
24+
#ifndef UNIFIEDCACHE_SHARED_INFRA_TIME_NOW_TIME_H
25+
#define UNIFIEDCACHE_SHARED_INFRA_TIME_NOW_TIME_H
2626

27-
#include <string>
27+
#include <chrono>
2828

2929
namespace UC {
3030

31-
class CacheLayout {
31+
class NowTime {
3232
public:
33-
static std::string MetaShmFile();
34-
static std::string DataShmFile(const size_t id);
33+
static auto Now()
34+
{
35+
auto now = std::chrono::steady_clock::now().time_since_epoch();
36+
return std::chrono::duration<double>(now).count();
37+
}
3538
};
3639

37-
} // namespace UC
40+
} // namespace UC
3841

3942
#endif

ucm/shared/test/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ if(BUILD_UNIT_TESTS)
55
target_include_directories(ucmshared.test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/case)
66
target_link_libraries(ucmshared.test PRIVATE
77
trans
8-
gtest_main gtest mockcpp
8+
gtest_main gtest
99
)
1010
gtest_discover_tests(ucmshared.test)
1111
endif()

0 commit comments

Comments
 (0)