expire cache when ram excees 90%

This commit is contained in:
mdipierro committed 2015-03-22 13:40:05 -05:00
1 parent 81fc9dbc6c
commit 3ea49739d3
1 file changed
+39 -18
+39 -18
View File
@@ -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