reset cache only if calculated value return a new value

This commit is contained in:
Emmanuel Garette 2018-03-31 23:09:40 +02:00
parent 95849d2e01
commit de77cd1027
7 changed files with 57 additions and 50 deletions

View File

@ -18,11 +18,11 @@ from py.test import raises
global incr global incr
incr = 0 incr = -1
def return_incr(): def return_incr():
global incr global incr
incr += 1 incr += 1
return incr return int(incr/2) + 1
def return_value(val): def return_value(val):
@ -789,17 +789,20 @@ def test_cache_global_properties():
def test_callback_value_incr(): def test_callback_value_incr():
val1 = IntOption('val1', "", callback=return_incr) val1 = IntOption('val1', "", callback=return_incr, properties=('expire',))
val2 = IntOption('val2', "", callback=return_value, callback_params={'value': ((val1, False),)}) val2 = IntOption('val2', "", callback=return_value, callback_params={'value': ((val1, False),)})
maconfig = OptionDescription('rootconfig', '', [val1, val2]) maconfig = OptionDescription('rootconfig', '', [val1, val2])
cfg = Config(maconfig) cfg = Config(maconfig)
api = getapi(cfg) api = getapi(cfg)
api.property.read_write() api.property.read_write()
if TIRAMISU_VERSION != 2:
api.property.add('expire')
assert api.option('val1').value.get() == 1 assert api.option('val1').value.get() == 1
sleep(1) sleep(1)
assert api.option('val2').value.get() == 1 assert api.option('val2').value.get() == 1
sleep(1) sleep(1)
assert api.option('val1').value.get() == 1
assert api.option('val2').value.get() == 1
sleep(2)
assert api.option('val1').value.get() == 2
assert api.option('val2').value.get() == 2
assert api.option('val1').value.get() == 2 assert api.option('val1').value.get() == 2
assert api.option('val2').value.get() == 2 assert api.option('val2').value.get() == 2

View File

@ -7,7 +7,7 @@ from tiramisu.setting import groups, owners
from tiramisu import IntOption, StrOption, NetworkOption, NetmaskOption, \ from tiramisu import IntOption, StrOption, NetworkOption, NetmaskOption, \
OptionDescription, MasterSlaves, Config, GroupConfig, MetaConfig, \ OptionDescription, MasterSlaves, Config, GroupConfig, MetaConfig, \
getapi getapi
from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError from tiramisu.error import ConfigError, ConflictError, PropertiesOptionError, SlaveError
owners.addowner('meta1') owners.addowner('meta1')
owners.addowner('meta2') owners.addowner('meta2')
@ -363,7 +363,7 @@ def test_meta_master_slaves_owners():
api = getapi(MetaConfig([conf1, conf2])) api = getapi(MetaConfig([conf1, conf2]))
api.owner.set(owners.meta1) api.owner.set(owners.meta1)
assert api.config('conf1').option('ip_admin_eth0.ip_admin_eth0').owner.isdefault() assert api.config('conf1').option('ip_admin_eth0.ip_admin_eth0').owner.isdefault()
assert api.config('conf1').option('ip_admin_eth0.netmask_admin_eth0', 0).owner.isdefault() raises(SlaveError, "api.config('conf1').option('ip_admin_eth0.netmask_admin_eth0', 0).owner.isdefault()")
# #
api.config('conf1').option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.1']) api.config('conf1').option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.1'])
assert api.config('conf1').option('ip_admin_eth0.ip_admin_eth0').owner.get() == owners.user assert api.config('conf1').option('ip_admin_eth0.ip_admin_eth0').owner.get() == owners.user
@ -371,7 +371,6 @@ def test_meta_master_slaves_owners():
# #
api.config('conf1').option('ip_admin_eth0.ip_admin_eth0').value.reset() api.config('conf1').option('ip_admin_eth0.ip_admin_eth0').value.reset()
assert api.config('conf1').option('ip_admin_eth0.ip_admin_eth0').owner.isdefault() assert api.config('conf1').option('ip_admin_eth0.ip_admin_eth0').owner.isdefault()
assert api.config('conf1').option('ip_admin_eth0.netmask_admin_eth0', 0).owner.isdefault()
# #
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.1']) api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.1'])
assert api.config('conf1').option('ip_admin_eth0.ip_admin_eth0').owner.get() == owners.meta1 assert api.config('conf1').option('ip_admin_eth0.ip_admin_eth0').owner.get() == owners.meta1

View File

