libmoost
/home/mhx/git/github/libmoost/include/moost/kvstore/mock_connection.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 
00029 
00030 
00031 
00032 
00033 #ifndef FM_LAST_KVSTORE_MOCK_CONNECTION_HPP
00034 #define FM_LAST_KVSTORE_MOCK_CONNECTION_HPP
00035 
00036 #include "i_kyoto_tycoon_connection.h"
00037 
00038 #include <string>
00039 #include <vector>
00040 #include <map>
00041 #include <ctime>
00042 
00043 #include <boost/thread/mutex.hpp>
00044 
00045 namespace moost { namespace kvstore {
00046 
00047 class DefaultAccessPolicy
00048 {
00049 public:
00050    template <class StoreT>
00051    static boost::shared_array<char> get(StoreT& store, const char* pkey, size_t ksize, size_t& vsize)
00052    {
00053       std::string key(pkey, ksize);
00054       return store.get(key, vsize);
00055    }
00056 
00057    // throws on failure, supply key "fail" to force failure
00058    template <class StoreT>
00059    static void set(StoreT& store, const char* pkey, size_t ksize, const char* pval, size_t vsize)
00060    {
00061       std::string key(pkey, ksize);
00062       store.set(key, pval, vsize);
00063    }
00064 
00065    // throws on failure, supply key "fail" to force failure
00066    template <class StoreT>
00067    static void cache(StoreT& store, const char* pkey, size_t ksize, const char* pval, size_t vsize, int expiryTime)
00068    {
00069       std::string key(pkey, ksize);
00070       store.cache(key, pval, vsize, expiryTime);
00071    }
00072 };
00073 
00074 template <class AccessPolicy = DefaultAccessPolicy>
00075 class MockKyotoTycoonConnection : public IKyotoTycoonConnection
00076 {
00077 public:
00078 
00079    MockKyotoTycoonConnection() : isOpen_(false) { }
00080 
00081    ~MockKyotoTycoonConnection() { close(); }
00082 
00083    void open(const std::string& /*host*/, int /*port*/, int /*timeoutMs*/)
00084    {
00085       if (isOpen_) { throw std::runtime_error("The connection is already open"); }
00086       // initialize singleton
00087       store();
00088       isOpen_ = true;
00089    }
00090 
00091    void close()
00092    {
00093       isOpen_ = false;
00094    }
00095 
00096 public:
00097 
00098    // if key is found then return value is a C-style string
00099    // of length vsize (not including the trailing null byte)
00100    boost::shared_array<char> get(const void* pkey, size_t ksize, size_t& vsize) const
00101    {
00102       assert_data_store_open();
00103       return AccessPolicy::get(store(), reinterpret_cast<const char *>(pkey), ksize, vsize);
00104    }
00105 
00106    // throws on failure, supply key "fail" to force failure
00107    virtual void set(const void* pkey, size_t ksize, const void* pval, size_t vsize) const
00108    {
00109       assert_data_store_open();
00110       AccessPolicy::set(store(), reinterpret_cast<const char *>(pkey), ksize, reinterpret_cast<const char *>(pval), vsize);
00111    }
00112 
00113    // throws on failure, supply key "fail" to force failure
00114    virtual void cache(const void* pkey, size_t ksize, const void* pval, size_t vsize, boost::int64_t expirySecs) const
00115    {
00116       assert_data_store_open();
00117       boost::int64_t expiryTime = time(0) + expirySecs;
00118       AccessPolicy::cache(store(), reinterpret_cast<const char *>(pkey), ksize, reinterpret_cast<const char *>(pval), vsize, expiryTime);
00119    }
00120 
00121 private:
00122 
00123    void assert_data_store_open() const
00124    {
00125       assert(isOpen_);
00126       if (!isOpen_)
00127          throw std::runtime_error("Mock Kyoto Tycoon connection not open");
00128    }
00129 
00130 private:
00131 
00132    class Store
00133    {
00134    private:
00135 
00136       typedef std::vector<char> entry_t;
00137       typedef std::map<std::string, entry_t> store_t;
00138       typedef std::map<std::string, time_t> expiry_store_t;
00139 
00140       mutable boost::mutex mutex_;  // synchronize access to store and expiry store
00141       store_t db_;
00142       expiry_store_t expiry_;
00143 
00144    public:
00145 
00146       // return a copy of the stored char*
00147       // or 0 if not found
00148       boost::shared_array<char> get(const std::string& key, size_t& vsize) const
00149       {
00150          boost::shared_array<char> val;
00151          vsize = 0;
00152          time_t expiry;
00153 
00154          boost::mutex::scoped_lock lock(mutex_);
00155 
00156          if (!get(key, expiry, expiry_) || expiry >= time(0))
00157          {
00158             entry_t entry;
00159             if (get(key, entry, db_))
00160             {
00161                vsize = entry.size();
00162                val.reset(new char[vsize+1]);
00163                memcpy(val.get(), &entry[0], entry.size());
00164                val[vsize] = 0;
00165             }
00166          }
00167 
00168          return val;
00169       }
00170 
00171       void set(const std::string& key, const char* val, size_t vsize)
00172       {
00173          boost::mutex::scoped_lock lock(mutex_);
00174          db_[key].assign(val, val + vsize);
00175          // remove any existing expiry time for key
00176          expiry_store_t::iterator it = expiry_.find(key);
00177          if (it != expiry_.end())
00178             expiry_.erase(it);
00179       }
00180 
00181      void cache(const std::string& key, const char* val, size_t vsize, boost::int64_t expirySecs)
00182       {
00183          boost::mutex::scoped_lock lock(mutex_);
00184          db_[key].assign(val, val + vsize);
00185          expiry_[key] = time(0) + static_cast<time_t>(expirySecs);
00186       }
00187 
00188    private:
00189 
00190       template <typename TKey, typename TVal, typename TMap>
00191       bool get(const TKey& key, TVal& val, TMap& store) const
00192       {
00193          typename TMap::const_iterator it = store.find(key);
00194          bool found = (it != store.end());
00195          if (found)
00196             val = it->second;
00197          return found;
00198       }
00199    };
00200 
00201    bool isOpen_;
00202 
00203    // singleton store
00204    static Store& store()
00205    {
00206       static Store store_;
00207       return store_;
00208    }
00209 };
00210 
00211 }}  // end namespace
00212 
00213 #endif