libmoost
/home/mhx/git/github/libmoost/include/moost/kvds/kvds_mem.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00040 
00041 #include <cstdlib>
00042 #include <cstring>
00043 #include <stdexcept>
00044 #include <fstream>
00045 #include <vector>
00046 #include <map>
00047 
00048 #include <boost/type_traits.hpp>
00049 #include <boost/static_assert.hpp>
00050 #include <boost/cast.hpp>
00051 
00052 #include "ikvds.hpp"
00053 
00054 #ifndef MOOST_KVDS_KVDSMEM_HPP__
00055 #define MOOST_KVDS_KVDSMEM_HPP__
00056 
00057 namespace moost { namespace kvds {
00058 
00059    typedef std::vector<char> byte_array_t;
00060 
00062 
00063    template <typename T>
00064    class KvdsMem : public IKvds
00065    {
00066    public:
00067       typedef T store_type;
00068       typedef typename T::key_type key_type;
00069       typedef typename T::mapped_type val_type;
00070 
00071       KvdsMem() : itr_(store_.end()){}
00072       ~KvdsMem()
00073       {
00074          if(!dsname_.empty())
00075          {
00076             close();
00077          }
00078       }
00079 
00080       void open (char const dsname [], bool newdb = false)
00081       {
00082          if(!dsname_.empty()) { throw std::runtime_error("The store is already open"); }
00083 
00084          dsname_ = dsname;
00085 
00086          if(newdb)
00087          {
00088             // Truncate database if it already exists
00089             std::ofstream(dsname_.c_str(), std::ios::binary | std::ios::trunc);
00090          }
00091          else
00092          {
00093             std::ifstream in(dsname_.c_str(), std::ios::binary);
00094             in.exceptions(std::ios::badbit);
00095 
00096             try
00097             {
00098                if(in.is_open()) // Failure to open is fine, this could be a new store
00099                {
00100                   key_type key;
00101 
00102                   while(in)
00103                   {
00104                      size_t key_size = 0;
00105                      in.read(reinterpret_cast<char *>(&key_size), sizeof(key_size));
00106 
00107                      if(key_size > 0)
00108                      {
00109                         key.resize(key_size / sizeof(typename key_type::value_type));
00110                         in.read(reinterpret_cast<char *>(&key[0]), boost::numeric_cast<std::streamsize>(key_size));
00111 
00112                         size_t val_size = 0;
00113                         in.read(reinterpret_cast<char *>(&val_size), sizeof(val_size));
00114 
00115                         if(val_size > 0)
00116                         {
00117                            val_type & val = store_[key];
00118                            val.resize(val_size / sizeof(typename val_type::value_type));
00119 
00120                            if(in)
00121                            {
00122                               in.read(reinterpret_cast<char *>(&val[0]), boost::numeric_cast<std::streamsize>(val_size));
00123                            }
00124                         }
00125                      }
00126                   }
00127                }
00128             }
00129             catch(...)
00130             {
00131                dsname_.clear(); // On close, ensure we don't save bad data and cause potential corruption!
00132                throw;
00133             }
00134          }
00135       }
00136 
00137 
00138       void save()
00139       {
00140          if(!dsname_.empty())
00141          {
00142             std::ofstream out(dsname_.c_str(), std::ios::binary);
00143             out.exceptions(std::ios::badbit | std::ios::failbit);
00144 
00145             for(typename store_type::const_iterator itr = store_.begin() ; itr != store_.end() ; ++itr)
00146             {
00147                size_t key_size = itr->first.size();
00148                out.write(reinterpret_cast<char const *>(&key_size), sizeof(key_size));
00149                out.write(reinterpret_cast<char const *>(&itr->first[0]), boost::numeric_cast<std::streamsize>(key_size));
00150 
00151                size_t val_size = itr->second.size();
00152                out.write(reinterpret_cast<char const *>(&val_size), sizeof(val_size));
00153                out.write(reinterpret_cast<char const *>(&itr->second[0]), boost::numeric_cast<std::streamsize>(val_size));
00154             }
00155 
00156             dsname_.clear();
00157          }
00158       }
00159 
00160       void close()
00161       {
00162          save();
00163       }
00164 
00165    private:
00166       std::string dsname_;
00167 
00168    private:
00170       BOOST_STATIC_ASSERT((boost::is_same<key_type, byte_array_t>::value));
00171       BOOST_STATIC_ASSERT((boost::is_same<val_type, byte_array_t>::value));
00172 
00173    public:
00177       store_type & get_store() { return store_; }
00178 
00179    public: 
00180       bool put(
00181          void const * pkey, size_t const ksize,
00182          void const * pval, size_t const vsize
00183          )
00184       {
00185          key_type key(ksize);
00186          memcpy (&key[0], pkey, ksize);
00187 
00188          val_type & vt = store_[key];
00189 
00190          vt.resize(vsize);
00191          memcpy (&vt[0], pval, vsize);
00192 
00193          return true;
00194       }
00195 
00196       bool get(
00197          void const * pkey, size_t const ksize,
00198          void * pval, size_t & vsize
00199          )
00200       {
00201          key_type key(ksize);
00202          memcpy (&key[0], pkey, ksize);
00203 
00204          typename store_type::const_iterator itr = store_.find(key);
00205 
00206          bool found = itr != store_.end();
00207 
00208          if(found)
00209          {
00210             vsize = std::min(vsize, itr->second.size());
00211             memcpy(pval, &itr->second[0], vsize);
00212          }
00213          else { vsize = 0; }
00214 
00215          return found;
00216       }
00217 
00218       bool add(
00219          void const * pkey, size_t const ksize,
00220          void const * pval, size_t const vsize
00221          )
00222       {
00223          key_type key(ksize);
00224          memcpy (&key[0], pkey, ksize);
00225 
00226          val_type & vt = store_[key];
00227 
00228          size_t const osize = vt.size();
00229          vt.resize(osize + vsize);
00230          memcpy (&vt[osize], pval, vsize);
00231 
00232          return true;
00233       }
00234 
00235       bool all(
00236          void const * pkey, size_t const ksize,
00237          void * pval, size_t & vsize
00238          )
00239       {
00240          bool found = false;
00241          size_t esize = 0;
00242 
00243          if(siz(pkey, ksize, esize))
00244          {
00245             if(esize <= vsize)
00246             {
00247                found = get(
00248                   pkey, ksize,
00249                   pval, esize
00250                   );
00251             }
00252 
00253             vsize = esize;
00254          }
00255          else { vsize = 0; }
00256 
00257          return found;
00258       }
00259 
00260       bool xst(
00261          void const * pkey, size_t const ksize
00262          )
00263       {
00264          key_type key(ksize);
00265          memcpy (&key[0], pkey, ksize);
00266          return store_.find(key) != store_.end();
00267       }
00268 
00269       bool del(
00270          void const * pkey, size_t const ksize
00271          )
00272       {
00273          bool removed = false;
00274 
00275          key_type key(ksize);
00276          memcpy (&key[0], pkey, ksize);
00277 
00278          typename store_type::iterator itr = store_.find(key);
00279 
00280          if(itr != store_.end())
00281          {
00282             store_.erase(itr);
00283             removed = true;
00284          }
00285 
00286          return removed;
00287       }
00288 
00289       bool clr()
00290       {
00291          store_.clear();
00292          return true;
00293       }
00294 
00295       bool beg()
00296       {
00297          itr_ = store_.begin();
00298          return true;
00299       }
00300 
00301       bool nxt(
00302          void * pkey, size_t & ksize
00303          )
00304       {
00305          bool found = false;
00306 
00307          if(itr_ != store_.end())
00308          {
00309             size_t const size = itr_->first.size();
00310 
00311             if(size <= ksize)
00312             {
00313                memcpy(pkey, &itr_->first[0], size);
00314                ++itr_;
00315                found = true;
00316             }
00317 
00318             ksize = size;
00319          }
00320          else
00321          {
00322             ksize = 0;
00323          }
00324 
00325          return found;
00326       }
00327 
00328       bool end()
00329       {
00330          return itr_ == store_.end();
00331       }
00332 
00333       bool siz(
00334          void const * pkey, size_t const ksize,
00335          size_t & vsize
00336          )
00337 
00338       {
00339          key_type key(ksize);
00340          memcpy (&key[0], pkey, ksize);
00341 
00342          typename store_type::const_iterator itr = store_.find(key);
00343 
00344          bool found = itr != store_.end();
00345 
00346          if(itr != store_.end())
00347          {
00348             vsize = itr->second.size();
00349          }
00350 
00351          return found;
00352       }
00353 
00354       bool cnt(boost::uint64_t & cnt)
00355       {
00356          cnt = store_.size();
00357          return true;
00358       }
00359 
00360       bool nil(bool & isnil)
00361       {
00362          isnil = store_.empty();
00363          return true;
00364       }
00365 
00366    private:
00367       store_type store_;
00368       typename store_type::const_iterator itr_;
00369 
00370    };
00371 
00373    typedef KvdsMem<std::map<byte_array_t, byte_array_t> > KvdsMemMap;
00374 
00375 }}
00376 
00377 #endif /// MOOST_KVDS_KVDSMEM_HPP__