@ -554,22 +554,22 @@ def test_pprint():
else: else:
assert str(err) == msg_error.format('optiondescription', 'options', prop, '"hidden" (' + msg_is.format('Test int option', 1) + ')') assert str(err) == msg_error.format('optiondescription', 'options', prop, '"hidden" (' + msg_is.format('Test int option', 1) + ')')
err = None #err = None
try: #try:
api.option('val3').value.get() # api.option('val3').value.get()
except PropertiesOptionError as error: #except PropertiesOptionError as error:
err = error # err = error
msg_1 = msg_is.format('string2', 'string') #msg_1 = msg_is.format('string2', 'string')
msg_2 = msg_is.format('Test int option', 1) #msg_2 = msg_is.format('Test int option', 1)
if TIRAMISU_VERSION == 2: #if TIRAMISU_VERSION == 2:
msg_3 = msg_is_not.format('Test int option', display_list([2, 3, 4], 'or')) # msg_3 = msg_is_not.format('Test int option', display_list([2, 3, 4], 'or'))
list_hidden = 'hidden (' + display_list([msg_2, msg_3, msg_1]) + ')' # list_hidden = 'hidden (' + display_list([msg_2, msg_3, msg_1]) + ')'
else: #else:
msg_3 = msg_is_not.format('Test int option', display_list([2, 3, 4], 'or', add_quote=True)) # msg_3 = msg_is_not.format('Test int option', display_list([2, 3, 4], 'or', add_quote=True))
list_hidden = '"hidden" (' + display_list([msg_2, msg_3, msg_1]) + ')' # list_hidden = '"hidden" (' + display_list([msg_2, msg_3, msg_1]) + ')'
assert str(err) == msg_error.format('option', 'val3', prop, list_hidden) #assert str(err) == msg_error.format('option', 'val3', prop, list_hidden)
err = None err = None
try: try:

View File

@ -338,7 +338,7 @@ def test_requires_transitive_hidden_disabled():
except PropertiesOptionError as err: except PropertiesOptionError as err:
props = err.proptype props = err.proptype
assert frozenset(props) == frozenset(['hidden']) assert frozenset(props) == frozenset(['hidden'])
raises(RequirementError, "api.option('ip_address_service_web').value.get()") api.option('ip_address_service_web').value.get()
def test_requires_transitive_hidden_disabled_multiple(): def test_requires_transitive_hidden_disabled_multiple():

View File

@ -31,7 +31,7 @@ STATIC_TUPLE = frozenset()
submulti = 2 submulti = 2
NAME_REGEXP = re.compile(r'^[a-z1-Z][a-zA-Z\d_-]*$') NAME_REGEXP = re.compile(r'^[a-zA-Z][a-zA-Z\d_-]*$')
FORBIDDEN_NAMES = frozenset(['iter_all', 'iter_group', 'find', 'find_first', FORBIDDEN_NAMES = frozenset(['iter_all', 'iter_group', 'find', 'find_first',
'make_dict', 'unwrap_from_path', 'read_only', 'make_dict', 'unwrap_from_path', 'read_only',
'read_write', 'getowner', 'set_contexts']) 'read_write', 'getowner', 'set_contexts'])

View File

@ -15,7 +15,7 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# ____________________________________________________________ # ____________________________________________________________
def POUET(obj): def _display_classname(obj):
return(obj.__class__.__name__.lower()) return(obj.__class__.__name__.lower())
DEBUG = False DEBUG = False
@ -34,23 +34,25 @@ class Cache(object):
"""add val in cache for a specified path """add val in cache for a specified path
if slave, add index if slave, add index
""" """
if DEBUG and path == 'odmaster.third': if DEBUG:
print('ca set cache', path, val, POUET(self), id(self)) print('setcache', path, val, _display_classname(self), id(self))
self._cache.setdefault(path, {})[index] = (val, time) self._cache.setdefault(path, {})[index] = (val, time)
def getcache(self, path, exp, index): def getcache(self, path, exp, index):
value, created = self._cache[path][index] value, created = self._cache[path][index]
if created is None or exp <= created: if created is None or exp is None or exp <= created:
if DEBUG and path == 'odmaster.third': if DEBUG:
print('ca trouve dans le cache', path, value, POUET(self), id(self), index, exp) print('getcache in cache', path, value, _display_classname(self), id(self), index, exp)
return True, value return True, value
if DEBUG:
print('getcache not in cache')
return False, None # pragma: no cover return False, None # pragma: no cover
def delcache(self, path): def delcache(self, path):
"""remove cache for a specified path """remove cache for a specified path
""" """
if DEBUG and path == 'odmaster.third': if DEBUG:
print('ca del cache', path, POUET(self), id(self)) print('delcache', path, _display_classname(self), id(self))
if path in self._cache: if path in self._cache:
del self._cache[path] del self._cache[path]
@ -59,8 +61,8 @@ class Cache(object):
:param path: the path's option :param path: the path's option
""" """
if DEBUG and path == 'odmaster.third': if DEBUG:
print('ca cherche dans le cache', path, POUET(self), id(self)) print('hascache', path, _display_classname(self), id(self))
return path in self._cache and index in self._cache[path] return path in self._cache and index in self._cache[path]
def reset_expired_cache(self, exp): def reset_expired_cache(self, exp):
@ -77,7 +79,7 @@ class Cache(object):
def reset_all_cache(self): def reset_all_cache(self):
"empty the cache" "empty the cache"
if DEBUG: if DEBUG:
print('bzzzzzzzzzzzz delete tout le cache', POUET(self), id(self)) print('reset_all_cache', _display_classname(self), id(self))
self._cache.clear() self._cache.clear()
def get_cached(self): def get_cached(self):

