1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """
18 Memcache service
19 ================
20
21 The service provides configuration and construction of memcache connectors.
22
23 Configuration
24 ~~~~~~~~~~~~~
25
26 You need to configure the memcache service to be loaded
27 (``wtf.app.services.memcache.MemcacheService``) in the services section). This
28 requires the following additional configuration::
29
30 [memcache]
31 servers = host[:port] ...
32
33 # pool failover/maintenance options
34 # ---------------------------------
35 #grace_time = [int] Grace time on dead pools until they're backuped
36 # (Default: 30)
37 #retry_time = [int] Retry interval after they're backuped (Default: 60)
38
39 # storage options
40 #compress_threshold = [int] Min size for value compression (Default: 128)
41 #padded = [bool] Use padding for small values (< 16 bytes)? (Default: yes)
42 #prefix = [str] Prefix keys with some arbitrary string (intended for
43 # developers using the same memcache) (Default: ``''``)
44 #split = [bool] Allow splitting of values if they are bigger than the
45 # largest slab? See largest_slab option below. (Default: yes)
46 #largest_slab = [int] Size of the largest slab in bytes. The value is
47 # directly connected to the memcache implementation.
48 # (Default: 1MB)
49
50 # global defaults
51 #max_age = [int] expire time (max age) per item
52 # (Default: no default max_age)
53
54 # default values *per server*
55 #maxconn = [int] hard connection maximum (Default: 0 == unlimited)
56 #maxcached = [int] max cached connections (Default: 0)
57 #weight = [int] relative weight, compared to the other servers. The higher
58 # the more requests it gets. (Default: 1)
59 #timeout = [float] communication timeout in seconds. (Default: 2.6)
60
61 # You can refine various settings per server with optional sections:
62 #[memcache host[:port]]
63 # set specific settings per server here
64 # (maxconn, maxcached, weight, timeout)
65
66
67 Usage
68 ~~~~~
69
70 Now you can import ``__svc__.wtf.memcache`` and take the ``connection``
71 decorator from there. It will inject you an ``mc`` keyword into the argument
72 list::
73
74 from __svc__.wtf import memcache
75
76 @memcache.connection
77 def foo(..., mc=None):
78 mc.set(...)
79
80 The decorator takes optional arguments, ``max_age``, ``nocache``,
81 ``prepare`` and ``exceptions``. ``max_age`` defines the default max age for
82 this connector (overriding the configured one).
83
84 ``nocache`` determines whether the ``nocache`` call argument should be
85 evaluated. The value can be ``False`` (``0``), ``True`` (``1``), ``2`` or
86 ``-1``. If it evaluates to ``False``, no special handling will be applied.
87 Otherwise the function (keyword) argument ``nocache`` will be checked as
88 boolean. If the caller supplies a true value, the memcache connector will
89 behave like the memcache was not available. If the decorator ``nocache``
90 argument is ``2`` (``> 1``), the ``nocache`` function call argument will be
91 passed through, otherwise it's been swallowed by the decorator. If it's
92 ``-1``, the nocache parameter is swallowed but not evaluated. Default is
93 ``False``. Now this all sounds confusing, I guess. Here's an example::
94
95 @memcache.connection(nocache=True)
96 def foo(..., mc=None):
97 ...
98
99 foo(nocache=True)
100
101 The call to ``foo`` causes every memcache operation inside ``foo`` like
102 the memcache was not running, without any change on ``foo``. For a more
103 complex handling, you can define::
104
105 @memcache.connection(nocache=2)
106 def foo(..., nocache=None, mc=None):
107 ...
108
109 foo(nocache=True)
110
111 This call to ``foo`` causes the same "oblivion" of the memcache connector, but
112 passes the nocache value to the ``foo`` function for further evaluation.
113
114 One further note: If the connector is passed from outside, like::
115
116 @memcache.connection(nocache=True)
117 def foo(..., mc=None):
118 ...
119
120 @memcache.connection(nocache=False)
121 def bar(..., mc=None):
122 foo(..., mc=mc)
123
124 The "inside" settings (here: ``foo``'s decorator's parameters) are ignored.
125
126 ``prepare`` defines a key preparation callable (overriding the default one,
127 which MD5s the keys). This callables takes a key and returns a key (at least
128 the returned value must be a ``str``)::
129
130 # identify preparation. Note that a configured prefix is still applied to
131 # the result.
132 prepare = lambda x: x
133
134 @memcache.connection(prepare=prepare)
135 def foo(..., mc=None):
136 mc.set(...)
137
138 ``exceptions`` determines whether the memcache user wants to see memcache
139 exceptions or not. If ``True`` the exceptions are passed through. If
140 ``False``, they're swallowed and treated as failed memcache response.
141 """
142 __author__ = u"Andr\xe9 Malo"
143 __docformat__ = "restructuredtext en"
144
145 import copy as _copy
146 try:
147 import hashlib as _md5
148 except ImportError:
149 import md5 as _md5
150 import time as _time
151
152 from wtf import services as _services
153 from wtf import util as _util
154 from wtf.ext import memcache as _memcache
157 """ Failsafe memcached decorator (against missing service) """
158 try:
159
160 from __svc__.wtf import memcache
161 except ImportError:
162 kwargs['disabled'] = True
163 def inner(func):
164 """ Decorator """
165 return TransparentCacheDecorator(
166 func, keygen, NoMemcacheWrapper(), 0, **kwargs
167 )
168 else:
169 def inner(func):
170 """ Decorator """
171 return memcache.memcached(keygen, **kwargs)(func)
172 return inner
173
176 """ Failsafe connection decorator (against missing service) """
177 try:
178
179 from __svc__.wtf import memcache
180 except ImportError:
181 if len(args) == 1 and not kwargs and callable(args[0]):
182 return args[0]
183 def inner(func):
184 """ Decorator """
185 return func
186 return inner
187
188 return memcache.connection(*args, **kwargs)
189
192 """ Decorator which transparently memoizes a function call """
193
194 - def __new__(cls, func, keygen, mcc, max_age, nocache=False,
195 disabled=False, pass_=False, local=False, nolocal=False,
196 recache=False):
197 """ Construction """
198
199 self = super(TransparentCacheDecorator, cls).__new__(cls)
200 extra = {}
201 if nocache == 1:
202 extra['nocache'] = False
203 if nolocal == 1:
204 extra['nolocal'] = False
205 if recache:
206 extra['recache'] = False
207 self.__init__(func, keygen, mcc, max_age,
208 nocache=nocache,
209 disabled=disabled,
210 pass_=pass_,
211 local=local,
212 nolocal=nolocal,
213 recache=recache,
214 )
215 return _util.decorating(func, extra=extra or None)(self)
216
217 - def __init__(self, func, keygen, mcc, max_age, nocache=False,
218 disabled=False, pass_=False, local=False, nolocal=False,
219 recache=False):
220 """
221 Initialization
222
223 :Parameters:
224 `func` : ``callable``
225 The function to decorate
226
227 `keygen` : ``callable``
228 Key generator callable
229
230 `mcc` : `Memcache`
231 Memcache connector
232
233 `nocache` : ``int``
234 Evaluate nocache argument?
235
236 `disabled` : ``bool``
237 Is this decorator disabled?
238
239 `pass_` : ``bool``
240 Pass memcache to the function?
241
242 `local` : ``bool`` or ``float``
243 Cache locally as well? (It will be deepcopied for usage)
244 The local cachetime will be `local` * max_age of the memcache age.
245 (if False, it's 0, if True, it's 1)
246
247 `nolocal` : ``int``
248 Evaluate nolocal argument?
249
250 `recache` : ``bool``
251 Evaluate recache argument? Useful for backfilling.
252 The memcache won't be asked, but set unconditionally.
253 """
254
255 super(TransparentCacheDecorator, self).__init__(func)
256 self._keygen = keygen
257 self._mc = mcc
258 self._nocache = nocache
259 self._disabled = disabled
260 self._pass = pass_
261 self._recache = recache
262 self._nolocal = nolocal
263 if local and max_age > 0:
264 max_age = int(max_age * local)
265 if max_age > 0:
266 self._local = max_age, {}
267 else:
268 self._local = None
269 else:
270 self._local = None
271
273 """
274 Compute the key, check for presence and return the cached result
275
276 If the key is not cached yet, just call the function and store the
277 result in the cache. Except nocache is requested by the caller and
278 activated in this decorator instance.
279
280 :Parameters:
281 `args` : ``tuple``
282 Function's positional arguments
283
284 `kwargs` : ``dict``
285 Function's keyword arguments
286
287 :Return: Whatever the decorated function returns
288 :Rtype: any
289
290 :Exceptions:
291 - `Exception` : Whatever the decorated function raises
292 """
293
294 if self._recache:
295 recache = kwargs.pop('recache', False)
296 else:
297 recache = False
298 if self._nocache:
299 nocache = kwargs.pop('nocache', False)
300 else:
301 nocache = False
302 if self._nolocal:
303 nolocal = kwargs.pop('nolocal', False)
304 else:
305 nolocal = False
306 if self._disabled or self._nocache:
307 if self._disabled:
308 nocache = True
309 if self._nocache > 1:
310 kwargs['nocache'] = nocache
311 if self._nolocal > 1:
312 kwargs['nolocal'] = nolocal
313 if self._pass:
314 kwargs['mc'] = NoMemcacheWrapper()
315 if nocache and self._nocache > 0:
316 return self._func(*args, **kwargs)
317
318 mcc = self._mc
319 if self._pass:
320 kwargs['mc'] = mcc
321 key = self._keygen(*args, **kwargs)
322 if not nolocal:
323 local = self._local
324 if local is not None and not recache:
325 found = local[1].get(key)
326 if found is not None:
327 stamp, found = found
328 if stamp >= _time.time():
329 return _copy.deepcopy(found)
330 try:
331 del local[1][key]
332 except KeyError:
333 pass
334 if not recache:
335 cached = mcc.get(key)
336 if cached:
337 if not nolocal and local is not None:
338 local[1][key] = (
339 _time.time() + local[0],
340 _copy.deepcopy(cached[key])
341 )
342 return cached[key]
343 result = self._func(*args, **kwargs)
344 mcc.set(key, result)
345 if not nolocal and local is not None:
346 local[1][key] = (_time.time() + local[0], _copy.deepcopy(result))
347 return result
348
351 """
352 Memcache decorator
353
354 :IVariables:
355 - `_mc`: Memcache connector
356
357 :Types:
358 - `_mc`: `MemcacheWrapper` or `Memcache`
359 """
360
361 - def __init__(self, func, mcc, nocache=False, disabled=False):
362 """
363 Initialization
364
365 :Parameters:
366 - `func`: The function to decorate
367 - `mcc`: The memcache connector
368 - `nocache`: Nocache behavior
369 - `disabled`: Is this decorator disabled?
370
371 :Types:
372 - `func`: ``callable``
373 - `mcc`: `MemcacheWrapper` or `Memcache`
374 - `nocache`: ``int``
375 - `disabled`: ``bool``
376 """
377 super(MemcacheDecorator, self).__init__(func)
378 self._mc = mcc
379 self._nocache = int(nocache)
380 self._disabled = disabled
381
383 """
384 Create a memcache connector or reuse a supplied one
385
386 The resulting connector is passed as a keyword argument into the
387 decorated function.
388
389 :Parameters:
390 - `args`: Function's positional arguments
391 - `kwargs`: Function's keyword arguments
392
393 :Types:
394 - `args`: ``tuple``
395 - `kwargs`: ``dict``
396
397 :return: Whatever the decorated function returns
398 :rtype: any
399
400 :Exceptions:
401 - `Exception`: Whatever the decorated function raises
402 """
403 if self._disabled:
404 kwargs['mc'] = NoMemcacheWrapper()
405 else:
406 mcc = kwargs.get('mc')
407 if not mcc:
408 mcc = self._mc
409 if self._nocache:
410 nocache = kwargs.pop('nocache', False)
411 if self._nocache > 1:
412 kwargs['nocache'] = nocache
413 if self._nocache > 0 and nocache:
414 mcc = NoMemcacheWrapper()
415 kwargs['mc'] = mcc
416 return self._func(*args, **kwargs)
417
420 """ Dummy connector, which does nothing actually, but provide the API """
421
422 - def set(self, key, value, max_age=None):
423 """
424 Set a key/value pair unconditionally
425
426 :Parameters:
427 - `key`: The key to store under
428 - `value`: The value to store (should be picklable)
429 - `max_age`: Maximum age in seconds. If omitted or ``None`` the
430 default is applied.
431
432 :Types:
433 - `key`: ``str``
434 - `value`: any
435 - `max_age`: ``int``
436
437 :return: Stored successfully?
438 :rtype: ``bool``
439 """
440
441
442 return False
443
444 - def add(self, key, value, max_age=None):
445 """
446 Set a key/value pair if the key does not exist yet
447
448 :Parameters:
449 - `key`: The key to store under
450 - `value`: The value to store (should be picklable)
451 - `max_age`: Maximum age in seconds. If omitted or ``None`` the
452 default is applied.
453
454 :Types:
455 - `key`: ``str``
456 - `value`: any
457 - `max_age`: ``int``
458
459 :return: Stored successfully?
460 :rtype: ``bool``
461 """
462
463
464 return False
465
466 - def replace(self, key, value, max_age=None):
467 """
468 Set a key/value pair only if the key does exist already
469
470 :Parameters:
471 - `key`: The key to store under
472 - `value`: The value to store (should be picklable)
473 - `max_age`: Maximum age in seconds. If omitted or ``None`` the
474 default is applied.
475
476 :Types:
477 - `key`: ``str``
478 - `value`: any
479 - `max_age`: ``int``
480
481 :return: Stored successfully?
482 :rtype: ``bool``
483 """
484
485
486 return False
487
488 - def delete(self, key, block_time=None, all_pools=False):
489 """
490 Delete a key/value pair from the cache
491
492 :Parameters:
493 - `key`: The key to identify the item to delete
494 - `block_time`: Time to block add and replace requests for this key
495 in seconds. If omitted or ``None``, the blocking time is ``0``.
496 - `all_pools`: Issue delete to each pool? This may be useful to
497 enforce the deletion on backup pools, too. However, it won't
498 delete the key from currently dead pools. So, it might be not
499 that useful after all, but it's the best we can do from this
500 side of the ocean.
501
502 :Types:
503 - `key`: ``str``
504 - `block_time`: ``int``
505 - `all_pools`: ``bool``
506
507 :return: Whether it was really deleted from the main pool (or the
508 current backup pool) of this key (i.e. whether it existed
509 before)
510 :rtype: ``bool``
511 """
512
513
514 return False
515
516 - def get(self, *keys):
517 """
518 Get a list of key/value pairs from the cache (if applicable)
519
520 The returned dict contains all pairs it could get. But keys maybe
521 missing or the dict might be completely empty (of course).
522
523 :Parameters:
524 - `keys`: The keys to fetch
525
526 :Types:
527 - `keys`: ``tuple``
528
529 :return: The dict of key/value pairs
530 :rtype: ``dict``
531 """
532
533
534 return {}
535
538 """
539 Exception catching wrapper
540
541 :IVariables:
542 - `_mc`: Memcache connector
543
544 :Types:
545 - `_mc`: `Memcache`
546 """
547
549 """
550 Initialization
551
552 :Parameters:
553 - `mcc`: Memcache connector
554
555 :Types:
556 - `mcc`: `Memcache`
557 """
558 self._mc = mcc
559
561 """
562 Create proxy around callables, catching memcache errors.
563
564 The proxy functions are cached.
565
566 :Parameters:
567 - `name`: The attribute to wrap up
568
569 :Types:
570 - `name`: ``str``
571
572 :return: The original attribute or the proxied placeholder
573 :rtype: any
574
575 :Exceptions:
576 - `AttributeError`: The attribute was not found
577 """
578 attr = getattr(self._mc, name)
579 if callable(attr):
580 def proxy(*args, **kwargs):
581 """ Catching proxy """
582 try:
583 return attr(*args, **kwargs)
584 except _memcache.Error:
585 return False
586 try:
587 proxy.__name__ = attr.__name__
588 except AttributeError:
589 pass
590 proxy.__doc__ = attr.__doc__
591 setattr(self, name, proxy)
592 return proxy
593 return attr
594
595 - def get(self, *keys):
596 """
597 Get a list of key/value pairs from the cache (if applicable)
598
599 The returned dict contains all pairs it could get. But keys maybe
600 missing or the dict might be completely empty (of course).
601
602 :Parameters:
603 - `keys`: The keys to fetch
604
605 :Types:
606 - `keys`: ``tuple``
607
608 :return: The dict of key/value pairs
609 :rtype: ``dict``
610 """
611 try:
612 return self._mc.get(*keys)
613 except _memcache.Error:
614 return {}
615
618 """
619 `Memcache` wrapper, applying default max age
620
621 This is, what the decorator injects if a default max age is configured
622 or the exceptions are caught.
623
624 :IVariables:
625 - `_mc`: Memcache connector
626 - `_max_age`: Default max age
627
628 :Types:
629 - `_mc`: `Memcache`
630 - `_max_age`: ``int``
631 """
632
633 - def __init__(self, mcc, max_age, exceptions):
634 """
635 Initialization
636
637 :Parameters:
638 - `mcc`: Memcache connector
639 - `max_age`: Default expire time
640 - `exceptions`: pass exceptions to the caller?
641
642 :Types:
643 - `mcc`: `Memcache`
644 - `max_age`: ``int``
645 - `exceptions`: ``bool``
646 """
647 if not exceptions:
648 mcc = ExceptionWrapper(mcc)
649 self._mc = mcc
650 self._max_age = max_age
651
652 self.delete = mcc.delete
653 self.get = mcc.get
654 if max_age is None:
655 self.set = mcc.set
656 self.add = mcc.add
657 self.replace = mcc.replace
658
659 - def set(self, key, value, max_age=None):
660 """
661 Set a key/value pair unconditionally
662
663 :Parameters:
664 - `key`: The key to store under
665 - `value`: The value to store (should be picklable)
666 - `max_age`: Maximum age in seconds. If omitted or ``None`` the
667 default is applied.
668
669 :Types:
670 - `key`: ``str``
671 - `value`: any
672 - `max_age`: ``int``
673
674 :return: Stored successfully?
675 :rtype: ``bool``
676 """
677
678
679 if max_age is None:
680 max_age = self._max_age
681 return self._mc.store("set", key, value, max_age)
682
683 - def add(self, key, value, max_age=None):
684 """
685 Set a key/value pair if the key does not exist yet
686
687 :Parameters:
688 - `key`: The key to store under
689 - `value`: The value to store (should be picklable)
690 - `max_age`: Maximum age in seconds. If omitted or ``None`` the
691 default is applied.
692
693 :Types:
694 - `key`: ``str``
695 - `value`: any
696 - `max_age`: ``int``
697
698 :return: Stored successfully?
699 :rtype: ``bool``
700 """
701
702
703 if max_age is None:
704 max_age = self._max_age
705 return self._mc.store("add", key, value, max_age)
706
707 - def replace(self, key, value, max_age=None):
708 """
709 Set a key/value pair only if the key does exist already
710
711 :Parameters:
712 - `key`: The key to store under
713 - `value`: The value to store (should be picklable)
714 - `max_age`: Maximum age in seconds. If omitted or ``None`` the
715 default is applied.
716
717 :Types:
718 - `key`: ``str``
719 - `value`: any
720 - `max_age`: ``int``
721
722 :return: Stored successfully?
723 :rtype: ``bool``
724 """
725
726
727 if max_age is None:
728 max_age = self._max_age
729 return self._mc.store("replace", key, value, max_age)
730
733 """
734 Actual global memcache service object
735
736 :IVariables:
737 - `_pools`: Pool list
738 - `_create`: Memcache wrapper creator
739 - `_max_age`: Globally configured max age
740 - `_mc`: Default memcache wrapper
741
742 :Types:
743 - `_pools`: ``tuple``
744 - `_create`: ``callable``
745 - `_max_age`: ``int``
746 - `_mc`: `MemcacheWrapper` or `Memcache`
747 """
748
749 - def __init__(self, pools, max_age, grace_time, retry_time,
750 compress_threshold, padded, split, prefix, largest_slab):
751 """
752 Initialization
753
754 :Parameters:
755 - `pools`: Pool list
756 - `max_age`: Default expire time (``None`` for no such default)
757 - `grace_time`: Grace time, see `ext.memcache.Memcache.__init__`
758 for details
759 - `retry_time`: Retry time, see `ext.memcache.Memcache.__init__`
760 for details
761 - `compress_threshold`: Compression threshold
762 - `padded`: Padded, yes/no? (``None`` for the default)
763 - `split`: Split yes/no? (``None`` for the default)
764 - `prefix`: global key prefix
765 - `largest_slab`: Largest slab size (``None`` for the default)
766
767 :Types:
768 - `pools`: ``iterable``
769 - `max_age`: ``int``
770 - `grace_time`: ``int``
771 - `retry_time`: ``int``
772 - `compress_threshold`: ``int``
773 - `padded`: ``bool``
774 - `split`: ``bool``
775 - `prefix`: ``str``
776 - `largest_slab`: ``int``
777 """
778 self._pools = tuple(pools)
779
780 def create(prepare, max_age, exceptions):
781 """
782 Memcache connector creator
783
784 :Parameters:
785 - `prepare`: Key preparation function
786 - `max_age`: Default expire time (or ``None``)
787 - `exceptions`: Raise exceptions?
788
789 :Types:
790 - `prepare`: ``callable``
791 - `max_age`: ``int``
792 - `exceptions`: ``bool``
793
794 :return: The memcache connector
795 :rtype: `Memcache` or `MemcacheWrapper`
796 """
797 mcc = _memcache.Memcache(self._pools,
798 prepare=prepare,
799 grace_time=grace_time,
800 retry_time=retry_time,
801 compress_threshold=compress_threshold,
802 padded=padded,
803 split=split,
804 prefix=prefix,
805 largest_slab=largest_slab,
806 )
807 if max_age is not None or not exceptions:
808 mcc = MemcacheWrapper(mcc, max_age, exceptions)
809 return mcc
810 self._max_age = max_age
811 self._create = create
812 self._mc = create(self._prepare, max_age, False)
813
815 """
816 Determine pool status
817
818 Each status is a dict
819 ``{'spec': 'spec', 'alive': bool, 'weight': int}``.
820
821 :return: The status of the pools (``[status, ...]``)
822 :rtype: ``list``
823 """
824 return [dict(
825 spec=pool.spec,
826 weight=pool.weight,
827 alive=not pool.dead,
828 ) for pool in self._pools]
829
831 """
832 Shutdown the memcache pools
833
834 The pools are no longer usable after that. This is for final
835 application shutdown. Don't use it in the application itself!
836 """
837 pools, self._pools = self._pools, ()
838 for pool in pools:
839 try:
840 pool.shutdown()
841 except (SystemExit, KeyboardInterrupt):
842 raise
843 except:
844 pass
845
846 - def connect(self, max_age=None, prepare=None, exceptions=None):
847 """
848 Create a memcache connector
849
850 Although the method name suggests it, the method doesn't actually
851 connect. The connection is selected by key later when using the
852 connector to actually do something.
853
854 :Parameters:
855 - `max_age`: Default max age for store commands in seconds (overriding
856 the configured default)
857 - `prepare`: Key preparation function (overriding the default)
858 - `exceptions`: Pass exceptions to the caller? (Default: ``False``)
859
860 :Types:
861 - `max_age`: ``int``
862 - `prepare`: ``callable``
863 - `exceptions`: ``bool``
864
865 :return: The memcache connector (may be wrapped for requested
866 functionality, so it's not necessarily a real `Memcache`)
867 :rtype: `Memcache`
868 """
869 if max_age is None and prepare is None and exceptions is None:
870 return self._mc
871
872 if max_age is None:
873 max_age = self._max_age
874 if prepare is None:
875 prepare = self._prepare
876 if exceptions is None:
877 exceptions = False
878 return self._create(prepare, max_age, exceptions)
879
881 """
882 Cache the function transparently
883
884 Recognized keyword parameters:
885
886 ``max_age``
887 [int] Default expire time for storing operations
888 ``prepare``
889 [callable] Key preparation function
890 ``nocache``
891 [int] Nocache behavior. See `services.memcache` for details.
892 ``recache``
893 [bool] Recache behavioue. See `services.memcache` for details.
894 ``disabled``
895 [bool] Disable this memcache decorator (useful for debugging)?
896 ``pass_``
897 [bool] If true, the memcache connector will be passed to the
898 function
899 ``exceptions``
900 [bool] Memcache exception behavior (pass through = True)
901
902 :Parameters:
903 `keygen` : ``callable``
904 Key generator function
905
906 `kwargs` : ``dict``
907 Keyword arguments
908
909 :Return: The memcached decorator
910 :Rtype: `TransparentCacheDecorator`
911 """
912 if self._max_age is None and kwargs.get('max_age') is None:
913 raise RuntimeError("@memcached needs a max age set")
914
915 nocache = kwargs.pop('nocache', None)
916 disabled = kwargs.pop('disabled', None)
917 pass_ = kwargs.pop('pass_', None)
918 local = kwargs.pop('local', None)
919 nolocal = kwargs.pop('nolocal', None)
920 recache = kwargs.pop('recache', None)
921 if disabled is None:
922 disabled = False
923 if nocache is None:
924 nocache = False
925 if nolocal is None:
926 nolocal = False
927 if recache is None:
928 recache = False
929 if pass_ is None:
930 pass_ = False
931 mcc = self.connect(**kwargs)
932 def factory(func):
933 """
934 Decorator factory
935
936 :Parameters:
937 - `func`: The function to decorate
938
939 :Types:
940 - `func`: ``callable``
941
942 :return: The decorated function
943 :rtype: ``callable``
944 """
945 return TransparentCacheDecorator(func, keygen, mcc, self._max_age,
946 nocache=nocache,
947 disabled=disabled,
948 pass_=pass_,
949 local=local,
950 nolocal=nolocal,
951 recache=recache,
952 )
953 return factory
954
956 """
957 Inject a new connector into function's arguments
958
959 The method takes either one positional argument (the function to
960 decorate) *or* keyword arguments which override default options:
961
962 ``max_age``
963 [int] Default expire time for storing operations
964 ``prepare``
965 [callable] Key preparation function
966 ``nocache``
967 [int] Nocache behavior. See `services.memcache` for details.
968 ``disabled``
969 [bool] Disable the memcache connection (useful for debugging)
970 ``exceptions``
971 [bool] Memcache exception behaviour (pass through = True)
972
973 :Parameters:
974 - `args`: Positional arguments
975 - `kwargs`: keyword arguments
976
977 :Types:
978 - `args`: ``tuple``
979 - `kwargs`: ``tuple``
980
981 :return: Decorator or decorator factory
982 :rtype: ``callable``
983
984 :Exceptions:
985 - `TypeError`: The arguments are formally invalid
986 """
987 if len(args) == 1 and not kwargs and callable(args[0]):
988 return MemcacheDecorator(args[0], self._mc)
989 elif not args:
990 nocache = kwargs.pop('nocache', None)
991 disabled = kwargs.pop('disabled', None)
992 if nocache is None:
993 nocache = False
994 if disabled is None:
995 disabled = False
996 mcc = self.connect(**kwargs)
997 def factory(func):
998 """
999 Decorator factory
1000
1001 :Parameters:
1002 - `func`: The function to decorate
1003
1004 :Types:
1005 - `func`: ``callable``
1006
1007 :return: The decorated function
1008 :rtype: ``callable``
1009 """
1010 return MemcacheDecorator(func, mcc, nocache=nocache)
1011 return factory
1012 raise TypeError(
1013 "Arguments have to be either one callable positional argument "
1014 "or keyword arguments"
1015 )
1016
1018 """
1019 Default key preparator
1020
1021 The input key is assumed to be a string and is just MD5 hashed.
1022 The hexdigest is the resulting key then.
1023
1024 :Parameters:
1025 - `key`: The key to prepare
1026
1027 :Types:
1028 - `key`: ``str``
1029
1030 :return: The prepared key
1031 :rtype: ``str``
1032 """
1033 return _md5.md5(key).hexdigest()
1034
1037 """
1038 Memcache service
1039
1040 This service provides a global memcache access.
1041
1042 :IVariables:
1043 - `_mc`: Global memcache service
1044
1045 :Types:
1046 - `_mc`: `GlobalMemcache`
1047 """
1048 __implements__ = [_services.ServiceInterface]
1049
1050 - def __init__(self, config, opts, args):
1051 """ :See: `wtf.services.ServiceInterface.__init__` """
1052 section = config.memcache
1053 servertokens = tuple(section.servers)
1054 pools = []
1055 for server in servertokens:
1056 key = u'memcache %s' % server
1057 if key in config:
1058 subsection = config[key]
1059 else:
1060 subsection = section
1061 server = _util.parse_socket_spec(server, _memcache.DEFAULT_PORT)
1062 pools.append(_memcache.MemcacheConnectionPool(
1063 subsection('maxconn', section('maxconn', 0)),
1064 subsection('maxcached', section('maxcached', 0)),
1065 server,
1066 weight=subsection('weight', section('weight', None)),
1067 timeout=subsection('timeout', section('timeout', 2.6)),
1068 ))
1069 max_age = unicode(section('max_age', u'')) or None
1070 if max_age is not None:
1071 max_age = int(max_age)
1072 self._mc = GlobalMemcache(pools,
1073 max_age,
1074 section('grace_time', None),
1075 section('retry_time', None),
1076 section('compress_threshold', None),
1077 section('padded', None),
1078 section('split', None),
1079 unicode(section('prefix', u'')).encode('utf-8'),
1080 section('largest_slab', None),
1081 )
1082
1083 @classmethod
1084 - def simple(cls, *spec, **kwargs):
1085 """
1086 Create simple on-the-fly configured service
1087
1088 Recognized keyword args:
1089
1090 ``max_age``
1091 [int] Default max age
1092 ``prefix``
1093 [unicode] Global key prefix
1094 ``padded``
1095 [bool] Padded small values?
1096 ``timeout``
1097 [float] Server timeout
1098
1099 :Parameters:
1100 - `spec`: Memcache servers (``('spec', ...)``)
1101 - `kwargs`: Keyword parameters for memcache config
1102
1103 :Types:
1104 - `spec`: ``tuple``
1105 - `kwargs`: ``dict``
1106
1107 :return: The memcache service
1108 :rtype: `GlobalMemcache`
1109
1110 :Exceptions:
1111 - `TypeError`: Unrecognized keyword args
1112 """
1113 from wtf import config as _config
1114 config = _config.Config(None)
1115 config['memcache'] = _config.Section()
1116 config['memcache']['servers'] = list(spec)
1117
1118 max_age = kwargs.pop('max_age', None)
1119 if max_age is not None:
1120 config['memcache']['max_age'] = int(max_age)
1121
1122 prefix = kwargs.pop('prefix', None)
1123 if prefix is not None:
1124 config['memcache']['prefix'] = unicode(prefix)
1125
1126 padded = kwargs.pop('padded', None)
1127 if padded is not None:
1128 config['memcache']['padded'] = bool(padded)
1129
1130 timeout = kwargs.pop('timeout', None)
1131 if timeout is not None:
1132 config['memcache']['timeout'] = float(timeout)
1133
1134 if kwargs:
1135 raise TypeError("Unrecognized keyword args: %s" % ", ".join(
1136 kwargs.iterkeys()
1137 ))
1138 return cls(config, None, []).global_service()[1]
1139
1141 """ :See: `wtf.services.ServiceInterface.shutdown` """
1142 self._mc.shutdown()
1143
1145 """ :See: `wtf.services.ServiceInterface.global_service` """
1146 return 'wtf.memcache', self._mc
1147
1149 """ :See: `wtf.services.ServiceInterface.middleware` """
1150 return func
1151