Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(405)

Side by Side Diff: chrome/common/extensions/docs/server2/appengine_memcache.py

Issue 10829348: Extensions Docs Server: Large performance increase (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: server is fast Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import time
6
5 from appengine_wrappers import memcache 7 from appengine_wrappers import memcache
8 from future import Future
6 9
7 MEMCACHE_FILE_SYSTEM_READ = 'MemcacheFileSystem.Get' 10 MEMCACHE_FILE_SYSTEM_READ = 'MemcacheFileSystem.Get'
8 MEMCACHE_FILE_SYSTEM_STAT = 'MemcacheFileSystem.Stat' 11 MEMCACHE_FILE_SYSTEM_STAT = 'MemcacheFileSystem.Stat'
9 MEMCACHE_GITHUB_STAT = 'MemcacheGithub.Stat' 12 MEMCACHE_GITHUB_STAT = 'MemcacheGithub.Stat'
10 MEMCACHE_BRANCH_UTILITY = 'BranchUtility' 13 MEMCACHE_BRANCH_UTILITY = 'BranchUtility'
14 MEMCACHE_FILE_SYSTEM_CACHE = 'MemcacheFileSystemCache'
15 MEMCACHE_FILE_SYSTEM_CACHE_LISTING = 'MemcacheFileSystemCache.Listing'
16
17 class _CacheEntry(object):
18 def __init__(self, value, expire_time):
19 self.value = value
20 self._never_expires = (expire_time == 0)
21 self._expiry = time.time() + expire_time
22
23 def HasExpired(self):
24 if self._never_expires:
25 return False
26 return time.time() > self._expiry
27
28 class _AsyncGetFuture(object):
29 def __init__(self, cache, time, namespace, rpc=None, mapping=None):
not at google - send to devlin 2012/08/20 05:27:10 document these parameters? I had to read the code
cduvall 2012/08/20 21:28:09 Done.
30 self._cache = cache
31 self._time = time
32 self._namespace = namespace
33 self._rpc = rpc
34 self._mapping = mapping
35
36 def Get(self):
37 if self._rpc is not None:
38 result = self._rpc.get_result()
39 self._cache[self._namespace].update(
40 dict((k, _CacheEntry(v, self._time)) for k, v in result.iteritems()))
41 self._mapping.update(result)
not at google - send to devlin 2012/08/20 05:27:10 this only works if initial_mapping is not None, an
cduvall 2012/08/20 21:28:09 Done.
42 return self._mapping
11 43
12 class AppEngineMemcache(object): 44 class AppEngineMemcache(object):
not at google - send to devlin 2012/08/20 05:27:10 This all just got complicated. You're gonna hate
cduvall 2012/08/20 21:28:09 Done.
13 """A wrapper around the standard App Engine memcache that enforces namespace 45 """A wrapper around the standard App Engine memcache that enforces namespace
14 use. Uses a branch to make sure there are no key collisions if separate 46 use. Uses a branch to make sure there are no key collisions if separate
15 branches cache the same file. 47 branches cache the same file.
16 """ 48 """
17 def __init__(self, branch): 49 def __init__(self, branch):
18 self._branch = branch 50 self._branch = branch
51 self._cache = {}
19 52
20 def Set(self, key, value, namespace, time=60): 53 def _SetInMemory(self, key, value, namespace, time):
21 return memcache.set(key, 54 if namespace not in self._cache:
22 value, 55 self._cache[namespace] = {}
23 namespace=self._branch + '.' + namespace, 56 self._cache[namespace][key] = _CacheEntry(value, time)
24 time=time)
25 57
26 def Get(self, key, namespace): 58 def _TryGAE(self, key, namespace, time):
27 return memcache.get(key, namespace=self._branch + '.' + namespace) 59 result = memcache.get(key, namespace=namespace)
60 if result is not None:
61 self._SetInMemory(key, result, namespace, time)
62 return result
63
64 def _MakeNamespace(self, namespace):
65 return self._branch + '.' + namespace
66
67 def Set(self, key, value, namespace, time=300):
not at google - send to devlin 2012/08/20 05:27:10 define 300 as a constant somewhere?
cduvall 2012/08/20 21:28:09 Done.
68 namespace = self._MakeNamespace(namespace)
69 self._SetInMemory(key, value, namespace, time)
70 memcache.set(key, value, namespace=namespace, time=time)
not at google - send to devlin 2012/08/20 05:27:10 this can be an async set, right? We don't care abo
cduvall 2012/08/20 21:28:09 There isn't a set_async function in memcache, only
71
72 def SetMulti(self, mapping, namespace, time=300):
73 namespace = self._MakeNamespace(namespace)
74 for k, v in mapping.iteritems():
75 self._SetInMemory(k, v, namespace, time)
76 # Use a batch set? App Engine kept throwing:
77 # ValueError: Values may not be more than 1000000 bytes in length
not at google - send to devlin 2012/08/20 05:27:10 Interesting. Yeah make this a TODO. If it's an as
cduvall 2012/08/20 21:28:09 Done.
78 # for the batch set.
79 self.Set(k, v, namespace, time=time)
80
81 def Get(self, key, namespace, time=300):
82 namespace = self._MakeNamespace(namespace)
83 if namespace not in self._cache:
84 return self._TryGAE(key, namespace, time)
85 cache_entry = self._cache[namespace].get(key, None)
86 if not cache_entry:
87 return self._TryGAE(key, namespace, time)
88 if cache_entry.HasExpired():
89 self._cache[namespace].pop(key)
90 return memcache.get(key, namespace=namespace)
91 return cache_entry.value
92
93 def GetMulti(self, keys, namespace, time=300):
94 namespace = self._MakeNamespace(namespace)
95 keys = keys[:]
96 mapping = {}
97 if namespace not in self._cache:
98 self._cache[namespace] = {}
99 for key in keys:
100 cache_entry = self._cache[namespace].get(key, None)
101 if cache_entry is not None and not cache_entry.HasExpired():
not at google - send to devlin 2012/08/20 05:27:10 nit: reverse the condition to make this more reada
cduvall 2012/08/20 21:28:09 Done.
102 mapping[key] = cache_entry.value
103 keys.remove(key)
104 else:
105 mapping[key] = None
106 client = memcache.Client()
107 rpc = client.get_multi_async(keys, namespace=namespace)
108 return Future(delegate=_AsyncGetFuture(self._cache,
109 time,
110 namespace,
111 rpc=rpc,
112 mapping=mapping))
28 113
29 def Delete(self, key, namespace): 114 def Delete(self, key, namespace):
30 return memcache.delete(key, namespace=self._branch + '.' + namespace) 115 namespace = self._MakeNamespace(namespace)
116 if namespace in self._cache:
117 self._cache[namespace].pop(key)
118 memcache.delete(key, namespace=namespace)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698