#define LIBMEMCACHEDPP_H
#include <libmemcached/memcached.h>
+#include <libmemcached/exception.hpp>
#include <string.h>
+#include <sstream>
#include <string>
#include <vector>
#include <map>
Memcache()
:
+ servers_list(),
memc(),
+ servers(NULL),
result()
{
memcached_create(&memc);
}
+ Memcache(const std::string &in_servers_list)
+ :
+ servers_list(in_servers_list),
+ memc(),
+ servers(NULL),
+ result()
+ {
+ memcached_create(&memc);
+ servers= memcached_servers_parse(servers_list.c_str());
+ memcached_server_push(&memc, servers);
+ }
+
+ Memcache(const std::string &hostname,
+ unsigned int port)
+ :
+ servers_list(),
+ memc(),
+ servers(NULL),
+ result()
+ {
+ memcached_create(&memc);
+ servers_list.append(hostname);
+ servers_list.append(":");
+ std::ostringstream strsmt;
+ strsmt << port;
+ servers_list.append(strsmt.str());
+ servers= memcached_servers_parse(servers_list.c_str());
+ memcached_server_push(&memc, servers);
+ }
+
Memcache(memcached_st *clone)
:
+ servers_list(),
memc(),
+ servers(NULL),
result()
{
memcached_clone(&memc, clone);
Memcache(const Memcache &rhs)
:
+ servers_list(rhs.servers_list),
memc(),
+ servers(NULL),
result()
{
memcached_clone(&memc, const_cast<memcached_st *>(&rhs.getImpl()));
+ servers= memcached_servers_parse(servers_list.c_str());
+ memcached_server_push(&memc, servers);
+ }
+
+ Memcache &operator=(const Memcache &rhs)
+ {
+ if (this != &rhs)
+ {
+ memcached_clone(&memc, const_cast<memcached_st *>(&rhs.getImpl()));
+ servers= memcached_servers_parse(servers_list.c_str());
+ memcached_server_push(&memc, servers);
+ }
+ return *this;
}
~Memcache()
{
memcached_free(&memc);
+ memcached_server_list_free(servers);
}
/**
return memcached_strerror(NULL, rc);
}
+ /**
+ * Return the string which contains the list of memcached servers being
+ * used.
+ *
+ * @return a std::string containing the list of memcached servers
+ */
+ const std::string getServersList() const
+ {
+ return servers_list;
+ }
+
+ /**
+ * Set the list of memcached servers to use.
+ *
+ * @param[in] in_servers_list list of servers
+ * @return true on success; false otherwise
+ */
+ bool setServers(const std::string &in_servers_list)
+ {
+ servers_list.assign(in_servers_list);
+ servers= memcached_servers_parse(in_servers_list.c_str());
+ return (servers == NULL);
+ }
+
+ /**
+ * Add a server to the list of memcached servers to use.
+ *
+ * @param[in] server_name name of the server to add
+ * @param[in[ port port number of server to add
+ * @return true on success; false otherwise
+ */
+ bool addServer(const std::string &server_name, unsigned int port)
+ {
+ memcached_return rc;
+ std::ostringstream strstm;
+ servers_list.append(",");
+ servers_list.append(server_name);
+ servers_list.append(":");
+ strstm << port;
+ servers_list.append(strstm.str());
+ servers= memcached_server_list_append(servers,
+ server_name.c_str(),
+ port,
+ &rc);
+ return (rc == MEMCACHED_SUCCESS);
+ }
+
/**
* Fetches an individual value from the server. mget() must always
* be called before using this method.
* @return true on success; false otherwise
*/
bool get(const std::string &key,
- std::vector<char> &ret_val)
+ std::vector<char> &ret_val) throw (Error)
{
uint32_t flags= 0;
memcached_return rc;
if (key.empty())
{
- return false;
+ throw(Error("the key supplied is empty!", false));
}
char *value= memcached_get(&memc, key.c_str(), key.length(),
&value_length, &flags, &rc);
*/
bool getByKey(const std::string &master_key,
const std::string &key,
- std::vector<char> &ret_val)
+ std::vector<char> &ret_val) throw(Error)
{
uint32_t flags= 0;
memcached_return rc;
if (master_key.empty() || key.empty())
{
- return false;
+ throw(Error("the master key or key supplied is empty!", false));
}
- char *value= memcached_get_by_key(&memc,
- master_key.c_str(), master_key.length(),
+ char *value= memcached_get_by_key(&memc,
+ master_key.c_str(), master_key.length(),
key.c_str(), key.length(),
&value_length, &flags, &rc);
if (value)
* @param[in] flags flags to store with the object
* @return true on succcess; false otherwise
*/
- bool set(const std::string &key,
+ bool set(const std::string &key,
const std::vector<char> &value,
time_t expiration,
- uint32_t flags)
+ uint32_t flags) throw(Error)
{
if (key.empty() || value.empty())
{
- return false;
+ throw(Error("the key or value supplied is empty!", false));
}
- memcached_return rc= memcached_set(&memc,
+ memcached_return rc= memcached_set(&memc,
key.c_str(), key.length(),
&value[0], value.size(),
expiration, flags);
const std::string &key,
const std::vector<char> &value,
time_t expiration,
- uint32_t flags)
+ uint32_t flags) throw(Error)
{
if (master_key.empty() ||
key.empty() ||
value.empty())
{
- return false;
+ throw(Error("the key or value supplied is empty!", false));
}
memcached_return rc= memcached_set_by_key(&memc, master_key.c_str(),
master_key.length(),
bool setAll(std::vector<std::string> &keys,
std::vector< std::vector<char> *> &values,
time_t expiration,
- uint32_t flags)
+ uint32_t flags) throw(Error)
{
if (keys.size() != values.size())
{
- return false;
+ throw(Error("The number of keys and values do not match!", false));
}
bool retval= true;
std::vector<std::string>::iterator key_it= keys.begin();
*/
bool setAll(std::map<const std::string, std::vector<char> > &key_value_map,
time_t expiration,
- uint32_t flags)
+ uint32_t flags) throw(Error)
{
if (key_value_map.empty())
{
- return false;
+ throw(Error("The key/values are not properly set!", false));
}
bool retval= true;
std::map<const std::string, std::vector<char> >::iterator it=
retval= set(it->first, it->second, expiration, flags);
if (retval == false)
{
- return false;
+ std::string err_buff("There was an error setting the key ");
+ err_buff.append(it->first);
+ throw(Error(err_buff, false));
}
++it;
}
* @param[out] value store the result of the increment here
* @return true on success; false otherwise
*/
- bool increment(const std::string &key, uint32_t offset, uint64_t *value)
+ bool increment(const std::string &key, uint32_t offset, uint64_t *value) throw(Error)
{
if (key.empty())
{
- return false;
+ throw(Error("the key supplied is empty!", false));
}
memcached_return rc= memcached_increment(&memc, key.c_str(), key.length(),
offset, value);
* @return true on success; false otherwise
*/
bool decrement(const std::string &key, uint32_t offset, uint64_t *value)
+ throw(Error)
{
if (key.empty())
{
- return false;
+ throw(Error("the key supplied is empty!", false));
}
memcached_return rc= memcached_decrement(&memc, key.c_str(),
key.length(),
* @return true on success; false otherwise
*/
bool add(const std::string &key, const std::vector<char> &value)
+ throw(Error)
{
if (key.empty() || value.empty())
{
- return false;
+ throw(Error("the key or value supplied is empty!", false));
}
memcached_return rc= memcached_add(&memc, key.c_str(), key.length(),
&value[0], value.size(), 0, 0);
*/
bool addByKey(const std::string &master_key,
const std::string &key,
- const std::vector<char> &value)
+ const std::vector<char> &value) throw(Error)
{
if (master_key.empty() ||
key.empty() ||
value.empty())
{
- return false;
+ throw(Error("the master key or key supplied is empty!", false));
}
memcached_return rc= memcached_add_by_key(&memc,
master_key.c_str(),
* @param[in[ value value to replace object with
* @return true on success; false otherwise
*/
- bool replace(const std::string &key, const std::vector<char> &value)
+ bool replace(const std::string &key, const std::vector<char> &value) throw(Error)
{
if (key.empty() ||
value.empty())
{
- return false;
+ throw(Error("the key or value supplied is empty!", false));
}
memcached_return rc= memcached_replace(&memc, key.c_str(), key.length(),
&value[0], value.size(),
key.empty() ||
value.empty())
{
- return false;
+ throw(Error("the master key or key supplied is empty!", false));
}
memcached_return rc= memcached_replace_by_key(&memc,
master_key.c_str(),
* @return true on success; false otherwise
*/
bool prepend(const std::string &key, const std::vector<char> &value)
+ throw(Error)
{
if (key.empty() || value.empty())
{
- return false;
+ throw(Error("the key or value supplied is empty!", false));
}
memcached_return rc= memcached_prepend(&memc, key.c_str(), key.length(),
&value[0], value.size(), 0, 0);
bool prependByKey(const std::string &master_key,
const std::string &key,
const std::vector<char> &value)
+ throw(Error)
{
if (master_key.empty() ||
key.empty() ||
value.empty())
{
- return false;
+ throw(Error("the master key or key supplied is empty!", false));
}
- memcached_return rc= memcached_prepend_by_key(&memc,
- master_key.c_str(),
+ memcached_return rc= memcached_prepend_by_key(&memc,
+ master_key.c_str(),
master_key.length(),
- key.c_str(),
+ key.c_str(),
key.length(),
- &value[0],
+ &value[0],
value.size(),
0,
0);
* @return true on success; false otherwise
*/
bool append(const std::string &key, const std::vector<char> &value)
+ throw(Error)
{
if (key.empty() || value.empty())
{
- return false;
+ throw(Error("the key or value supplied is empty!", false));
}
- memcached_return rc= memcached_append(&memc,
- key.c_str(),
+ memcached_return rc= memcached_append(&memc,
+ key.c_str(),
key.length(),
- &value[0],
- value.size(),
+ &value[0],
+ value.size(),
0, 0);
return (rc == MEMCACHED_SUCCESS);
}
* @param[in] value data to append to object's value
* @return true on success; false otherwise
*/
- bool appendByKey(const std::string &master_key,
- const std::string &key,
+ bool appendByKey(const std::string &master_key,
+ const std::string &key,
const std::vector<char> &value)
+ throw(Error)
{
if (master_key.empty() ||
key.empty() ||
value.empty())
{
- return false;
+ throw(Error("the master key or key supplied is empty!", false));
}
memcached_return rc= memcached_append_by_key(&memc,
master_key.c_str(),
*/
bool cas(const std::string &key,
const std::vector<char> &value,
- uint64_t cas_arg)
+ uint64_t cas_arg) throw(Error)
{
if (key.empty() || value.empty())
{
- return false;
+ throw(Error("the key or value supplied is empty!", false));
}
memcached_return rc= memcached_cas(&memc, key.c_str(), key.length(),
&value[0], value.size(),
bool casByKey(const std::string &master_key,
const std::string &key,
const std::vector<char> &value,
- uint64_t cas_arg)
+ uint64_t cas_arg) throw(Error)
{
if (master_key.empty() ||
key.empty() ||
value.empty())
{
- return false;
+ throw(Error("the master key, key or value supplied is empty!", false));
}
memcached_return rc= memcached_cas_by_key(&memc,
master_key.c_str(),
* @param[in] key key of object to delete
* @return true on success; false otherwise
*/
- bool remove(const std::string &key)
+ bool remove(const std::string &key) throw(Error)
{
if (key.empty())
{
- return false;
+ throw(Error("the key supplied is empty!", false));
}
memcached_return rc= memcached_delete(&memc, key.c_str(), key.length(), 0);
return (rc == MEMCACHED_SUCCESS);
* @return true on success; false otherwise
*/
bool remove(const std::string &key,
- time_t expiration)
+ time_t expiration) throw(Error)
{
if (key.empty())
{
- return false;
+ throw(Error("the key supplied is empty!", false));
}
- memcached_return rc= memcached_delete(&memc,
- key.c_str(),
- key.length(),
+ memcached_return rc= memcached_delete(&memc,
+ key.c_str(),
+ key.length(),
expiration);
return (rc == MEMCACHED_SUCCESS);
}
* @param[in] key key of object to delete
* @return true on success; false otherwise
*/
- bool removeByKey(const std::string &master_key,
- const std::string &key)
+ bool removeByKey(const std::string &master_key,
+ const std::string &key) throw(Error)
{
if (master_key.empty() || key.empty())
{
- return false;
+ throw(Error("the master key or key supplied is empty!", false));
}
- memcached_return rc= memcached_delete_by_key(&memc,
- master_key.c_str(),
+ memcached_return rc= memcached_delete_by_key(&memc,
+ master_key.c_str(),
master_key.length(),
- key.c_str(),
- key.length(),
+ key.c_str(),
+ key.length(),
0);
return (rc == MEMCACHED_SUCCESS);
}
*/
bool removeByKey(const std::string &master_key,
const std::string &key,
- time_t expiration)
+ time_t expiration) throw(Error)
{
if (master_key.empty() || key.empty())
{
- return false;
+ throw(Error("the master key or key supplied is empty!", false));
}
memcached_return rc= memcached_delete_by_key(&memc,
master_key.c_str(),
private:
+ std::string servers_list;
memcached_st memc;
+ memcached_server_st *servers;
memcached_result_st result;
};
--- /dev/null
+/*
+ * An example file showing the usage of the C++ libmemcached interface.
+ */
+
+#include <vector>
+#include <string>
+#include <iostream>
+#include <algorithm>
+
+#include <string.h>
+
+#include <libmemcached/memcached.hpp>
+
+using namespace std;
+using namespace memcache;
+
+class DeletePtrs
+{
+public:
+ template<typename T>
+ inline void operator()(const T *ptr) const
+ {
+ delete ptr;
+ }
+};
+
+class MyCache
+{
+public:
+
+ static const uint32_t num_of_clients= 10;
+
+ static MyCache &singleton()
+ {
+ static MyCache instance;
+ return instance;
+ }
+
+ void set(const string &key,
+ const vector<char> &value)
+ {
+ time_t expiry= 0;
+ uint32_t flags= 0;
+ getCache()->set(key, value, expiry, flags);
+ }
+
+ vector<char> get(const string &key)
+ {
+ vector<char> ret_value;
+ getCache()->get(key, ret_value);
+ return ret_value;
+ }
+
+ void remove(const string &key)
+ {
+ getCache()->remove(key);
+ }
+
+ Memcache *getCache()
+ {
+ /*
+ * pick a random element from the vector of clients. Obviously, this is
+ * not very random but suffices as an example!
+ */
+ uint32_t index= rand() % num_of_clients;
+ return clients[index];
+ }
+
+private:
+
+ /*
+ * A vector of clients.
+ */
+ std::vector<Memcache *> clients;
+
+ MyCache()
+ :
+ clients()
+ {
+ /* create clients and add them to the vector */
+ for (uint32_t i= 0; i < num_of_clients; i++)
+ {
+ Memcache *client= new Memcache("127.0.0.1:11211");
+ clients.push_back(client);
+ }
+ }
+
+ ~MyCache()
+ {
+ for_each(clients.begin(), clients.end(), DeletePtrs());
+ clients.clear();
+ }
+
+ MyCache(const MyCache&);
+
+};
+
+class Product
+{
+public:
+
+ Product(int in_id, double in_price)
+ :
+ id(in_id),
+ price(in_price)
+ {}
+
+ Product()
+ :
+ id(0),
+ price(0.0)
+ {}
+
+ int getId() const
+ {
+ return id;
+ }
+
+ double getPrice() const
+ {
+ return price;
+ }
+
+private:
+
+ int id;
+ double price;
+
+};
+
+void setAllProducts(vector<Product> &products)
+{
+ vector<char> raw_products(products.size() * sizeof(Product));
+ memcpy(&raw_products[0], &products[0], products.size() * sizeof(Product));
+ MyCache::singleton().set("AllProducts", raw_products);
+}
+
+vector<Product> getAllProducts()
+{
+ vector<char> raw_products = MyCache::singleton().get("AllProducts");
+ vector<Product> products(raw_products.size() / sizeof(Product));
+ memcpy(&products[0], &raw_products[0], raw_products.size());
+ return products;
+}
+
+Product getProduct(const string &key)
+{
+ vector<char> raw_product= MyCache::singleton().get(key);
+ Product ret;
+ if (! raw_product.empty())
+ {
+ memcpy(&ret, &raw_product[0], sizeof(Product));
+ }
+ else
+ {
+ /* retrieve it from the persistent store */
+ }
+ return ret;
+}
+
+void setProduct(const string &key, const Product &product)
+{
+ vector<char> raw_product(sizeof(Product));
+ memcpy(&raw_product[0], &product, sizeof(Product));
+ MyCache::singleton().set(key, raw_product);
+}
+
+int main()
+{
+#if 0
+ Product pad(1, 5.0);
+ const string key("padraig");
+ cout << "Going to set an object in the cache..." << endl;
+ setProduct(key, pad);
+ cout << "Now retrieve that key..." << endl;
+ Product test= getProduct(key);
+ double price= test.getPrice();
+ cout << "Price of retrieve object: " << price << endl;
+ Product next(2, 10.0);
+ vector<Product> products;
+ products.push_back(pad);
+ products.push_back(next);
+ cout << "going to set a vector of products..." << endl;
+ setAllProducts(products);
+ cout << "now retrieve those products..." << endl;
+ vector<Product> got= getAllProducts();
+ cout << "size of retrieved vector: " << got.size() << endl;
+ vector<Product>::iterator iter= got.begin();
+ while (iter != got.end())
+ {
+ cout << "product " << (*iter).getId() << " costs " << (*iter).getPrice() << endl;
+ ++iter;
+ }
+#endif
+ Memcache first_client("127.0.0.1:11211");
+ Memcache second_client("127.0.0.1", 11211);
+ //first_client.set("key", some_vector_of_chars, expiry, flags);
+ //first_client.get("key", vector_to_fill_with_data);
+ //first_client.remove("key");
+ first_client.addServer("192.168.1.1", 11211);
+ return 0;
+}