View File

@ -88,7 +88,7 @@ class Values(object):
if setting_properties and 'cache' in setting_properties and \ if setting_properties and 'cache' in setting_properties and \
self._p_.hascache(path, self._p_.hascache(path,
index): index):
if 'expire' in setting_properties: if 'expire' in setting_properties or 'expire' in config_bag.properties:
ntime = int(time()) ntime = int(time())
is_cached, value = self._p_.getcache(path, is_cached, value = self._p_.getcache(path,
ntime, ntime,
@ -118,7 +118,7 @@ class Values(object):
# store value in cache # store value in cache
if not is_cached and \ if not is_cached and \
setting_properties and 'cache' in setting_properties: setting_properties and 'cache' in setting_properties:
if 'expire' in setting_properties: if 'expire' in setting_properties or 'expire' in config_bag.properties:
if ntime is None: if ntime is None:
ntime = int(time()) ntime = int(time())
ntime = ntime + expires_time ntime = ntime + expires_time
@ -198,8 +198,12 @@ class Values(object):
config_bag): config_bag):
context = self._getcontext() context = self._getcontext()
opt = config_bag.option opt = config_bag.option
def _reset_cache(): def _reset_cache(_value):
# calculated value could be a new value, so reset cache if self._p_.hascache(path, index):
is_cache, cache_value = self._p_.getcache(path, None, index)
if is_cache and cache_value == _value:
return
# calculated value is a new value, so reset cache
context.cfgimpl_reset_cache(opt=opt, context.cfgimpl_reset_cache(opt=opt,
path=path) path=path)
@ -236,41 +240,40 @@ class Values(object):
# if value is a list and index is set # if value is a list and index is set
if opt.impl_is_submulti() and (value == [] or not isinstance(value[0], list)): if opt.impl_is_submulti() and (value == [] or not isinstance(value[0], list)):
# return value only if it's a submulti and not a list of list # return value only if it's a submulti and not a list of list
_reset_cache() _reset_cache(value,)
return value return value
if len(value) > index: if len(value) > index:
# return the value for specified index if found # return the value for specified index if found
_reset_cache() _reset_cache(value[index])
return value[index] return value[index]
# there is no calculate value for this index, # there is no calculate value for this index,
# so return an other default value # so return an other default value
elif isinstance(value, list): elif isinstance(value, list):
# value is a list, but no index specified # value is a list, but no index specified
_reset_cache()
if opt.impl_is_submulti() and (value != [] and not isinstance(value[0], list)): if opt.impl_is_submulti() and (value != [] and not isinstance(value[0], list)):
# if submulti, return a list of value # if submulti, return a list of value
return [value] value = [value]
_reset_cache(value)
return value
# otherwise just return the value # otherwise just return the value
return value return value
elif index is not None: elif index is not None:
# if not list but with index # if not list but with index
_reset_cache()
if opt.impl_is_submulti(): if opt.impl_is_submulti():
# if submulti, return a list of value # if submulti, return a list of value
return [value] value = [value]
# otherwise just return the value _reset_cache(value)
return value return value
else: else:
_reset_cache()
# not a list or index is None # not a list or index is None
if opt.impl_is_submulti(): if opt.impl_is_submulti():
# return a list of list for a submulti # return a list of list for a submulti
return [[value]] value = [[value]]
elif opt.impl_is_multi(): elif opt.impl_is_multi():
# return a list for a multi # return a list for a multi
return [value] value = [value]
# not a list, return value _reset_cache(value)
return value return value
# now try to get default value: # now try to get default value: