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+ #include " space_property.h"
25+ #include < atomic>
26+ #include " logger/logger.h"
27+ #include " file/file.h"
28+
29+ namespace UC {
30+
31+ static constexpr uint32_t Magic = ((' S' << 16 ) | (' p' << 8 ) | 1 );
32+ static constexpr size_t PropertySize = 256 ;
33+
34+ struct Property {
35+ std::atomic<uint32_t > magic;
36+ uint32_t padding;
37+ std::atomic<size_t > capacity;
38+ };
39+ static_assert (sizeof (Property) <= PropertySize, " Property take too much space" );
40+ static_assert (std::atomic<uint32_t >::is_always_lock_free, " magic must be lock-free" );
41+ static_assert (std::atomic<size_t >::is_always_lock_free, " capacity must be lock-free" );
42+
43+ inline auto PropertyPtr (void * addr) { return (Property*)addr; }
44+
45+ SpaceProperty::~SpaceProperty ()
46+ {
47+ if (this ->addr_ ) {
48+ File::MUnmap (this ->addr_ , PropertySize);
49+ }
50+ this ->addr_ = nullptr ;
51+ }
52+
53+ Status SpaceProperty::Setup (const std::string& propertyFilePath)
54+ {
55+ auto file = File::Make (propertyFilePath);
56+ if (!file) { return Status::OutOfMemory (); }
57+ auto flags = IFile::OpenFlag::CREATE | IFile::OpenFlag::EXCL | IFile::OpenFlag::READ_WRITE;
58+ auto status = file->Open (flags);
59+ if (status.Success ()) { return this ->InitShmProperty (file.get ()); }
60+ if (status == Status::DuplicateKey ()) { return this ->LoadShmProperty (file.get ()); }
61+ return status;
62+ }
63+
64+ void SpaceProperty::IncreaseCapacity (const size_t delta)
65+ {
66+ PropertyPtr (this ->addr_ )->capacity += delta;
67+ }
68+
69+ void SpaceProperty::DecreaseCapacity (const size_t delta)
70+ {
71+ auto property = PropertyPtr (this ->addr_ );
72+ auto capacity = property->capacity .load (std::memory_order_acquire);
73+ while (capacity > delta) {
74+ if (property->capacity .compare_exchange_weak (capacity, capacity - delta, std::memory_order_acq_rel)) {
75+ return ;
76+ }
77+ capacity = property->capacity .load (std::memory_order_acquire);
78+ }
79+ }
80+
81+ size_t SpaceProperty::GetCapacity () const
82+ {
83+ return PropertyPtr (this ->addr_ )->capacity .load (std::memory_order_relaxed);
84+ }
85+
86+ Status SpaceProperty::InitShmProperty (IFile* shmPropertyFile)
87+ {
88+ auto status = shmPropertyFile->Truncate (PropertySize);
89+ if (status.Failure ()) { return status; }
90+ status = shmPropertyFile->MMap (this ->addr_ , PropertySize, true , true , true );
91+ if (status.Failure ()) { return status; }
92+ std::fill_n ((uint8_t *)this ->addr_ , PropertySize, 0 );
93+ auto property = PropertyPtr (this ->addr_ );
94+ property->padding = 0 ;
95+ property->capacity = 0 ;
96+ property->magic = Magic;
97+ return Status::OK ();
98+ }
99+
100+ Status SpaceProperty::LoadShmProperty (IFile* shmPropertyFile)
101+ {
102+ auto status = shmPropertyFile->Open (IFile::OpenFlag::READ_WRITE);
103+ if (status.Failure ()) { return status; }
104+ constexpr auto retryInterval = std::chrono::milliseconds (100 );
105+ constexpr auto maxTryTime = 100 ;
106+ auto tryTime = 0 ;
107+ IFile::FileStat stat;
108+ do {
109+ if (tryTime > maxTryTime) {
110+ UC_ERROR (" Shm file({}) not ready." , shmPropertyFile->Path ());
111+ return Status::Retry ();
112+ }
113+ std::this_thread::sleep_for (retryInterval);
114+ status = shmPropertyFile->Stat (stat);
115+ if (status.Failure ()) { return status; }
116+ tryTime++;
117+ } while (static_cast <size_t >(stat.st_size ) != PropertySize);
118+ status = shmPropertyFile->MMap (this ->addr_ , PropertySize, true , true , true );
119+ if (status.Failure ()) { return status; }
120+ auto property = PropertyPtr (this ->addr_ );
121+ tryTime = 0 ;
122+ do {
123+ if (property->magic == Magic) { break ; }
124+ if (tryTime > maxTryTime) {
125+ UC_ERROR (" Shm file({}) not ready." , shmPropertyFile->Path ());
126+ return Status::Retry ();
127+ }
128+ std::this_thread::sleep_for (retryInterval);
129+ tryTime++;
130+ } while (true );
131+ return Status::OK ();
132+ }
133+
134+ } // namespace UC
0 commit comments