2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @file src/storage/InMemoryStorageBackend.cpp
18 * @author Aleksander Zdyb <a.zdyb@samsung.com>
20 * @brief Implementation of InMemoryStorageBackend
31 #include <sys/types.h>
32 #include <unordered_map>
36 #include <exceptions/BucketNotExistsException.h>
37 #include <exceptions/CannotCreateFileException.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>
45 #include <storage/BucketDeserializer.h>
46 #include <storage/StorageDeserializer.h>
47 #include <storage/StorageSerializer.h>
49 #include "InMemoryStorageBackend.h"
53 const std::string InMemoryStorageBackend::m_indexFileName = "buckets";
55 void InMemoryStorageBackend::load(void) {
56 std::string indexFilename = m_dbPath + m_indexFileName;
59 auto indexStream = std::make_shared<std::ifstream>();
60 openFileStream(indexStream, indexFilename);
62 StorageDeserializer storageDeserializer(indexStream,
63 std::bind(&InMemoryStorageBackend::bucketStreamOpener, this, std::placeholders::_1));
65 storageDeserializer.initBuckets(buckets());
66 storageDeserializer.loadBuckets(buckets());
67 } catch (const DatabaseException &) {
68 LOGC("Reading cynara database failed.");
70 // TODO: Implement emergency mode toggle
73 if (!hasBucket(defaultPolicyBucketId)) {
74 LOGN("Creating defaultBucket.");
75 this->buckets().insert({ defaultPolicyBucketId, PolicyBucket() });
79 void InMemoryStorageBackend::save(void) {
82 int ret = mkdir(m_dbPath.c_str(), S_IRWXU);
86 LOGE("Cannot create directory <%s>. Error [%d] : <%s>.",
87 m_dbPath.c_str(), err, strerror(err));
88 throw UnexpectedErrorException(err, strerror(err));
92 auto indexStream = std::make_shared<std::ofstream>();
93 openDumpFileStream(indexStream, m_dbPath + m_indexFileName);
95 StorageSerializer storageSerializer(indexStream);
96 storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener,
97 this, std::placeholders::_1));
100 PolicyBucket InMemoryStorageBackend::searchDefaultBucket(const PolicyKey &key) {
101 return searchBucket(defaultPolicyBucketId, key);
104 PolicyBucket InMemoryStorageBackend::searchBucket(const PolicyBucketId &bucketId,
105 const PolicyKey &key) {
107 const auto &bucket = this->buckets().at(bucketId);
108 return bucket.filtered(key);
109 } catch (const std::out_of_range &) {
110 throw BucketNotExistsException(bucketId);
114 void InMemoryStorageBackend::insertPolicy(const PolicyBucketId &bucketId, PolicyPtr policy) {
116 auto &bucket = buckets().at(bucketId);
117 bucket.insertPolicy(policy);
118 } catch (const std::out_of_range &) {
119 throw BucketNotExistsException(bucketId);
123 void InMemoryStorageBackend::createBucket(const PolicyBucketId &bucketId,
124 const PolicyResult &defaultPolicy) {
125 PolicyBucket newBucket(bucketId, defaultPolicy);
126 buckets().insert({ bucketId, newBucket });
129 void InMemoryStorageBackend::updateBucket(const PolicyBucketId &bucketId,
130 const PolicyResult &defaultPolicy) {
132 auto &bucket = buckets().at(bucketId);
133 bucket.setDefaultPolicy(defaultPolicy);
134 } catch (const std::out_of_range &) {
135 throw BucketNotExistsException(bucketId);
139 void InMemoryStorageBackend::deleteBucket(const PolicyBucketId &bucketId) {
140 auto bucketErased = buckets().erase(bucketId);
141 if (bucketErased == 0) {
142 throw BucketNotExistsException(bucketId);
146 bool InMemoryStorageBackend::hasBucket(const PolicyBucketId &bucketId) {
147 return buckets().find(bucketId) != buckets().end();
150 void InMemoryStorageBackend::deletePolicy(const PolicyBucketId &bucketId, const PolicyKey &key) {
152 // TODO: Move the erase code to PolicyCollection maybe?
153 auto &bucket = buckets().at(bucketId);
154 bucket.deletePolicy(key);
155 } catch (const std::out_of_range &) {
156 throw BucketNotExistsException(bucketId);
160 void InMemoryStorageBackend::deleteLinking(const PolicyBucketId &bucketId) {
161 auto bucketIdMatches = [&bucketId] (PolicyPtr policy) -> bool {
162 auto policyResult = policy->result();
164 // Check bucket id only if policy is a bucket policy
165 // TODO: Maybe move the test to PolicyResult
166 if (policyResult.policyType() == PredefinedPolicyType::BUCKET) {
167 return policyResult.metadata() == bucketId;
172 for (auto &bucketIter : buckets()) {
173 auto &bucket = bucketIter.second;
174 bucket.deletePolicy(bucketIdMatches);
178 void InMemoryStorageBackend::openFileStream(std::shared_ptr<std::ifstream> stream,
179 const std::string &filename) {
180 // TODO: Consider adding exceptions to streams and handling them:
181 // stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
182 stream->open(filename);
184 if (!stream->is_open())
185 throw FileNotFoundException(filename);
188 void InMemoryStorageBackend::openDumpFileStream(std::shared_ptr<std::ofstream> stream,
189 const std::string &filename) {
190 stream->open(filename, std::ofstream::out | std::ofstream::trunc);
192 if (!stream->is_open()) {
193 throw CannotCreateFileException(filename);
197 std::shared_ptr<BucketDeserializer> InMemoryStorageBackend::bucketStreamOpener(
198 const PolicyBucketId &bucketId) {
199 std::string bucketFilename = m_dbPath + "_" + bucketId;
200 auto bucketStream = std::make_shared<std::ifstream>();
202 openFileStream(bucketStream, bucketFilename);
203 return std::make_shared<BucketDeserializer>(bucketStream);
204 } catch (const FileNotFoundException &) {
209 std::shared_ptr<StorageSerializer> InMemoryStorageBackend::bucketDumpStreamOpener(
210 const PolicyBucketId &bucketId) {
211 std::string bucketFilename = m_dbPath + "_" + bucketId;
212 auto bucketStream = std::make_shared<std::ofstream>();
214 openDumpFileStream(bucketStream, bucketFilename);
215 return std::make_shared<StorageSerializer>(bucketStream);
218 } /* namespace Cynara */