PageRenderTime 25ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 1ms

/src/storage/InMemoryStorageBackend.cpp

https://gitlab.com/admin-github-cloud/cynara
C++ | 290 lines | 219 code | 42 blank | 29 comment | 13 complexity | c65c1a3fb6c1dca65e46ab9a196f3c9a MD5 | raw file
  1. /*
  2. * Copyright (c) 2014-2016 Samsung Electronics Co., Ltd All Rights Reserved
  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. /**
  17. * @file src/storage/InMemoryStorageBackend.cpp
  18. * @author Aleksander Zdyb <a.zdyb@samsung.com>
  19. * @author Pawel Wieczorek <p.wieczorek2@samsung.com>
  20. * @version 1.0
  21. * @brief Implementation of InMemoryStorageBackend
  22. */
  23. #include <errno.h>
  24. #include <fstream>
  25. #include <functional>
  26. #include <memory>
  27. #include <new>
  28. #include <stdexcept>
  29. #include <string>
  30. #include <string.h>
  31. #include <sys/stat.h>
  32. #include <sys/types.h>
  33. #include <unordered_map>
  34. #include <log/log.h>
  35. #include <config/PathConfig.h>
  36. #include <exceptions/BucketNotExistsException.h>
  37. #include <exceptions/DatabaseCorruptedException.h>
  38. #include <exceptions/DatabaseException.h>
  39. #include <exceptions/FileNotFoundException.h>
  40. #include <exceptions/UnexpectedErrorException.h>
  41. #include <types/PolicyBucket.h>
  42. #include <types/PolicyResult.h>
  43. #include <types/PolicyType.h>
  44. #include <storage/BucketDeserializer.h>
  45. #include <storage/Integrity.h>
  46. #include <storage/StorageDeserializer.h>
  47. #include <storage/StorageSerializer.h>
  48. #include "InMemoryStorageBackend.h"
  49. namespace Cynara {
  50. InMemoryStorageBackend::InMemoryStorageBackend(const std::string &path) : m_dbPath(path),
  51. m_checksum(path), m_integrity(path) {
  52. }
  53. void InMemoryStorageBackend::load(void) {
  54. bool isBackupValid = m_integrity.backupGuardExists();
  55. std::string bucketSuffix = "";
  56. std::string indexFilename = m_dbPath + PathConfig::StoragePath::indexFilename;
  57. std::string chsFilename = m_dbPath + PathConfig::StoragePath::checksumFilename;
  58. if (isBackupValid) {
  59. bucketSuffix += PathConfig::StoragePath::backupFilenameSuffix;
  60. indexFilename += PathConfig::StoragePath::backupFilenameSuffix;
  61. chsFilename += PathConfig::StoragePath::backupFilenameSuffix;
  62. }
  63. try {
  64. std::ifstream chsStream;
  65. openFileStream(chsStream, chsFilename, isBackupValid);
  66. m_checksum.load(chsStream);
  67. auto indexStream = std::make_shared<std::ifstream>();
  68. openFileStream(*indexStream, indexFilename, isBackupValid);
  69. StorageDeserializer storageDeserializer(indexStream,
  70. std::bind(&InMemoryStorageBackend::bucketStreamOpener, this,
  71. std::placeholders::_1, bucketSuffix, isBackupValid));
  72. storageDeserializer.initBuckets(buckets());
  73. storageDeserializer.loadBuckets(buckets());
  74. } catch (const DatabaseException &) {
  75. LOGC("Reading cynara database failed.");
  76. buckets().clear();
  77. throw DatabaseCorruptedException();
  78. }
  79. m_checksum.clear();
  80. if (!hasBucket(defaultPolicyBucketId)) {
  81. LOGN("Creating defaultBucket.");
  82. this->buckets().insert({ defaultPolicyBucketId, PolicyBucket(defaultPolicyBucketId) });
  83. }
  84. postLoadCleanup(isBackupValid);
  85. }
  86. void InMemoryStorageBackend::saveBackup(void) {
  87. std::string checksumFilename = m_dbPath + PathConfig::StoragePath::checksumFilename;
  88. auto chsStream = std::make_shared<std::ofstream>();
  89. openDumpFileStream<std::ofstream>(*chsStream,
  90. checksumFilename + PathConfig::StoragePath::backupFilenameSuffix);
  91. dumpDatabase(chsStream);
  92. }
  93. void InMemoryStorageBackend::save(void) {
  94. saveBackup();
  95. m_integrity.syncDatabase(buckets(), true);
  96. m_integrity.createBackupGuard();
  97. m_integrity.revalidatePrimaryDatabase(buckets());
  98. //guard is removed during revalidation
  99. }
  100. PolicyBucket InMemoryStorageBackend::searchDefaultBucket(const PolicyKey &key) {
  101. return searchBucket(defaultPolicyBucketId, key);
  102. }
  103. PolicyBucket InMemoryStorageBackend::searchBucket(const PolicyBucketId &bucketId,
  104. const PolicyKey &key) {
  105. try {
  106. const auto &bucket = this->buckets().at(bucketId);
  107. return bucket.filtered(key);
  108. } catch (const std::out_of_range &) {
  109. throw BucketNotExistsException(bucketId);
  110. }
  111. }
  112. void InMemoryStorageBackend::insertPolicy(const PolicyBucketId &bucketId, PolicyPtr policy) {
  113. try {
  114. auto &bucket = buckets().at(bucketId);
  115. bucket.insertPolicy(policy);
  116. } catch (const std::out_of_range &) {
  117. throw BucketNotExistsException(bucketId);
  118. }
  119. }
  120. void InMemoryStorageBackend::createBucket(const PolicyBucketId &bucketId,
  121. const PolicyResult &defaultPolicy) {
  122. PolicyBucket newBucket(bucketId, defaultPolicy);
  123. buckets().insert({ bucketId, newBucket });
  124. }
  125. void InMemoryStorageBackend::updateBucket(const PolicyBucketId &bucketId,
  126. const PolicyResult &defaultPolicy) {
  127. try {
  128. auto &bucket = buckets().at(bucketId);
  129. bucket.setDefaultPolicy(defaultPolicy);
  130. } catch (const std::out_of_range &) {
  131. throw BucketNotExistsException(bucketId);
  132. }
  133. }
  134. void InMemoryStorageBackend::deleteBucket(const PolicyBucketId &bucketId) {
  135. auto bucketErased = buckets().erase(bucketId);
  136. if (bucketErased == 0) {
  137. throw BucketNotExistsException(bucketId);
  138. }
  139. }
  140. bool InMemoryStorageBackend::hasBucket(const PolicyBucketId &bucketId) {
  141. return buckets().find(bucketId) != buckets().end();
  142. }
  143. void InMemoryStorageBackend::deletePolicy(const PolicyBucketId &bucketId, const PolicyKey &key) {
  144. try {
  145. // TODO: Move the erase code to PolicyCollection maybe?
  146. auto &bucket = buckets().at(bucketId);
  147. bucket.deletePolicy(key);
  148. } catch (const std::out_of_range &) {
  149. throw BucketNotExistsException(bucketId);
  150. }
  151. }
  152. void InMemoryStorageBackend::deleteLinking(const PolicyBucketId &bucketId) {
  153. auto bucketIdMatches = [&bucketId] (PolicyPtr policy) -> bool {
  154. auto policyResult = policy->result();
  155. // Check bucket id only if policy is a bucket policy
  156. // TODO: Maybe move the test to PolicyResult
  157. if (policyResult.policyType() == PredefinedPolicyType::BUCKET) {
  158. return policyResult.metadata() == bucketId;
  159. }
  160. return false;
  161. };
  162. for (auto &bucketIter : buckets()) {
  163. auto &bucket = bucketIter.second;
  164. bucket.deletePolicy(bucketIdMatches);
  165. }
  166. }
  167. PolicyBucket::Policies InMemoryStorageBackend::listPolicies(const PolicyBucketId &bucketId,
  168. const PolicyKey &filter) const {
  169. try {
  170. auto &bucket = buckets().at(bucketId);
  171. return bucket.listPolicies(filter);
  172. } catch (const std::out_of_range &) {
  173. throw BucketNotExistsException(bucketId);
  174. }
  175. }
  176. void InMemoryStorageBackend::erasePolicies(const PolicyBucketId &bucketId, bool recursive,
  177. const PolicyKey &filter) {
  178. PolicyBucket::BucketIds bucketIds = {bucketId};
  179. while (!bucketIds.empty()) {
  180. auto it = bucketIds.begin();
  181. PolicyBucketId policyBucketId = *it;
  182. bucketIds.erase(it);
  183. try {
  184. auto &policyBucket = buckets().at(policyBucketId);
  185. if (recursive) {
  186. auto subBuckets = policyBucket.getSubBuckets();
  187. bucketIds.insert(subBuckets.begin(), subBuckets.end());
  188. }
  189. policyBucket.deletePolicy([&filter] (PolicyPtr policy) -> bool {
  190. return policy->key().matchFilter(filter);
  191. });
  192. } catch (const std::out_of_range &) {
  193. throw BucketNotExistsException(policyBucketId);
  194. }
  195. }
  196. }
  197. void InMemoryStorageBackend::dumpDatabase(const std::shared_ptr<std::ofstream> &chsStream) {
  198. auto indexStream = std::make_shared<ChecksumStream>(PathConfig::StoragePath::indexFilename,
  199. chsStream);
  200. std::string indexFilename = m_dbPath + PathConfig::StoragePath::indexFilename;
  201. openDumpFileStream<ChecksumStream>(*indexStream,
  202. indexFilename + PathConfig::StoragePath::backupFilenameSuffix);
  203. StorageSerializer<ChecksumStream> storageSerializer(indexStream);
  204. storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener,
  205. this, std::placeholders::_1, chsStream));
  206. }
  207. void InMemoryStorageBackend::openFileStream(std::ifstream &stream, const std::string &filename,
  208. bool isBackupValid) {
  209. // TODO: Consider adding exceptions to streams and handling them:
  210. // stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
  211. stream.open(filename);
  212. if (!stream.is_open()) {
  213. throw FileNotFoundException(filename);
  214. }
  215. m_checksum.compare(stream, filename, isBackupValid);
  216. }
  217. std::shared_ptr<BucketDeserializer> InMemoryStorageBackend::bucketStreamOpener(
  218. const PolicyBucketId &bucketId, const std::string &filenameSuffix, bool isBackupValid) {
  219. std::string bucketFilename = m_dbPath + PathConfig::StoragePath::bucketFilenamePrefix +
  220. bucketId + filenameSuffix;
  221. auto bucketStream = std::make_shared<std::ifstream>();
  222. try {
  223. openFileStream(*bucketStream, bucketFilename, isBackupValid);
  224. return std::make_shared<BucketDeserializer>(bucketStream);
  225. } catch (const FileNotFoundException &) {
  226. return nullptr;
  227. } catch (const std::bad_alloc &) {
  228. return nullptr;
  229. }
  230. }
  231. std::shared_ptr<StorageSerializer<ChecksumStream> > InMemoryStorageBackend::bucketDumpStreamOpener(
  232. const PolicyBucketId &bucketId, const std::shared_ptr<std::ofstream> &chsStream) {
  233. std::string bucketFilename = m_dbPath + PathConfig::StoragePath::bucketFilenamePrefix +
  234. bucketId + PathConfig::StoragePath::backupFilenameSuffix;
  235. auto bucketStream = std::make_shared<ChecksumStream>(
  236. PathConfig::StoragePath::bucketFilenamePrefix + bucketId, chsStream);
  237. openDumpFileStream<ChecksumStream>(*bucketStream, bucketFilename);
  238. return std::make_shared<StorageSerializer<ChecksumStream> >(bucketStream);
  239. }
  240. void InMemoryStorageBackend::postLoadCleanup(bool isBackupValid) {
  241. if (isBackupValid) {
  242. m_integrity.revalidatePrimaryDatabase(buckets());
  243. }
  244. //in case there were unnecessary files in db directory
  245. m_integrity.deleteNonIndexedFiles(std::bind(&InMemoryStorageBackend::hasBucket, this,
  246. std::placeholders::_1));
  247. }
  248. } /* namespace Cynara */