00001
00006 #ifndef _SPACE_H
00007 #define _SPACE_H
00008
00009 #include <list>
00010 #include <vector>
00011 #include <sstream>
00012 #include <pthread.h>
00013
00014 #include "Value.h"
00015 #include "Cache.h"
00016 #include "User.h"
00017 #include "LightString.h"
00018
00019 #ifdef HAVE_CONFIG_H
00020 #include "config.h"
00021 #endif
00022
00023 #if HAVE_TR1_UNORDERED_MAP // && GCC_VERSION >= 40300
00024 #include <tr1/unordered_map>
00028 #define USING_UNORDERED_MAP 1
00029 #elif HAVE_EXT_HASH_MAP
00030 #include <ext/hash_map>
00031 #elif HAVE_HASH_MAP
00032 #include <hash_map>
00033 #elif HAVE_HASH_MAP_H
00034 #include <hash_map.h>
00035 #else
00036 #error "hash_map is not available with this compiler"
00037 #endif
00038
00046 struct Stats {
00047
00051 unsigned long long hardQuota;
00052
00056 unsigned long long softQuota;
00057
00061 unsigned long long usedQuota;
00062
00066 unsigned long long getsCount;
00067
00071 unsigned long long setsCount;
00072
00076 unsigned long long bytesWritten;
00077
00081 unsigned long long bytesRead;
00082
00086 unsigned long long missCount;
00087
00091 unsigned long long hitCount;
00092
00096 unsigned long long itemsCount;
00097
00101
00102
00103
00104
00108 unsigned int setTimeRecord;
00109
00113 unsigned int getTimeRecord;
00114
00118 Stats(unsigned long long hardQuota = 0, unsigned long long softQuota = 0) :
00119 hardQuota(hardQuota), softQuota(softQuota), usedQuota(0), getsCount(0), setsCount(0),
00120 bytesWritten(0), bytesRead(0), missCount(0), hitCount(0), itemsCount(0),
00121 setTimeRecord(0), getTimeRecord(0) {
00122 }
00123 };
00124
00125 class Cache;
00126 class User;
00127
00128 using namespace std;
00129
00135 inline size_t HASH(const LightString key) {
00136
00137 #undef get16bits
00138
00139 #define get16bits(d) (*((const uint16_t *) (d)))
00140
00141 #if !defined (get16bits)
00142 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
00143 +(uint32_t)(((const uint8_t *)(d))[0]) )
00144 #endif
00145
00146 char * data = key.memoryPointer;
00147 int len = key.size;
00148
00149 uint32_t hash = len, tmp;
00150 int rem;
00151
00152 if (len <= 0 || data == NULL)
00153 return (size_t) - 1;
00154
00155 rem = len & 3;
00156 len >>= 2;
00157
00158
00159 for (; len > 0; len--) {
00160 hash += get16bits (data);
00161 tmp = (get16bits (data+2) << 11) ^ hash;
00162 hash = (hash << 16) ^ tmp;
00163 data += 2 * sizeof(uint16_t);
00164 hash += hash >> 11;
00165 }
00166
00167
00168 switch (rem) {
00169 case 3:
00170 hash += get16bits (data);
00171 hash ^= hash << 16;
00172 hash ^= data[sizeof(uint16_t)] << 18;
00173 hash += hash >> 11;
00174 break;
00175 case 2:
00176 hash += get16bits (data);
00177 hash ^= hash << 11;
00178 hash += hash >> 17;
00179 break;
00180 case 1:
00181 hash += *data;
00182 hash ^= hash << 10;
00183 hash += hash >> 1;
00184 }
00185
00186
00187 hash ^= hash << 3;
00188 hash += hash >> 5;
00189 hash ^= hash << 4;
00190 hash += hash >> 17;
00191 hash ^= hash << 25;
00192 hash += hash >> 6;
00193
00194 return hash;
00195 }
00196
00197 #if USING_UNORDERED_MAP
00198 namespace std {
00199 namespace tr1 {
00200
00201 template<>
00202 struct hash<LightString> {
00203 inline size_t operator()(const LightString & str) const {
00204 return HASH(str);
00205 }
00206 };
00207
00208 }
00209 }
00210
00211 #else
00212
00216 namespace __gnu_cxx {
00220 template<> struct hash<LightString> {
00224 inline size_t operator()(const LightString & str) const {
00225 return HASH(str);
00226 }
00227 };
00228 }
00229 #endif
00230
00237 enum SpaceResult {
00238 RESULT_SUCCESS, RESULT_MISS, RESULT_EXISTS, RESULT_CAS_FAIL, RESULT_ERROR, RESULT_BAD_SIZE
00239 };
00240
00246 class Space {
00247 public:
00248 class HashTabElement;
00249 class LRUListElement;
00250
00251 #if USING_UNORDERED_MAP
00252
00255 typedef ::tr1::unordered_map<LightString, HashTabElement> SpaceHashTab;
00256 #else
00257
00260 typedef __gnu_cxx ::hash_map<LightString, HashTabElement> SpaceHashTab;
00261 #endif
00262
00266 typedef std::vector<SpaceHashTab> SpaceHashTabs;
00267
00271 typedef std::list<LRUListElement> SpaceLRUList;
00272
00276 typedef std::vector<SpaceLRUList> SpaceLRULists;
00277
00281 typedef std::vector<pthread_rwlock_t *> Mutexes;
00282
00286 typedef std::map<int, char> Indexes;
00287
00291 class HashTabElement {
00292 public:
00293
00297 Value value;
00298
00302 SpaceLRUList::iterator iteratorLRUList;
00303
00310 HashTabElement(const Value &value, Space::SpaceLRUList::iterator iteratorLRUList) :
00311 value(value), iteratorLRUList(iteratorLRUList) {
00312 }
00313 };
00314
00318 class LRUListElement {
00319 public:
00320
00324 int hashTabIndex;
00325
00329 LightString key;
00330
00334 time_t expiryTime;
00335
00343 LRUListElement(int hashTabIndex, const LightString& key, time_t expiryTime) :
00344 hashTabIndex(hashTabIndex), key(key), expiryTime(expiryTime) {
00345 }
00346 };
00347
00348 public:
00349
00356 Mutexes mapMutexes;
00357
00361 pthread_mutex_t globalMutex;
00362
00366 std::string name;
00367
00371 Stats stats;
00372
00376 Stats * fragmentedStats;
00377
00381 static unsigned int NUMERIC_OBJECT_SIZE;
00382
00386 static unsigned int INCR_MAX_STORAGE_LEN;
00387
00391 static const int MUTEXES_COUNT;
00392
00396 SpaceHashTabs hashTab;
00397
00401 SpaceLRULists LRUList;
00402
00403 private:
00404
00405 Cache *memcache;
00406 User *user;
00407
00408
00409 Indexes lockedTableIndexes;
00410 Indexes sharedLockedTableIndexes;
00411
00412 unsigned long long current_cas_id;
00413
00414 public:
00424 Space(const std::string & name, unsigned long long softQuota, unsigned long long hardQuota,
00425 Cache *memcache, User *user);
00426
00427 virtual ~Space();
00428
00438 Value get(const LightString &key, unsigned timeout = 0);
00439
00455 bool get(const LightString &key, Value& value, unsigned timeout = 0);
00456
00472 SpaceResult set(const LightString &key, const Value &value, unsigned timeout,
00473 uint64_t * new_cas_id = NULL);
00474
00489 SpaceResult cas(const LightString &key, const Value &value, unsigned timeout, uint64_t cas_id,
00490 uint64_t * new_cas_id = NULL);
00491
00503 SpaceResult add(const LightString &key, const Value &value, unsigned timeout, uint64_t cas_id =
00504 0, uint64_t * new_cas_id = NULL);
00505
00517 SpaceResult replace(const LightString &key, const Value &value, unsigned timeout,
00518 uint64_t cas_id = 0, uint64_t * new_cas_id = NULL);
00519
00529 SpaceResult append(const LightString &key, const Value &value, uint64_t * new_cas_id = NULL);
00530
00540 SpaceResult prepend(const LightString &key, const Value &value, uint64_t * new_cas_id = NULL);
00541
00555 SpaceResult increment(const LightString &key, uint64_t step, uint64_t * out, unsigned timeout =
00556 0, bool force = 0, uint64_t initial = 0);
00557
00572 SpaceResult decrement(const LightString &key, uint64_t step, uint64_t * out, unsigned timeout =
00573 0, bool force = 0, uint64_t initial = 0);
00574
00583 bool saveSpace(const char *fileName, unsigned minTimeout = 0);
00584
00588 void cleanSpace();
00589
00593 void destroySpace();
00594
00600 Stats getStats();
00601
00612 void clearStats();
00613
00617 void setStatus(unsigned nUsedQuota, unsigned nGetsCount, unsigned nSetsCount,
00618 unsigned nBytesWritten, unsigned nBytesRead, unsigned nMissCount, unsigned nHitCount,
00619 unsigned long long nItemsCount);
00620
00626 std::string getStatsStr() {
00627 std::stringstream ss;
00628
00629 ss << "hardQuota=" << stats.hardQuota << "\n";
00630 ss << "softQuota=" << stats.softQuota << "\n";
00631 ss << "usedQuota=" << stats.usedQuota << "\n";
00632 ss << "getsCount=" << stats.getsCount << "\n";
00633 ss << "setsCount=" << stats.setsCount << "\n";
00634 ss << "bytesWritten=" << stats.bytesWritten << "\n";
00635 ss << "bytesRead=" << stats.bytesRead << "\n";
00636 ss << "missCount=" << stats.missCount << "\n";
00637 ss << "hitCount=" << stats.hitCount << "\n";
00638 return ss.str();
00639 }
00640
00641 private:
00642
00649 SpaceResult doSet(const LightString &key, const Value &value, unsigned timeout,
00650 int tableCookie, SpaceHashTab::iterator found, uint64_t cas_id = 0,
00651 uint64_t * new_cas_id = NULL);
00652
00653 SpaceResult crement(const LightString &key, uint64_t step, uint64_t * out, unsigned timeout,
00654 bool force, uint64_t initial);
00655
00656 SpaceResult
00657 pend(const LightString &key, const Value &value, uint64_t * new_cas_id, bool append);
00658
00666 static unsigned computeExpiryTime(unsigned timeout);
00667
00668 inline size_t hash(const LightString & key);
00669
00670
00671
00677 ostream & print(Space::Indexes & mymap) {
00678
00679 for (Indexes::iterator it = mymap.begin(); it != mymap.end(); it++) {
00680 if (it->second) {
00681 cout << " " << it->first << "->" << (int) it->second << " ";
00682 }
00683 }
00684
00685 return cout;
00686 }
00687 };
00688
00689 #endif
00690