blob: 67a9d8f91ea26797e13dba866bcd6163f2da5bc2 [file] [log] [blame]
Kuiying Wang3a044402019-02-19 15:00:11 +08001/*
2// Copyright (c) 2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#include "post_code.hpp"
ZhikuiRen993d4dd2020-01-29 14:25:44 -080017
18#include "iomanip"
19
20void PostCode::deleteAll()
21{
22 auto dir = fs::path(PostCodeListPath);
23 std::uintmax_t n = fs::remove_all(dir);
24 std::cerr << "clearPostCodes deleted " << n << " files in "
25 << PostCodeListPath << std::endl;
26 fs::create_directories(dir);
27 postCodes.clear();
28 currentBootCycleIndex = 1;
29 currentBootCycleCount(1);
30}
31
Kuiying Wang3a044402019-02-19 15:00:11 +080032std::vector<uint64_t> PostCode::getPostCodes(uint16_t index)
33{
ZhikuiRen993d4dd2020-01-29 14:25:44 -080034 std::vector<uint64_t> codesVec;
35 if (1 == index && !postCodes.empty())
36 {
37 for (auto& code : postCodes)
38 codesVec.push_back(code.second);
39 }
40 else
41 {
42 uint16_t bootNum = getBootNum(index);
Kuiying Wang3a044402019-02-19 15:00:11 +080043
ZhikuiRen993d4dd2020-01-29 14:25:44 -080044 decltype(postCodes) codes;
45 deserializePostCodes(
46 fs::path(strPostCodeListPath + std::to_string(bootNum)), codes);
47 for (std::pair<uint64_t, uint64_t> code : codes)
48 codesVec.push_back(code.second);
49 }
50 return codesVec;
51}
52
53std::map<uint64_t, uint64_t> PostCode::getPostCodesWithTimeStamp(uint16_t index)
54{
55 if (1 == index && !postCodes.empty())
56 {
Kuiying Wang3a044402019-02-19 15:00:11 +080057 return postCodes;
ZhikuiRen993d4dd2020-01-29 14:25:44 -080058 }
59
60 uint16_t bootNum = getBootNum(index);
61 decltype(postCodes) codes;
62 deserializePostCodes(
63 fs::path(strPostCodeListPath + std::to_string(bootNum)), codes);
Kuiying Wang3a044402019-02-19 15:00:11 +080064 return codes;
65}
ZhikuiRen993d4dd2020-01-29 14:25:44 -080066
Kuiying Wang3a044402019-02-19 15:00:11 +080067void PostCode::savePostCodes(uint64_t code)
68{
ZhikuiRen993d4dd2020-01-29 14:25:44 -080069 // steady_clock is a monotonic clock that is guaranteed to never be adjusted
70 auto postCodeTimeSteady = std::chrono::steady_clock::now();
71 uint64_t tsUS = std::chrono::duration_cast<std::chrono::microseconds>(
72 std::chrono::system_clock::now().time_since_epoch())
73 .count();
74
75 if (postCodes.empty())
76 {
77 firstPostCodeTimeSteady = postCodeTimeSteady;
78 firstPostCodeUsSinceEpoch = tsUS; // uS since epoch for 1st post code
79 incrBootCycle();
80 }
81 else
82 {
83 // calculating tsUS so it is monotonic within the same boot
84 tsUS = firstPostCodeUsSinceEpoch +
85 std::chrono::duration_cast<std::chrono::microseconds>(
86 postCodeTimeSteady - firstPostCodeTimeSteady)
87 .count();
88 }
89
90 postCodes.insert(std::make_pair(tsUS, code));
Kuiying Wang3a044402019-02-19 15:00:11 +080091 serialize(fs::path(PostCodeListPath));
ZhikuiRen993d4dd2020-01-29 14:25:44 -080092
Kuiying Wang3a044402019-02-19 15:00:11 +080093 return;
94}
95
96fs::path PostCode::serialize(const std::string& path)
97{
98 try
99 {
ZhikuiRen993d4dd2020-01-29 14:25:44 -0800100 fs::path idxPath(path + strCurrentBootCycleIndexName);
101 std::ofstream osIdx(idxPath.c_str(), std::ios::binary);
102 cereal::JSONOutputArchive idxArchive(osIdx);
103 idxArchive(currentBootCycleIndex);
104
105 uint16_t count = currentBootCycleCount();
106 fs::path cntPath(path + strCurrentBootCycleCountName);
107 std::ofstream osCnt(cntPath.c_str(), std::ios::binary);
108 cereal::JSONOutputArchive cntArchive(osCnt);
109 cntArchive(count);
Kuiying Wang3a044402019-02-19 15:00:11 +0800110
111 std::ofstream osPostCodes(
ZhikuiRen993d4dd2020-01-29 14:25:44 -0800112 (path + std::to_string(currentBootCycleIndex)));
Kuiying Wang3a044402019-02-19 15:00:11 +0800113 cereal::JSONOutputArchive oarchivePostCodes(osPostCodes);
114 oarchivePostCodes(postCodes);
115 }
116 catch (cereal::Exception& e)
117 {
118 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
119 return "";
120 }
121 catch (const fs::filesystem_error& e)
122 {
123 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
124 return "";
125 }
126 return path;
127}
128
129bool PostCode::deserialize(const fs::path& path, uint16_t& index)
130{
131 try
132 {
133 if (fs::exists(path))
134 {
135 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
136 cereal::JSONInputArchive iarchive(is);
137 iarchive(index);
138 return true;
139 }
140 return false;
141 }
142 catch (cereal::Exception& e)
143 {
144 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
145 return false;
146 }
147 catch (const fs::filesystem_error& e)
148 {
149 return false;
150 }
151
152 return false;
153}
154
155bool PostCode::deserializePostCodes(const fs::path& path,
ZhikuiRen993d4dd2020-01-29 14:25:44 -0800156 std::map<uint64_t, uint64_t>& codes)
Kuiying Wang3a044402019-02-19 15:00:11 +0800157{
158 try
159 {
160 if (fs::exists(path))
161 {
162 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
163 cereal::JSONInputArchive iarchive(is);
164 iarchive(codes);
165 return true;
166 }
167 return false;
168 }
169 catch (cereal::Exception& e)
170 {
171 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
172 return false;
173 }
174 catch (const fs::filesystem_error& e)
175 {
176 return false;
177 }
Kuiying Wang3a044402019-02-19 15:00:11 +0800178 return false;
179}
ZhikuiRen993d4dd2020-01-29 14:25:44 -0800180
181void PostCode::incrBootCycle()
182{
183 if (currentBootCycleIndex >= maxBootCycleNum())
184 {
185 currentBootCycleIndex = 1;
186 }
187 else
188 {
189 currentBootCycleIndex++;
190 }
191 currentBootCycleCount(std::min(
192 maxBootCycleNum(), static_cast<uint16_t>(currentBootCycleCount() + 1)));
193}
194
195uint16_t PostCode::getBootNum(const uint16_t index) const
196{
197 // bootNum assumes the oldest archive is boot number 1
198 // and the current boot number equals bootCycleCount
199 // map bootNum back to bootIndex that was used to archive postcode
200 uint16_t bootNum = currentBootCycleIndex;
201 if (index > bootNum) // need to wrap around
202 {
203 bootNum = (maxBootCycleNum() + currentBootCycleIndex) - index + 1;
204 }
205 else
206 {
207 bootNum = currentBootCycleIndex - index + 1;
208 }
209 return bootNum;
210}