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