expire cache when ram excees 90%
This commit is contained in:
1 parent
81fc9dbc6c
commit
3ea49739d3
1 file changed
+39
-18
+39
-18
@@ -22,6 +22,7 @@ caching will be provided by the GAE memcache
|
|||||||
import time
|
import time
|
||||||
import thread
|
import thread
|
||||||
import os
|
import os
|
||||||
|
import gc
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
@@ -40,6 +41,30 @@ try:
|
|||||||
except:
|
except:
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
|
try:
|
||||||
|
from collections import OrderedDict
|
||||||
|
import psutil
|
||||||
|
CAN_DO_CLEANUP = True
|
||||||
|
except ImportError:
|
||||||
|
CAN_DO_CLEANUP = False
|
||||||
|
|
||||||
|
def remove_oldest_entries(storage, percentage=90):
|
||||||
|
# compute current memory usage (%)
|
||||||
|
old_mem = psutil.virtual_memory().percent
|
||||||
|
# if we have data in storage and utilization exceeds 90%
|
||||||
|
while storage and old_mem > percentage:
|
||||||
|
# removed oldest entry
|
||||||
|
storage.popitem(last=False)
|
||||||
|
# garbage collect
|
||||||
|
gc.collect(2)
|
||||||
|
# comute used memory again
|
||||||
|
new_mem = psutil.virtual_memory().percent
|
||||||
|
# if the used memory did not decrease stop
|
||||||
|
if new_mem >= old_mem: break
|
||||||
|
# net new measurement for memory usage and loop
|
||||||
|
old_mem = new_mem
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger("web2py.cache")
|
logger = logging.getLogger("web2py.cache")
|
||||||
|
|
||||||
__all__ = ['Cache', 'lazy_cache']
|
__all__ = ['Cache', 'lazy_cache']
|
||||||
@@ -47,8 +72,6 @@ __all__ = ['Cache', 'lazy_cache']
|
|||||||
|
|
||||||
DEFAULT_TIME_EXPIRE = 300
|
DEFAULT_TIME_EXPIRE = 300
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CacheAbstract(object):
|
class CacheAbstract(object):
|
||||||
"""
|
"""
|
||||||
Abstract class for cache implementations.
|
Abstract class for cache implementations.
|
||||||
@@ -145,28 +168,25 @@ class CacheInRam(CacheAbstract):
|
|||||||
|
|
||||||
locker = thread.allocate_lock()
|
locker = thread.allocate_lock()
|
||||||
meta_storage = {}
|
meta_storage = {}
|
||||||
|
stats = {}
|
||||||
|
|
||||||
def __init__(self, request=None):
|
def __init__(self, request=None):
|
||||||
self.initialized = False
|
self.initialized = False
|
||||||
self.request = request
|
self.request = request
|
||||||
self.storage = {}
|
self.storage = OrderedDict() if CAN_DO_CLEANUP else {}
|
||||||
|
self.app = request.application if request else ''
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
if self.initialized:
|
if self.initialized:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self.initialized = True
|
self.initialized = True
|
||||||
self.locker.acquire()
|
self.locker.acquire()
|
||||||
request = self.request
|
if not self.app in self.meta_storage:
|
||||||
if request:
|
self.storage = self.meta_storage[self.app] = \
|
||||||
app = request.application
|
OrderedDict() if CAN_DO_CLEANUP else {}
|
||||||
|
self.stats[self.app] = {'hit_total': 0, 'misses': 0}
|
||||||
else:
|
else:
|
||||||
app = ''
|
self.storage = self.meta_storage[self.app]
|
||||||
if not app in self.meta_storage:
|
|
||||||
self.storage = self.meta_storage[app] = {
|
|
||||||
CacheAbstract.cache_stats_name: {'hit_total': 0, 'misses': 0}}
|
|
||||||
else:
|
|
||||||
self.storage = self.meta_storage[app]
|
|
||||||
self.locker.release()
|
self.locker.release()
|
||||||
|
|
||||||
def clear(self, regex=None):
|
def clear(self, regex=None):
|
||||||
@@ -178,9 +198,8 @@ class CacheInRam(CacheAbstract):
|
|||||||
else:
|
else:
|
||||||
self._clear(storage, regex)
|
self._clear(storage, regex)
|
||||||
|
|
||||||
if not CacheAbstract.cache_stats_name in storage.keys():
|
if not self.app in self.stats:
|
||||||
storage[CacheAbstract.cache_stats_name] = {
|
self.stats[self.app] = {'hit_total': 0, 'misses': 0}
|
||||||
'hit_total': 0, 'misses': 0}
|
|
||||||
|
|
||||||
self.locker.release()
|
self.locker.release()
|
||||||
|
|
||||||
@@ -211,7 +230,7 @@ class CacheInRam(CacheAbstract):
|
|||||||
del self.storage[key]
|
del self.storage[key]
|
||||||
if destroyer:
|
if destroyer:
|
||||||
destroyer(item[1])
|
destroyer(item[1])
|
||||||
self.storage[CacheAbstract.cache_stats_name]['hit_total'] += 1
|
self.stats[self.app]['hit_total'] += 1
|
||||||
self.locker.release()
|
self.locker.release()
|
||||||
|
|
||||||
if f is None:
|
if f is None:
|
||||||
@@ -224,7 +243,9 @@ class CacheInRam(CacheAbstract):
|
|||||||
|
|
||||||
self.locker.acquire()
|
self.locker.acquire()
|
||||||
self.storage[key] = (now, value)
|
self.storage[key] = (now, value)
|
||||||
self.storage[CacheAbstract.cache_stats_name]['misses'] += 1
|
self.stats[self.app]['misses'] += 1
|
||||||
|
if CAN_DO_CLEANUP:
|
||||||
|
remove_oldest_entries(self.storage)
|
||||||
self.locker.release()
|
self.locker.release()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user