Line data Source code
1 :
2 : /* Copyright (c) 2014-2015, Stefan.Eilemann@epfl.ch
3 : *
4 : * This library is free software; you can redistribute it and/or modify it under
5 : * the terms of the GNU Lesser General Public License version 2.1 as published
6 : * by the Free Software Foundation.
7 : *
8 : * This library is distributed in the hope that it will be useful, but WITHOUT
9 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
11 : * details.
12 : *
13 : * You should have received a copy of the GNU Lesser General Public License
14 : * along with this library; if not, write to the Free Software Foundation, Inc.,
15 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 : */
17 :
18 : #ifndef LUNCHBOX_PERSISTENTMAP_H
19 : #define LUNCHBOX_PERSISTENTMAP_H
20 :
21 : #include <lunchbox/api.h>
22 : #include <lunchbox/bitOperation.h> // byteswap()
23 : #include <lunchbox/debug.h> // className
24 : #include <lunchbox/log.h> // LBTHROW
25 : #include <lunchbox/types.h>
26 : #include <servus/uri.h>
27 :
28 : #include <boost/foreach.hpp>
29 : #include <boost/lexical_cast.hpp>
30 : #include <boost/noncopyable.hpp>
31 : #include <boost/type_traits.hpp>
32 :
33 : #include <iostream>
34 : #include <set>
35 : #include <stdexcept>
36 : #include <string>
37 : #include <vector>
38 :
39 : namespace lunchbox
40 : {
41 : namespace detail { class PersistentMap; }
42 :
43 : /**
44 : * Unified interface to save key-value pairs in a persistent store.
45 : *
46 : * Example: @include tests/persistentMap.cpp
47 : */
48 : class PersistentMap : public boost::noncopyable
49 : {
50 : public:
51 : /**
52 : * Construct a new persistent map.
53 : *
54 : * Depending on the URI scheme an implementation backend is chosen. If no
55 : * URI is given, a default one is selected. Available implementations are:
56 : * * leveldb://path (if LUNCHBOX_USE_LEVELDB is defined)
57 : * * skv://path_to_config\#pdsname (if LUNCHBOX_USE_SKV is defined)
58 : *
59 : * @param uri the storage backend and destination.
60 : * @throw std::runtime_error if no suitable implementation is found.
61 : * @throw std::runtime_error if opening the leveldb failed.
62 : * @version 1.9.2
63 : */
64 : LUNCHBOX_API PersistentMap( const std::string& uri = std::string( ));
65 :
66 : /**
67 : * Construct a persistent map using an URI. See other ctor for details.
68 : * @version 1.9.2
69 : */
70 : LUNCHBOX_API explicit PersistentMap( const servus::URI& uri );
71 :
72 : /** Destruct the persistent map. @version 1.9.2 */
73 : LUNCHBOX_API ~PersistentMap();
74 :
75 : /**
76 : * @return true if an implementation for the given URI is available.
77 : * @version 1.9.2
78 : */
79 : LUNCHBOX_API static bool handles( const servus::URI& uri );
80 :
81 : /**
82 : * Set the maximum number of asynchronous outstanding write operations.
83 : *
84 : * Some backend implementations support asynchronous writes, which can be
85 : * enabled by setting a non-zero queue depth. Applications then need to
86 : * quarantee that the inserted values stay valid until 'depth' other
87 : * elements have been inserted or flush() has been called. Implementations
88 : * which do not support asynchronous writes return 0.
89 : *
90 : * @return the queue depth chosen by the implementation, smaller or equal to
91 : * the given depth.
92 : * @version 1.11
93 : */
94 : LUNCHBOX_API size_t setQueueDepth( const size_t depth );
95 :
96 : /**
97 : * Insert or update a value in the database.
98 : *
99 : * @param key the key to store the value.
100 : * @param value the value stored at the key.
101 : * @return true on success, false otherwise
102 : * @throw std::runtime_error if the value is not copyable
103 : * @version 1.9.2
104 : */
105 0 : template< class V > bool insert( const std::string& key, const V& value )
106 0 : { return _insert( key, value, boost::has_trivial_assign< V >( )); }
107 :
108 : /**
109 : * Insert or update a vector of values in the database.
110 : *
111 : * @param key the key to store the value.
112 : * @param values the values stored at the key.
113 : * @return true on success, false otherwise
114 : * @throw std::runtime_error if the vector values are not copyable
115 : * @version 1.9.2
116 : */
117 : template< class V >
118 0 : bool insert( const std::string& key, const std::vector< V >& values )
119 0 : { return _insert( key, values, boost::has_trivial_assign< V >( )); }
120 :
121 : /**
122 : * Insert or update a set of values in the database.
123 : *
124 : * @param key the key to store the value.
125 : * @param values the values stored at the key.
126 : * @return true on success, false otherwise
127 : * @throw std::runtime_error if the set values are not copyable
128 : * @version 1.9.2
129 : */
130 : template< class V >
131 0 : bool insert( const std::string& key, const std::set< V >& values )
132 0 : { return insert( key, std::vector<V>( values.begin(), values.end( ))); }
133 :
134 : /**
135 : * Retrieve a value for a key.
136 : *
137 : * @param key the key to retrieve.
138 : * @return the value, or an empty string if the key is not available.
139 : * @version 1.9.2
140 : */
141 : LUNCHBOX_API std::string operator [] ( const std::string& key ) const;
142 :
143 : /**
144 : * Retrieve a value for a key.
145 : *
146 : * @param key the key to retrieve.
147 : * @return the value, or an empty string if the key is not available.
148 : * @version 1.11
149 : */
150 0 : template< class V > V get( const std::string& key ) const
151 0 : { return _get< V >( key ); }
152 :
153 : /**
154 : * Retrieve a value as a vector for a key.
155 : *
156 : * @param key the key to retrieve.
157 : * @return the values, or an empty vector if the key is not available.
158 : * @version 1.9.2
159 : */
160 : template< class V > std::vector< V > getVector( const std::string& key )
161 : const;
162 :
163 : /**
164 : * Retrieve a value as a set for a key.
165 : *
166 : * @param key the key to retrieve.
167 : * @return the values, or an empty set if the key is not available.
168 : * @version 1.9.2
169 : */
170 : template< class V > std::set< V > getSet( const std::string& key ) const;
171 :
172 : /**
173 : * Asynchronously retrieve a value which to be read later.
174 : *
175 : * Might be implemented as a 'NOP' by backend implementations.
176 : *
177 : * @param key the key to retrieve.
178 : * @param sizeHint the size of the value, may be ignored by implementation.
179 : * @return false on error, true otherwise.
180 : * @version 1.11
181 : */
182 : LUNCHBOX_API bool fetch( const std::string& key, size_t sizeHint = 0 ) const;
183 :
184 : /** @return true if the key exists. @version 1.9.2 */
185 : LUNCHBOX_API bool contains( const std::string& key ) const;
186 :
187 : /** Flush outstanding operations to the backend storage. @version 1.11 */
188 : LUNCHBOX_API bool flush();
189 :
190 : /** Enable or disable endianness conversion on reads. @version 1.11 */
191 : LUNCHBOX_API void setByteswap( const bool swap );
192 :
193 : private:
194 : detail::PersistentMap* const _impl;
195 :
196 : LUNCHBOX_API bool _insert( const std::string& key, const void* data,
197 : const size_t size );
198 : LUNCHBOX_API bool _swap() const;
199 :
200 :
201 : // Enables map.insert( "foo", "bar" ); bar is a char[4]. The funny braces
202 : // declare v as a "const ref to array of four chars", not as a "const array
203 : // to four char refs". Long live Bjarne!
204 : template< size_t N > bool
205 0 : _insert( const std::string& k, char const (& v)[N], const boost::true_type&)
206 : {
207 0 : return _insert( k, (void*)v, N - 1 ); // strip '0'
208 : }
209 :
210 : template< class V >
211 0 : bool _insert( const std::string& k, const V& v, const boost::true_type& )
212 : {
213 : if( boost::is_pointer< V >::value )
214 : LBTHROW( std::runtime_error( "Can't insert pointers" ));
215 0 : return _insert( k, &v, sizeof( V ));
216 : }
217 :
218 : template< class V >
219 : bool _insert( const std::string&, const V& v, const boost::false_type& )
220 : { LBTHROW( std::runtime_error( "Can't insert non-POD " + className( v ))); }
221 :
222 : template< class V >
223 0 : bool _insert( const std::string& key, const std::vector< V >& values,
224 : const boost::true_type& )
225 0 : { return _insert( key, values.data(), values.size() * sizeof( V )); }
226 :
227 0 : template< class V > V _get( const std::string& k ) const
228 : {
229 0 : if( !boost::has_trivial_assign< V >( ))
230 0 : LBTHROW( std::runtime_error( "Can't retrieve non-POD " +
231 : className( V( ))));
232 : if( boost::is_pointer< V >::value )
233 : LBTHROW( std::runtime_error( "Can't retrieve pointers" ));
234 :
235 0 : const std::string& value = (*this)[ k ];
236 0 : if( value.size() != sizeof( V ))
237 0 : LBTHROW( std::runtime_error( std::string( "Wrong value size " ) +
238 : boost::lexical_cast< std::string >( value.size( )) +
239 : " for type " + className( V( ))));
240 :
241 0 : V v( *reinterpret_cast< const V* >( value.data( )));
242 0 : if( _swap( ))
243 0 : byteswap( v );
244 0 : return v;
245 : }
246 : };
247 :
248 : template<> inline
249 0 : bool PersistentMap::_insert( const std::string& k, const std::string& v,
250 : const boost::false_type& )
251 : {
252 0 : return _insert( k, v.data(), v.length( ));
253 : }
254 :
255 : template< class V > inline
256 0 : std::vector< V > PersistentMap::getVector( const std::string& key ) const
257 : {
258 0 : const std::string& value = (*this)[ key ];
259 0 : std::vector< V > vector( reinterpret_cast< const V* >( value.data( )),
260 0 : reinterpret_cast< const V* >( value.data() + value.size( )));
261 0 : if( _swap() && sizeof( V ) != 1 )
262 : {
263 0 : BOOST_FOREACH( V& elem, vector )
264 0 : byteswap( elem );
265 : }
266 0 : return vector;
267 : }
268 :
269 : template< class V > inline
270 0 : std::set< V > PersistentMap::getSet( const std::string& key ) const
271 : {
272 0 : std::string value = (*this)[ key ];
273 : V* const begin = reinterpret_cast< V* >(
274 0 : const_cast< char * >( value.data( )));
275 0 : V* const end = begin + value.size() / sizeof( V );
276 :
277 0 : if( _swap() && sizeof( V ) != 1 )
278 0 : for( V* i = begin; i < end; ++i )
279 0 : byteswap( *i );
280 :
281 0 : return std::set< V >( begin, end );
282 : }
283 :
284 : }
285 :
286 : #endif //LUNCHBOX_PERSISTENTMAP_H
|