libmoost
|
00001 /* vim:set ts=3 sw=3 sts=3 et: */ 00028 00029 00030 00031 00032 00033 #ifndef MOOST_KVDS_KVDSKCH_LINUX_HPP__ 00034 #define MOOST_KVDS_KVDSKCH_LINUX_HPP__ 00035 00036 #include <cstdlib> 00037 #include <cstring> 00038 #include <stdexcept> 00039 #include <sstream> 00040 #include <limits> 00041 00042 #include <boost/scoped_array.hpp> 00043 00044 #if defined (_STDINT_H) 00045 #define STDINT_H_3C996A98_ABAB_4d71_AC4B_633055150696 00046 #undef _STDINT_H 00047 #endif 00048 00049 #include <kchashdb.h> 00050 00051 #ifdef STDINT_H_3C996A98_ABAB_4d71_AC4B_633055150696 00052 #undef STDINT_H_3C996A98_ABAB_4d71_AC4B_633055150696 00053 #if !defined (_STDINT_H) 00054 #define _STDINT_H 00055 #endif 00056 #else 00057 #undef _STDINT_H 00058 #endif 00059 00060 #include <boost/cast.hpp> 00061 00062 #include "../ikvds.hpp" 00063 00064 namespace moost { namespace kvds { 00065 00066 class KvdsKch : public IKvds 00067 { 00068 public: 00069 typedef kyotocabinet::HashDB store_type; 00070 00071 KvdsKch() : bOpen_(false), pcursor_(0) 00072 { 00073 } 00074 00075 ~KvdsKch() 00076 { 00077 try 00078 { 00079 close(); 00080 } 00081 catch(...) { /* ignore */ } 00082 } 00083 00084 void open (char const dsname [], bool newdb = false) 00085 { 00086 if(bOpen_) { throw std::runtime_error("The store is already open"); } 00087 00088 uint32_t const OMODE = (newdb ? kyotocabinet::HashDB::OTRUNCATE : 0) 00089 | (kyotocabinet::HashDB::OWRITER | kyotocabinet::HashDB::OREADER | kyotocabinet::HashDB::OCREATE); 00090 00091 bOpen_ = db_.open(dsname, OMODE); 00092 00093 if(!bOpen_) 00094 { 00095 throw_kch_exception("Failed to open KCH file"); 00096 } 00097 } 00098 00099 void save() { /* nothing to do, fully persisted storage */ } 00100 00101 void close() 00102 { 00103 release_cursor(); 00104 00105 if(bOpen_) 00106 { 00107 if (!db_.close()) 00108 throw_kch_exception(); 00109 bOpen_ = false; 00110 } 00111 } 00112 00116 store_type & get_store() { return db_; } 00117 00118 private: 00119 bool set_cursor() 00120 { 00121 release_cursor(); 00122 pcursor_ = db_.cursor(); 00123 // move to first record if there is one 00124 bool ok = true; 00125 if (!pcursor_->jump()) 00126 { 00127 release_cursor(); 00128 ok = false; 00129 } 00130 return ok; 00131 } 00132 00133 void release_cursor() 00134 { 00135 delete pcursor_; 00136 pcursor_ = 0; 00137 } 00138 00139 void throw_kch_exception(const std::string& msg) const 00140 { 00141 throw std::runtime_error(msg + ": " + db_.error().name()); 00142 } 00143 00144 void throw_kch_exception() const 00145 { 00146 throw_kch_exception("ERROR"); 00147 } 00148 00149 void assert_data_store_open() const 00150 { 00151 assert(bOpen_); 00152 } 00153 00154 public: // IKvds interface implementation 00155 00156 bool put( 00157 void const * pkey, size_t const ksize, 00158 void const * pval, size_t const vsize 00159 ) 00160 { 00161 assert_data_store_open(); 00162 return db_.set(static_cast<const char*>(pkey), ksize, static_cast<const char*>(pval), vsize); 00163 } 00164 00165 bool get( 00166 void const * pkey, size_t const ksize, 00167 void * pval, size_t & vsize 00168 ) 00169 { 00170 assert_data_store_open(); 00171 00172 int32_t const esize = db_.get((char *)pkey, ksize, (char *)pval, vsize); 00173 00174 bool found = (esize >= 0); 00175 00176 if(found) 00177 { 00178 vsize = std::min(vsize, (size_t) esize); 00179 } 00180 else { vsize = 0; } 00181 00182 return found; 00183 } 00184 00185 bool all( 00186 void const * pkey, size_t const ksize, 00187 void * pval, size_t & vsize 00188 ) 00189 { 00190 assert_data_store_open(); 00191 00192 bool found = false; 00193 size_t esize = 0; 00194 00195 if(siz(pkey, ksize, esize)) 00196 { 00197 if(esize <= vsize) 00198 { 00199 found = get( 00200 pkey, ksize, 00201 pval, esize 00202 ); 00203 } 00204 00205 vsize = esize; 00206 } 00207 else { vsize = 0; } 00208 00209 00210 return found; 00211 } 00212 00213 bool add( 00214 void const * pkey, size_t const ksize, 00215 void const * pval, size_t const vsize 00216 ) 00217 { 00218 assert_data_store_open(); 00219 return db_.append(static_cast<const char*>(pkey), ksize, static_cast<const char*>(pval), vsize); 00220 } 00221 00222 bool xst( 00223 void const * pkey, size_t const ksize 00224 ) 00225 { 00226 size_t size; 00227 return siz(pkey, ksize, size) > 0; 00228 } 00229 00230 bool del( 00231 void const * pkey, size_t const ksize 00232 ) 00233 { 00234 assert_data_store_open(); 00235 return db_.remove(static_cast<const char*>(pkey), ksize); 00236 } 00237 00238 bool clr() 00239 { 00240 assert_data_store_open(); 00241 return db_.clear(); 00242 } 00243 00244 bool beg() 00245 { 00246 assert_data_store_open(); 00247 return bOpen_ && set_cursor(); 00248 } 00249 00250 bool nxt( 00251 void * pkey, size_t & ksize 00252 ) 00253 { 00254 assert(bOpen_); 00255 00256 bool found = false;; 00257 00258 if (pcursor_) 00259 { 00260 size_t size; 00261 boost::scoped_array<char> pk(pcursor_->get_key(&size)); // alloc'd via new [] 00262 00263 if (size <= ksize) 00264 { 00265 memcpy(pkey, pk.get(), size); 00266 found = true; 00267 if (!pcursor_->step()) 00268 release_cursor(); 00269 } 00270 00271 ksize = size; 00272 } 00273 else 00274 { 00275 ksize = 0; 00276 } 00277 00278 return found; 00279 } 00280 00281 bool end() 00282 { 00283 return 0 == pcursor_; 00284 } 00285 00286 bool siz( 00287 void const * pkey, size_t const ksize, 00288 size_t & vsize 00289 ) 00290 { 00291 assert_data_store_open(); 00292 00293 boost::scoped_array<char> pval(db_.get(static_cast<const char*>(pkey), ksize, &vsize)); // alloc'd via new [] 00294 return (bool)pval; // true if set else false 00295 } 00296 00297 bool cnt(boost::uint64_t & cnt) 00298 { 00299 assert_data_store_open(); 00300 cnt = db_.count(); 00301 return cnt < boost::uint64_t(-1); 00302 } 00303 00304 bool nil(bool & isnil) 00305 { 00306 boost::uint64_t icnt = 0; 00307 bool ok = cnt(icnt); 00308 if(ok) { isnil = (0 == icnt); } 00309 return ok; 00310 } 00311 00312 private: 00313 store_type db_; 00314 bool bOpen_; 00315 kyotocabinet::HashDB::Cursor* pcursor_; 00316 }; 00317 00318 }} 00319 00320 #endif // MOOST_KVDS_KVDSKCH_LINUX_HPP__