Fix potential deadlock; FromKVJsonVisitor use db transaction
[archive/platform/core/system/libConfig.git] / src / config / kvstore.hpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Jan Olszak <j.olszak@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 /**
20  * @file
21  * @author Jan Olszak (j.olszak@samsung.com)
22  * @brief  Declaration of a class for key-value storage in a sqlite3 database
23  */
24
25 #ifndef COMMON_CONFIG_KVSTORE_HPP
26 #define COMMON_CONFIG_KVSTORE_HPP
27
28 #include "config/sqlite3/connection.hpp"
29 #include "config/sqlite3/statement.hpp"
30
31 #include <algorithm>
32 #include <initializer_list>
33 #include <memory>
34 #include <mutex>
35 #include <sstream>
36 #include <string>
37 #include <vector>
38 #include <atomic>
39
40 namespace config {
41
42 class KVStore {
43
44 public:
45     /**
46      * A guard struct for thread synchronization and transaction management.
47      */
48     typedef std::shared_ptr<void> Transaction;
49
50     /**
51      * @param path configuration database file path
52      */
53     explicit KVStore(const std::string& path);
54     ~KVStore();
55
56     KVStore(const KVStore&) = delete;
57     KVStore& operator=(const KVStore&) = delete;
58
59     /**
60      * Clears all the stored data
61      */
62     void clear();
63
64     /**
65      * @return Is there any data stored
66      */
67     bool isEmpty();
68
69     /**
70      * @param key string regexp of the stored values
71      *
72      * @return Does this key exist in the database
73      */
74     bool exists(const std::string& key);
75
76     /**
77      * Removes values corresponding to the passed key.
78      * Many values may correspond to one key, so many values may
79      * need to be deleted
80      *
81      * @param key string regexp of the stored values
82      */
83     void remove(const std::string& key);
84
85     /**
86      * Stores a single value corresponding to the passed key
87      *
88      * @param key string key of the value
89      * @param value value corresponding to the key
90      */
91     template<typename T>
92     void set(const std::string& key, const T& value)
93     {
94         return setInternal(key, value);
95     }
96
97     /**
98      * Gets the value corresponding to the key.
99      * Uses stringstreams to parse.
100      *
101      * @param key string key of the value
102      * @tparam T = std::string desired type of the return value
103      * @return value corresponding to the key
104      */
105     template<typename T = std::string>
106     T get(const std::string& key)
107     {
108         return getInternal(key, static_cast<T*>(nullptr));
109     }
110
111     /**
112      * Returns all stored keys.
113      */
114     std::vector<std::string> getKeys();
115
116     KVStore::Transaction getTransaction();
117
118 private:
119     typedef std::lock_guard<std::recursive_mutex> Lock;
120
121     struct TransactionImpl;
122     std::weak_ptr<TransactionImpl> mTransactionImplPtr;
123     std::recursive_mutex mMutex;
124
125     void setInternal(const std::string& key, const std::string& value);
126     void setInternal(const std::string& key, const std::initializer_list<std::string>& values);
127     void setInternal(const std::string& key, const std::vector<std::string>& values);
128     template<typename T>
129     void setInternal(const std::string& key, const T& value);
130     template<typename T>
131     void setInternal(const std::string& key, const std::vector<T>& values);
132
133     std::string getInternal(const std::string& key, std::string*);
134     std::vector<std::string> getInternal(const std::string& key, std::vector<std::string>*);
135     template<typename T>
136     T getInternal(const std::string& key, T*);
137     template<typename T>
138     std::vector<T> getInternal(const std::string& key, std::vector<T>*);
139
140     std::string mPath;
141     sqlite3::Connection mConn;
142     std::unique_ptr<sqlite3::Statement> mGetValueStmt;
143     std::unique_ptr<sqlite3::Statement> mGetKeyExistsStmt;
144     std::unique_ptr<sqlite3::Statement> mGetIsEmptyStmt;
145     std::unique_ptr<sqlite3::Statement> mGetValueListStmt;
146     std::unique_ptr<sqlite3::Statement> mSetValueStmt;
147     std::unique_ptr<sqlite3::Statement> mRemoveValuesStmt;
148     std::unique_ptr<sqlite3::Statement> mGetKeysStmt;
149
150     void setupDb();
151     void prepareStatements();
152     void createFunctions();
153 };
154
155 namespace {
156 template<typename T>
157 std::string toString(const T& value)
158 {
159     std::ostringstream oss;
160     oss << value;
161     return oss.str();
162 }
163
164 template<typename T>
165 T fromString(const std::string& strValue)
166 {
167     std::istringstream iss(strValue);
168     T value;
169     iss >> value;
170     return value;
171 }
172
173 } // namespace
174
175 template<typename T>
176 void KVStore::setInternal(const std::string& key, const T& value)
177 {
178     setInternal(key, toString(value));
179 }
180
181 template<typename T>
182 void KVStore::setInternal(const std::string& key, const std::vector<T>& values)
183 {
184     std::vector<std::string> strValues(values.size());
185
186     std::transform(values.begin(),
187                    values.end(),
188                    strValues.begin(),
189                    toString<T>);
190
191     setInternal(key, strValues);
192 }
193
194 template<typename T>
195 T KVStore::getInternal(const std::string& key, T*)
196 {
197     return fromString<T>(getInternal(key, static_cast<std::string*>(nullptr)));
198 }
199
200 template<typename T>
201 std::vector<T> KVStore::getInternal(const std::string& key, std::vector<T>*)
202 {
203     std::vector<std::string> strValues = getInternal(key, static_cast<std::vector<std::string>*>(nullptr));
204     std::vector<T> values(strValues.size());
205
206     std::transform(strValues.begin(),
207                    strValues.end(),
208                    values.begin(),
209                    fromString<T>);
210
211     return values;
212 }
213
214 /**
215  * Concatenates all parameters into one std::string.
216  * Uses '.' to connect the terms.
217  * @param args components of the string
218  * @tparam delim optional delimiter
219  * @tparam typename ... Args any type implementing str
220  * @return string created from he args
221  */
222 template<char delim = '.', typename Arg1, typename ... Args>
223 std::string key(const Arg1& a1, const Args& ... args)
224 {
225     std::string ret = toString(a1);
226     std::initializer_list<std::string> strings {toString(args)...};
227     for (const std::string& s : strings) {
228         ret += delim + s;
229     }
230
231     return ret;
232 }
233
234 /**
235  * Function added for key function completeness.
236  *
237  * @tparam delim = '.' parameter not used, added for consistency
238  * @return empty string
239  */
240 template<char delim = '.'>
241 std::string key()
242 {
243     return std::string();
244 }
245
246 } // namespace config
247
248 #endif // COMMON_CONFIG_KVSTORE_HPP
249
250