278fbde602bf1b0343beb2f3a566ad73be7619be
[shibboleth/sp.git] / memcache-store / memcache-store.cpp
1 /*
2  *  Copyright 2001-2009 Internet2
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * memcache-store.cpp
19  *
20  * Storage Service using memcache (pre memcache tags)
21  */
22
23 #if defined (_MSC_VER) || defined(__BORLANDC__)
24 # include "config_win32.h"
25 #else
26 # include "config.h"
27 #endif
28
29 #ifdef WIN32
30 # define _CRT_NONSTDC_NO_DEPRECATE 1
31 # define _CRT_SECURE_NO_DEPRECATE 1
32 # define MCEXT_EXPORTS __declspec(dllexport)
33 #else
34 # define MCEXT_EXPORTS
35 #endif
36
37 #include <xmltooling/base.h>
38
39 #include <list>
40 #include <iostream> 
41 #include <libmemcached/memcached.h>
42 #include <xercesc/util/XMLUniDefs.hpp>
43
44 #include <xmltooling/logging.h>
45 #include <xmltooling/unicode.h>
46 #include <xmltooling/XMLToolingConfig.h>
47 #include <xmltooling/util/NDC.h>
48 #include <xmltooling/util/StorageService.h>
49 #include <xmltooling/util/Threads.h>
50 #include <xmltooling/util/XMLHelper.h>
51
52 using namespace xmltooling::logging;
53 using namespace xmltooling;
54 using namespace xercesc;
55 using namespace std;
56
57 namespace xmltooling {
58   static const XMLCh Hosts[] = UNICODE_LITERAL_5(H,o,s,t,s);
59   static const XMLCh prefix[] = UNICODE_LITERAL_6(p,r,e,f,i,x);
60   static const XMLCh buildMap[] = UNICODE_LITERAL_8(b,u,i,l,d,M,a,p);
61   static const XMLCh sendTimeout[] = UNICODE_LITERAL_11(s,e,n,d,T,i,m,e,o,u,t);
62   static const XMLCh recvTimeout[] = UNICODE_LITERAL_11(r,e,c,v,T,i,m,e,o,u,t);
63   static const XMLCh pollTimeout[] = UNICODE_LITERAL_11(p,o,l,l,T,i,m,e,o,u,t);
64   static const XMLCh failLimit[] = UNICODE_LITERAL_9(f,a,i,l,L,i,m,i,t);
65   static const XMLCh retryTimeout[] = UNICODE_LITERAL_12(r,e,t,r,y,T,i,m,e,o,u,t);
66   static const XMLCh nonBlocking[] = UNICODE_LITERAL_11(n,o,n,B,l,o,c,k,i,n,g);
67   
68   class mc_record {
69   public:
70     string value;
71     time_t expiration;
72     mc_record(){};
73     mc_record(string _v, time_t _e) :
74       value(_v), expiration(_e)
75     {}
76   };
77
78   class MemcacheBase {
79   public:
80     MemcacheBase(const DOMElement* e);
81     ~MemcacheBase();
82         
83     bool addMemcache(const char *key,
84                      string &value,
85                      time_t timeout,
86                      uint32_t flags,
87                      bool use_prefix = true);
88     bool setMemcache(const char *key,
89                      string &value,
90                      time_t timeout,
91                      uint32_t flags,
92                      bool use_prefix = true);
93     bool replaceMemcache(const char *key,
94                          string &value,
95                          time_t timeout,
96                          uint32_t flags,
97                          bool use_prefix = true);
98     bool getMemcache(const char *key,
99                      string &dest,
100                      uint32_t *flags,
101                      bool use_prefix = true);
102     bool deleteMemcache(const char *key,
103                         time_t timeout,
104                         bool use_prefix = true);
105
106     void serialize(mc_record &source, string &dest);
107     void serialize(list<string> &source, string &dest);
108     void deserialize(string &source, mc_record &dest);
109     void deserialize(string &source, list<string> &dest);
110
111     bool addSessionToUser(string &key, string &user);
112     bool addLock(string what, bool use_prefix = true);
113     void deleteLock(string what, bool use_prefix = true);
114
115   protected:
116     const DOMElement* m_root; // can only use this during initialization
117     Category& log;
118     memcached_st *memc;
119     string m_prefix;
120     Mutex* m_lock;
121   };
122   
123   class MemcacheStorageService : public StorageService, public MemcacheBase {
124
125   public:
126     MemcacheStorageService(const DOMElement* e);
127     ~MemcacheStorageService();
128     
129     bool createString(const char* context, const char* key, const char* value, time_t expiration);
130     int readString(const char* context, const char* key, string* pvalue=NULL, time_t* pexpiration=NULL, int version=0);
131     int updateString(const char* context, const char* key, const char* value=NULL, time_t expiration=0, int version=0);
132     bool deleteString(const char* context, const char* key);
133     
134     bool createText(const char* context, const char* key, const char* value, time_t expiration) {
135       return createString(context, key, value, expiration);
136     }
137     int readText(const char* context, const char* key, string* pvalue=NULL, time_t* pexpiration=NULL, int version=0) {
138       return readString(context, key, pvalue, pexpiration, version);
139     }
140     int updateText(const char* context, const char* key, const char* value=NULL, time_t expiration=0, int version=0) {
141       return updateString(context, key, value, expiration, version);
142     }
143     bool deleteText(const char* context, const char* key) {
144       return deleteString(context, key);
145     }
146     
147     void reap(const char* context) {}
148
149     void updateContext(const char* context, time_t expiration);
150     void deleteContext(const char* context);
151
152     private:
153
154     Category& m_log;
155     bool m_buildMap;
156
157
158   };
159
160   StorageService* MemcacheStorageServiceFactory(const DOMElement* const & e) {
161     return new MemcacheStorageService(e);
162   }
163
164 };
165
166 bool MemcacheBase::addLock(string what, bool use_prefix) {
167   string lock_name = what + ":LOCK";
168   string set_val = "1";
169   unsigned tries = 5;
170   while (!addMemcache(lock_name.c_str(), set_val, 5, 0, use_prefix)) {
171     if (tries-- == 0) {
172       log.debug("Unable to get lock %s... FAILED.", lock_name.c_str());
173       return false;
174     }
175     log.debug("Unable to get lock %s... Retrying.", lock_name.c_str());
176     
177     // sleep 100ms
178 #ifdef WIN32
179     Sleep(100);
180 #else
181     struct timeval tv = { 0, 100000 };
182     select(0, 0, 0, 0, &tv);
183 #endif
184   }
185   return true;
186 }
187
188 void MemcacheBase::deleteLock(string what, bool use_prefix) {
189
190   string lock_name = what + ":LOCK";
191   deleteMemcache(lock_name.c_str(), 0, use_prefix);
192   return;
193
194 }  
195
196 void MemcacheBase::deserialize(string &source, mc_record &dest) {
197   istringstream is(source, stringstream::in | stringstream::out);
198   is >> dest.expiration;
199   is.ignore(1); // ignore delimiter
200   dest.value = is.str().c_str() + is.tellg();
201 }
202
203 void MemcacheBase::deserialize(string &source, list<string> &dest) {
204   istringstream is(source, stringstream::in | stringstream::out);
205   while (!is.eof()) {
206     string s;
207     is >> s;
208     dest.push_back(s);
209   }  
210 }
211
212 void MemcacheBase::serialize(mc_record &source, string &dest) {
213   ostringstream os(stringstream::in | stringstream::out);
214   os << source.expiration;
215   os << "-"; // delimiter
216   os << source.value;
217   dest = os.str();
218 }
219
220 void MemcacheBase::serialize(list<string> &source, string &dest) {  
221   ostringstream os(stringstream::in | stringstream::out);
222   for(list<string>::iterator iter = source.begin(); iter != source.end(); iter++) {
223     if (iter != source.begin()) {
224       os << endl;
225     }
226     os << *iter;
227   }
228   dest = os.str();
229 }
230
231 bool MemcacheBase::addSessionToUser(string &key, string &user) {
232
233   if (! addLock(user, false)) {
234     return false;
235   }
236
237   // Aquired lock
238
239   string sessid = m_prefix + key; // add specific prefix to session
240   string delimiter = ";";
241   string user_key = "UDATA:";
242   user_key += user;
243   string user_val;
244   uint32_t flags;
245   bool result = getMemcache(user_key.c_str(), user_val, &flags, false);
246
247   if (result) {
248     bool already_there = false;
249     // skip delimiters at beginning.
250     string::size_type lastPos = user_val.find_first_not_of(delimiter, 0);
251     
252     // find first "non-delimiter".
253     string::size_type pos = user_val.find_first_of(delimiter, lastPos);
254     
255     while (string::npos != pos || string::npos != lastPos) {
256       // found a token, add it to the vector.
257       string session = user_val.substr(lastPos, pos - lastPos);
258       if (strcmp(session.c_str(), sessid.c_str()) == 0) {
259         already_there = true;
260         break;
261       }
262       
263       // skip delimiters.  Note the "not_of"
264       lastPos = user_val.find_first_not_of(delimiter, pos);
265       
266       // find next "non-delimiter"
267       pos = user_val.find_first_of(delimiter, lastPos);
268     }
269     
270     if (!already_there) {
271       user_val += delimiter + sessid;
272       replaceMemcache(user_key.c_str(), user_val, 0, 0, false);
273     }
274   } else {
275     addMemcache(user_key.c_str(), sessid, 0, 0, false);
276   }
277
278   deleteLock(user, false);
279   return true;
280   
281 }
282
283 bool MemcacheBase::deleteMemcache(const char *key,
284                                   time_t timeout,
285                                   bool use_prefix) {
286   memcached_return rv;
287   string final_key;
288   bool success;
289
290   if (use_prefix) {
291     final_key = m_prefix + key;
292   } else {
293     final_key = key;
294   }
295
296   m_lock->lock();
297   rv = memcached_delete(memc, (char *)final_key.c_str(), final_key.length(), timeout);
298   m_lock->unlock();
299
300   if (rv == MEMCACHED_SUCCESS) {
301     success = true;
302   } else if (rv == MEMCACHED_NOTFOUND) {
303     // Key wasn't there... No biggie.
304     success = false;
305   } else if (rv == MEMCACHED_ERRNO) {
306     // System error
307     string error = string("Memcache::deleteMemcache() SYSTEM ERROR: ") + string(strerror(memc->cached_errno));
308     log.error(error);
309     throw IOException(error);
310   } else {
311     string error = string("Memcache::deleteMemcache() Problems: ") + memcached_strerror(memc, rv);
312     log.error(error);
313     throw IOException(error);
314   }
315
316   return success;
317 }
318
319 bool MemcacheBase::getMemcache(const char *key,
320                                string &dest,
321                                uint32_t *flags,
322                                bool use_prefix) {
323   memcached_return rv;
324   size_t len;
325   char *result;
326   string final_key;
327   bool success;
328   
329   if (use_prefix) {
330     final_key = m_prefix + key;
331   } else {
332     final_key = key;
333   }
334
335   m_lock->lock();
336   result = memcached_get(memc, (char *)final_key.c_str(), final_key.length(), &len, flags, &rv);
337   m_lock->unlock();
338
339   if (rv == MEMCACHED_SUCCESS) {
340     dest = result;
341     free(result);
342     success = true;
343   } else if (rv == MEMCACHED_NOTFOUND) {
344     log.debug("Key %s not found in memcache...", key);
345     success = false;
346   } else if (rv == MEMCACHED_ERRNO) {
347     // System error
348     string error = string("Memcache::getMemcache() SYSTEM ERROR: ") + string(strerror(memc->cached_errno));
349     log.error(error);
350     throw IOException(error);
351   } else {
352     string error = string("Memcache::getMemcache() Problems: ") + memcached_strerror(memc, rv);
353     log.error(error);
354     throw IOException(error);
355   }
356
357   return success;
358 }
359
360 bool MemcacheBase::addMemcache(const char *key,
361                                string &value,
362                                time_t timeout,
363                                uint32_t flags,
364                                bool use_prefix) {
365
366   memcached_return rv;
367   string final_key;
368   bool success;
369
370   if (use_prefix) {
371     final_key = m_prefix + key;
372   } else {
373     final_key = key;
374   }
375
376   m_lock->lock();
377   rv = memcached_add(memc, (char *)final_key.c_str(), final_key.length(), (char *)value.c_str(), value.length(), timeout, flags);
378   m_lock->unlock();
379
380   if (rv == MEMCACHED_SUCCESS) {
381     success = true;
382   } else if (rv == MEMCACHED_NOTSTORED) {
383     // already there
384     success = false;
385   } else if (rv == MEMCACHED_ERRNO) {
386     // System error
387     string error = string("Memcache::addMemcache() SYSTEM ERROR: ") + string(strerror(memc->cached_errno));
388     log.error(error);
389     throw IOException(error);
390   } else {
391     string error = string("Memcache::addMemcache() Problems: ") + memcached_strerror(memc, rv);
392     log.error(error);
393     throw IOException(error);
394   }
395
396   return success;
397 }
398
399 bool MemcacheBase::setMemcache(const char *key,
400                                string &value,
401                                time_t timeout,
402                                uint32_t flags,
403                                bool use_prefix) {
404
405   memcached_return rv;
406   string final_key;
407   bool success;
408
409   if (use_prefix) {
410     final_key = m_prefix + key;
411   } else {
412     final_key = key;
413   }
414
415   m_lock->lock();
416   rv = memcached_set(memc, (char *)final_key.c_str(), final_key.length(), (char *)value.c_str(), value.length(), timeout, flags);
417   m_lock->unlock();
418
419   if (rv == MEMCACHED_SUCCESS) {
420     success = true;
421   } else if (rv == MEMCACHED_ERRNO) {
422     // System error
423     string error = string("Memcache::setMemcache() SYSTEM ERROR: ") + string(strerror(memc->cached_errno));
424     log.error(error);
425     throw IOException(error);
426   } else {
427     string error = string("Memcache::setMemcache() Problems: ") + memcached_strerror(memc, rv);
428     log.error(error);
429     throw IOException(error);
430   }
431
432   return success;
433 }
434
435 bool MemcacheBase::replaceMemcache(const char *key,
436                                    string &value,
437                                    time_t timeout,
438                                    uint32_t flags,
439                                    bool use_prefix) {
440   
441   memcached_return rv;
442   string final_key;
443   bool success;
444
445   if (use_prefix) {
446     final_key = m_prefix + key;
447   } else {
448     final_key = key;
449   }
450
451   m_lock->lock();
452   rv = memcached_replace(memc, (char *)final_key.c_str(), final_key.length(), (char *)value.c_str(), value.length(), timeout, flags);
453   m_lock->unlock();
454
455   if (rv == MEMCACHED_SUCCESS) {
456     success = true;
457   } else if (rv == MEMCACHED_NOTSTORED) {
458     // not there
459     success = false;
460   } else if (rv == MEMCACHED_ERRNO) {
461     // System error
462     string error = string("Memcache::replaceMemcache() SYSTEM ERROR: ") + string(strerror(memc->cached_errno));
463     log.error(error);
464     throw IOException(error);
465   } else {
466     string error = string("Memcache::replaceMemcache() Problems: ") + memcached_strerror(memc, rv);
467     log.error(error);
468     throw IOException(error);
469   }
470
471   return success;
472 }
473
474 MemcacheBase::MemcacheBase(const DOMElement* e) : m_root(e), log(Category::getInstance("XMLTooling.MemcacheBase")), m_prefix("") {
475
476   auto_ptr_char p(e ? e->getAttributeNS(NULL,prefix) : NULL);
477   if (p.get() && *p.get()) {
478     log.debug("INIT: GOT key prefix: %s", p.get());
479     m_prefix = p.get();
480   }
481
482   m_lock = Mutex::create();
483   log.debug("Lock created");
484
485   memc = memcached_create(NULL);
486   if (memc == NULL) {
487     throw XMLToolingException("MemcacheBase::Memcache(): memcached_create() failed");
488   }
489
490   log.debug("Memcache created");
491
492   unsigned int hash = MEMCACHED_HASH_CRC;
493   memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, hash);
494   log.debug("CRC hash set");
495
496   int32_t send_timeout = 999999;
497   const XMLCh* tag = e ? e->getAttributeNS(NULL, sendTimeout) : NULL;
498   if (tag && *tag) {
499     send_timeout = XMLString::parseInt(tag);
500   }
501   log.debug("MEMCACHED_BEHAVIOR_SND_TIMEOUT will be set to %d", send_timeout);
502   memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SND_TIMEOUT, send_timeout);
503
504   int32_t recv_timeout = 999999;
505   tag = e ? e->getAttributeNS(NULL, sendTimeout) : NULL;
506   if (tag && *tag) {
507     recv_timeout = XMLString::parseInt(tag);
508   }
509   log.debug("MEMCACHED_BEHAVIOR_RCV_TIMEOUT will be set to %d", recv_timeout);
510   memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RCV_TIMEOUT, recv_timeout);
511
512   int32_t poll_timeout = 1000;
513   tag = e ? e->getAttributeNS(NULL, pollTimeout) : NULL;
514   if (tag && *tag) {
515     poll_timeout = XMLString::parseInt(tag);
516   }
517   log.debug("MEMCACHED_BEHAVIOR_POLL_TIMEOUT will be set to %d", poll_timeout);
518   memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, poll_timeout);
519
520   int32_t fail_limit = 5;
521   tag = e ? e->getAttributeNS(NULL, failLimit) : NULL;
522   if (tag && *tag) {
523     fail_limit = XMLString::parseInt(tag);
524   }
525   log.debug("MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT will be set to %d", fail_limit);
526   memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT, fail_limit);
527
528   int32_t retry_timeout = 30;
529   tag = e ? e->getAttributeNS(NULL, retryTimeout) : NULL;
530   if (tag && *tag) {
531     retry_timeout = XMLString::parseInt(tag);
532   }
533   log.debug("MEMCACHED_BEHAVIOR_RETRY_TIMEOUT will be set to %d", retry_timeout);
534   memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, retry_timeout);
535
536   int32_t nonblock_set = 1;
537   tag = e ? e->getAttributeNS(NULL, nonBlocking) : NULL;
538   if (tag && *tag) {
539     nonblock_set = XMLString::parseInt(tag);
540   }
541   log.debug("MEMCACHED_BEHAVIOR_NO_BLOCK will be set to %d", nonblock_set);
542   memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, nonblock_set);
543
544   // Grab hosts from the configuration.
545   e = e ? XMLHelper::getFirstChildElement(e,Hosts) : NULL;
546   if (!e || !e->hasChildNodes()) {
547     throw XMLToolingException("Memcache StorageService requires Hosts element in configuration.");
548   }
549   auto_ptr_char h(e->getFirstChild()->getNodeValue());
550   log.debug("INIT: GOT Hosts: %s", h.get());
551   memcached_server_st *servers;
552   servers = memcached_servers_parse(const_cast<char*>(h.get()));
553   log.debug("Got %u hosts.",  memcached_server_list_count(servers));
554   if (memcached_server_push(memc, servers) != MEMCACHED_SUCCESS) {
555     throw IOException("MemcacheBase::Memcache(): memcached_server_push() failed");    
556   }
557   memcached_server_list_free(servers);
558
559   log.debug("Memcache object initialized");
560 }
561
562 MemcacheBase::~MemcacheBase() {
563   memcached_free(memc);
564   delete m_lock;
565   log.debug("Base object destroyed");
566 }
567
568 MemcacheStorageService::MemcacheStorageService(const DOMElement* e)
569   : MemcacheBase(e), m_log(Category::getInstance("XMLTooling.MemcacheStorageService")), m_buildMap(false) {
570
571     const XMLCh* tag=e ? e->getAttributeNS(NULL,buildMap) : NULL;
572     if (tag && *tag && XMLString::parseInt(tag) != 0) {
573         m_buildMap = true;
574         m_log.debug("Cache built with buildMap ON");
575     }
576
577 }
578
579 MemcacheStorageService::~MemcacheStorageService() {
580
581   
582 }
583
584 bool MemcacheStorageService::createString(const char* context, const char* key, const char* value, time_t expiration) {
585
586   log.debug("createString ctx: %s - key: %s", context, key);
587
588   string final_key = string(context) + ":" + string(key);
589
590   mc_record rec(value, expiration);
591   string final_value;
592   serialize(rec, final_value);
593
594   bool result = addMemcache(final_key.c_str(), final_value, expiration, 1); // the flag will be the version
595
596   if (result && m_buildMap) {
597     log.debug("Got result, updating map");
598
599     string map_name = context;
600     // we need to update the context map
601     if (! addLock(map_name)) {
602       log.error("Unable to get lock for context %s!", context);
603       deleteMemcache(final_key.c_str(), 0);
604       return false;
605     }
606
607     string ser_arr;
608     uint32_t flags;
609     bool result = getMemcache(map_name.c_str(), ser_arr, &flags);
610     
611     list<string> contents;
612     if (result) {
613       log.debug("Match found. Parsing...");
614
615       deserialize(ser_arr, contents);
616       
617       log.debug("Iterating retrieved session map...");
618       list<string>::iterator iter;
619       for(iter = contents.begin(); 
620           iter != contents.end();
621           iter++) {
622         log.debug("value = " + *iter);
623       }
624
625     } else {
626       log.debug("New context: %s", map_name.c_str());
627
628     }
629
630     contents.push_back(key);
631     serialize(contents, ser_arr);    
632     setMemcache(map_name.c_str(), ser_arr, expiration, 0);    
633     
634     deleteLock(map_name);
635   }
636
637   return result;  
638
639 }
640
641 int MemcacheStorageService::readString(const char* context, const char* key, string* pvalue, time_t* pexpiration, int version) {
642
643   log.debug("readString ctx: %s - key: %s", context, key);
644
645   string final_key = string(context) + ":" + string(key);
646   uint32_t rec_version;
647   string value;
648
649   if (m_buildMap) {
650     log.debug("Checking context");
651
652     string map_name = context;
653     string ser_arr;
654     uint32_t flags;
655     bool ctx_found = getMemcache(map_name.c_str(), ser_arr, &flags);
656
657     if (!ctx_found) {
658       return 0;
659     }
660   }
661
662   bool found = getMemcache(final_key.c_str(), value, &rec_version);
663   if (!found) {
664     return 0;
665   }
666
667   if (version && rec_version <= (uint32_t)version) {
668     return version;
669   }
670
671   if (pexpiration || pvalue) {
672     mc_record rec;
673     deserialize(value, rec);
674     
675     if (pexpiration) {
676       *pexpiration = rec.expiration;
677     }
678     
679     if (pvalue) {
680       *pvalue = rec.value;
681     }
682   }
683   
684   return rec_version;
685
686 }
687
688 int MemcacheStorageService::updateString(const char* context, const char* key, const char* value, time_t expiration, int version) {
689
690   log.debug("updateString ctx: %s - key: %s", context, key);
691
692   time_t final_exp = expiration;
693   time_t *want_expiration = NULL;
694   if (! final_exp) {
695     want_expiration = &final_exp;
696   }
697
698   int read_res = readString(context, key, NULL, want_expiration, version);
699
700   if (!read_res) {
701     // not found
702     return read_res;
703   }
704
705   if (version && version != read_res) {
706     // version incorrect
707     return -1;
708   }
709
710   // Proceding with update
711   string final_key = string(context) + ":" + string(key);
712   mc_record rec(value, final_exp);
713   string final_value;
714   serialize(rec, final_value);
715
716   replaceMemcache(final_key.c_str(), final_value, final_exp, ++version);
717   return version;
718
719 }
720
721 bool MemcacheStorageService::deleteString(const char* context, const char* key) {
722
723   log.debug("deleteString ctx: %s - key: %s", context, key);
724   
725   string final_key = string(context) + ":" + string(key);
726
727   // Not updating context map, if there is one. There is no need.
728
729   return deleteMemcache(final_key.c_str(), 0);
730
731 }
732
733 void MemcacheStorageService::updateContext(const char* context, time_t expiration) {
734
735   log.debug("updateContext ctx: %s", context);
736
737   if (!m_buildMap) {
738     log.error("updateContext invoked on a Storage with no context map built!");
739     return;
740   }
741
742   string map_name = context;
743   string ser_arr;
744   uint32_t flags;
745   bool result = getMemcache(map_name.c_str(), ser_arr, &flags);
746   
747   list<string> contents;
748   if (result) {
749     log.debug("Match found. Parsing...");
750     
751     deserialize(ser_arr, contents);
752     
753     log.debug("Iterating retrieved session map...");
754     list<string>::iterator iter;
755     for(iter = contents.begin(); 
756         iter != contents.end();
757         iter++) {
758
759       // Update expiration times
760       string value;      
761       int read_res = readString(context, iter->c_str(), &value, NULL, 0);
762       
763       if (!read_res) {
764         // not found
765         continue;
766       }
767
768       updateString(context, iter->c_str(), value.c_str(), expiration, read_res);
769     }
770     replaceMemcache(map_name.c_str(), ser_arr, expiration, flags);
771   }
772   
773 }
774
775 void MemcacheStorageService::deleteContext(const char* context) {
776
777   log.debug("deleteContext ctx: %s", context);
778
779   if (!m_buildMap) {
780     log.error("deleteContext invoked on a Storage with no context map built!");
781     return;
782   }
783
784   string map_name = context;
785   string ser_arr;
786   uint32_t flags;
787   bool result = getMemcache(map_name.c_str(), ser_arr, &flags);
788   
789   list<string> contents;
790   if (result) {
791     log.debug("Match found. Parsing...");
792     
793     deserialize(ser_arr, contents);
794     
795     log.debug("Iterating retrieved session map...");
796     list<string>::iterator iter;
797     for(iter = contents.begin(); 
798         iter != contents.end();
799         iter++) {
800       string final_key = map_name + *iter;
801       deleteMemcache(final_key.c_str(), 0);
802     }
803     
804     deleteMemcache(map_name.c_str(), 0);
805   }
806   
807 }
808
809 extern "C" int MCEXT_EXPORTS xmltooling_extension_init(void*) {
810     // Register this SS type
811     XMLToolingConfig::getConfig().StorageServiceManager.registerFactory("MEMCACHE", MemcacheStorageServiceFactory);
812     return 0;
813 }
814
815 extern "C" void MCEXT_EXPORTS xmltooling_extension_term() {
816     XMLToolingConfig::getConfig().StorageServiceManager.deregisterFactory("MEMCACHE");
817 }