1 /* 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" 17 18 #include "iomanip" 19 20 PostCodeDataHolder* PostCodeDataHolder::instance = 0; 21 22 void PostCode::deleteAll() 23 { 24 auto dir = fs::path(postcodeDataHolderObj->PostCodeListPathPrefix + 25 std::to_string(postcodeDataHolderObj->node)); 26 std::uintmax_t n = fs::remove_all(dir); 27 std::cerr << "clearPostCodes deleted " << n << " files in " 28 << postcodeDataHolderObj->PostCodeListPathPrefix + 29 std::to_string(postcodeDataHolderObj->node) 30 << std::endl; 31 fs::create_directories(dir); 32 postCodes.clear(); 33 currentBootCycleIndex = 1; 34 currentBootCycleCount(1); 35 } 36 37 std::vector<postcode_t> PostCode::getPostCodes(uint16_t index) 38 { 39 std::vector<postcode_t> codesVec; 40 if (1 == index && !postCodes.empty()) 41 { 42 for (auto& code : postCodes) 43 codesVec.push_back(code.second); 44 } 45 else 46 { 47 uint16_t bootNum = getBootNum(index); 48 49 decltype(postCodes) codes; 50 deserializePostCodes( 51 fs::path(strPostCodeListPath + std::to_string(bootNum)), codes); 52 for (std::pair<uint64_t, postcode_t> code : codes) 53 codesVec.push_back(code.second); 54 } 55 return codesVec; 56 } 57 58 std::map<uint64_t, postcode_t> 59 PostCode::getPostCodesWithTimeStamp(uint16_t index) 60 { 61 if (1 == index && !postCodes.empty()) 62 { 63 return postCodes; 64 } 65 66 uint16_t bootNum = getBootNum(index); 67 decltype(postCodes) codes; 68 deserializePostCodes( 69 fs::path(strPostCodeListPath + std::to_string(bootNum)), codes); 70 return codes; 71 } 72 73 void PostCode::savePostCodes(postcode_t code) 74 { 75 // steady_clock is a monotonic clock that is guaranteed to never be adjusted 76 auto postCodeTimeSteady = std::chrono::steady_clock::now(); 77 uint64_t tsUS = std::chrono::duration_cast<std::chrono::microseconds>( 78 std::chrono::system_clock::now().time_since_epoch()) 79 .count(); 80 81 if (postCodes.empty()) 82 { 83 firstPostCodeTimeSteady = postCodeTimeSteady; 84 firstPostCodeUsSinceEpoch = tsUS; // uS since epoch for 1st post code 85 incrBootCycle(); 86 } 87 else 88 { 89 // calculating tsUS so it is monotonic within the same boot 90 tsUS = firstPostCodeUsSinceEpoch + 91 std::chrono::duration_cast<std::chrono::microseconds>( 92 postCodeTimeSteady - firstPostCodeTimeSteady) 93 .count(); 94 } 95 96 postCodes.insert(std::make_pair(tsUS, code)); 97 serialize(fs::path(strPostCodeListPath)); 98 99 return; 100 } 101 102 fs::path PostCode::serialize(const std::string& path) 103 { 104 try 105 { 106 fs::path idxPath(path + strCurrentBootCycleIndexName); 107 std::ofstream osIdx(idxPath.c_str(), std::ios::binary); 108 cereal::JSONOutputArchive idxArchive(osIdx); 109 idxArchive(currentBootCycleIndex); 110 111 uint16_t count = currentBootCycleCount(); 112 fs::path cntPath(path + strCurrentBootCycleCountName); 113 std::ofstream osCnt(cntPath.c_str(), std::ios::binary); 114 cereal::JSONOutputArchive cntArchive(osCnt); 115 cntArchive(count); 116 117 std::ofstream osPostCodes( 118 (path + std::to_string(currentBootCycleIndex))); 119 cereal::JSONOutputArchive oarchivePostCodes(osPostCodes); 120 oarchivePostCodes(postCodes); 121 } 122 catch (cereal::Exception& e) 123 { 124 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 125 return ""; 126 } 127 catch (const fs::filesystem_error& e) 128 { 129 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 130 return ""; 131 } 132 return path; 133 } 134 135 bool PostCode::deserialize(const fs::path& path, uint16_t& index) 136 { 137 try 138 { 139 if (fs::exists(path)) 140 { 141 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); 142 cereal::JSONInputArchive iarchive(is); 143 iarchive(index); 144 return true; 145 } 146 return false; 147 } 148 catch (cereal::Exception& e) 149 { 150 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 151 return false; 152 } 153 catch (const fs::filesystem_error& e) 154 { 155 return false; 156 } 157 158 return false; 159 } 160 161 bool PostCode::deserializePostCodes(const fs::path& path, 162 std::map<uint64_t, postcode_t>& codes) 163 { 164 try 165 { 166 if (fs::exists(path)) 167 { 168 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); 169 cereal::JSONInputArchive iarchive(is); 170 iarchive(codes); 171 return true; 172 } 173 return false; 174 } 175 catch (cereal::Exception& e) 176 { 177 phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 178 return false; 179 } 180 catch (const fs::filesystem_error& e) 181 { 182 return false; 183 } 184 return false; 185 } 186 187 void PostCode::incrBootCycle() 188 { 189 if (currentBootCycleIndex >= maxBootCycleNum()) 190 { 191 currentBootCycleIndex = 1; 192 } 193 else 194 { 195 currentBootCycleIndex++; 196 } 197 currentBootCycleCount(std::min( 198 maxBootCycleNum(), static_cast<uint16_t>(currentBootCycleCount() + 1))); 199 } 200 201 uint16_t PostCode::getBootNum(const uint16_t index) const 202 { 203 // bootNum assumes the oldest archive is boot number 1 204 // and the current boot number equals bootCycleCount 205 // map bootNum back to bootIndex that was used to archive postcode 206 uint16_t bootNum = currentBootCycleIndex; 207 if (index > bootNum) // need to wrap around 208 { 209 bootNum = (maxBootCycleNum() + currentBootCycleIndex) - index + 1; 210 } 211 else 212 { 213 bootNum = currentBootCycleIndex - index + 1; 214 } 215 return bootNum; 216 } 217