Browse Source

Merge pull request #1102 from rmehta/cache-redesign

Cache redesign
version-14
Rushabh Mehta 10 years ago
parent
commit
bbafe0d823
19 changed files with 197 additions and 155 deletions
  1. +4
    -4
      frappe/__init__.py
  2. +2
    -4
      frappe/database.py
  3. +7
    -12
      frappe/defaults.py
  4. +1
    -1
      frappe/desk/form/meta.py
  5. +1
    -1
      frappe/desk/moduleview.py
  6. +28
    -20
      frappe/desk/notifications.py
  7. +2
    -1
      frappe/model/document.py
  8. +31
    -28
      frappe/model/meta.py
  9. +3
    -1
      frappe/modules/__init__.py
  10. +19
    -14
      frappe/sessions.py
  11. +8
    -8
      frappe/tests/test_translation.py
  12. +9
    -10
      frappe/translate.py
  13. +1
    -8
      frappe/utils/data.py
  14. +42
    -16
      frappe/utils/redis_wrapper.py
  15. +8
    -8
      frappe/utils/user.py
  16. +6
    -4
      frappe/website/context.py
  17. +13
    -7
      frappe/website/render.py
  18. +4
    -2
      frappe/website/router.py
  19. +8
    -6
      frappe/website/utils.py

+ 4
- 4
frappe/__init__.py View File

@@ -432,10 +432,10 @@ def has_website_permission(doctype, ptype="read", doc=None, user=None, verbose=F


def is_table(doctype): def is_table(doctype):
"""Returns True if `istable` property (indicating child Table) is set for given DocType.""" """Returns True if `istable` property (indicating child Table) is set for given DocType."""
tables = cache().get_value("is_table")
if tables==None:
tables = db.sql_list("select name from tabDocType where ifnull(istable,0)=1")
cache().set_value("is_table", tables)
def get_tables():
return db.sql_list("select name from tabDocType where ifnull(istable,0)=1")
tables = cache().get_value("is_table", get_tables)
return doctype in tables return doctype in tables


def get_precision(doctype, fieldname, currency=None, doc=None): def get_precision(doctype, fieldname, currency=None, doc=None):


+ 2
- 4
frappe/database.py View File

@@ -602,14 +602,12 @@ class Database:
def set_temp(self, value): def set_temp(self, value):
"""Set a temperory value and return a key.""" """Set a temperory value and return a key."""
key = frappe.generate_hash() key = frappe.generate_hash()
frappe.cache().set_value(key, value)
frappe.cache().hset("temp", value)
return key return key


def get_temp(self, key): def get_temp(self, key):
"""Return the temperory value and delete it.""" """Return the temperory value and delete it."""
value = frappe.cache().get_value(key)
frappe.cache().delete_value(key)
return value
return frappe.cache().hget("temp", key)


def set_global(self, key, val, user='__global'): def set_global(self, key, val, user='__global'):
"""Save a global key value. Global values will be automatically set if they match fieldname.""" """Save a global key value. Global values will be automatically set if they match fieldname."""


+ 7
- 12
frappe/defaults.py View File

@@ -31,7 +31,7 @@ def get_user_permissions(user=None):
return build_user_permissions(user) return build_user_permissions(user)


def build_user_permissions(user): def build_user_permissions(user):
out = frappe.cache().get_value("user_permissions", user=user)
out = frappe.cache().hget("user_permissions", user)
if out==None: if out==None:
out = {} out = {}
for key, value in frappe.db.sql("""select defkey, ifnull(defvalue, '') as defvalue for key, value in frappe.db.sql("""select defkey, ifnull(defvalue, '') as defvalue
@@ -42,7 +42,7 @@ def build_user_permissions(user):
if user not in out.get("User", []): if user not in out.get("User", []):
out.setdefault("User", []).append(user) out.setdefault("User", []).append(user)


frappe.cache().set_value("user_permissions", out, user=user)
frappe.cache().hset("user_permissions", user, out)
return out return out


def get_defaults(user=None): def get_defaults(user=None):
@@ -147,7 +147,7 @@ def clear_default(key=None, value=None, parent=None, name=None, parenttype=None)


def get_defaults_for(parent="__default"): def get_defaults_for(parent="__default"):
"""get all defaults""" """get all defaults"""
defaults = frappe.cache().get_value("__defaults:" + parent)
defaults = frappe.cache().hget("defaults", parent)
if defaults==None: if defaults==None:
# sort descending because first default must get preceedence # sort descending because first default must get preceedence
res = frappe.db.sql("""select defkey, defvalue from `tabDefaultValue` res = frappe.db.sql("""select defkey, defvalue from `tabDefaultValue`
@@ -166,7 +166,7 @@ def get_defaults_for(parent="__default"):
elif d.defvalue is not None: elif d.defvalue is not None:
defaults[d.defkey] = d.defvalue defaults[d.defkey] = d.defvalue


frappe.cache().set_value("__defaults:" + parent, defaults)
frappe.cache().hset("defaults", parent, defaults)


return defaults return defaults


@@ -181,12 +181,7 @@ def clear_cache(user=None):
to_clear = [] to_clear = []
if user: if user:
to_clear = [user] to_clear = [user]
for p in (to_clear + common_keys):
frappe.cache().hdel("default", p)
elif frappe.flags.in_install!="frappe": elif frappe.flags.in_install!="frappe":
try:
to_clear = frappe.db.sql_list("select name from tabUser")
except Exception, e:
if e.args[0]!=1146:
# special case, in rename patch
raise
for p in (to_clear + common_keys):
frappe.cache().delete_value("__defaults:" + p)
frappe.cache().delete_key("default")

+ 1
- 1
frappe/desk/form/meta.py View File

@@ -16,7 +16,7 @@ from frappe.utils.jinja import render_include


def get_meta(doctype, cached=True): def get_meta(doctype, cached=True):
if cached and not frappe.conf.developer_mode: if cached and not frappe.conf.developer_mode:
meta = frappe.cache().get_value("form_meta:" + doctype, lambda: FormMeta(doctype))
meta = frappe.cache().hget("form_meta", doctype, lambda: FormMeta(doctype))
else: else:
meta = FormMeta(doctype) meta = FormMeta(doctype)




+ 1
- 1
frappe/desk/moduleview.py View File

@@ -201,7 +201,7 @@ def get_last_modified(doctype):


return last_modified return last_modified


last_modified = frappe.cache().get_value("last_modified:" + doctype, _get)
last_modified = frappe.cache().hget("last_modified", doctype, _get)


if last_modified==-1: if last_modified==-1:
last_modified = None last_modified = None


+ 28
- 20
frappe/desk/notifications.py View File

@@ -12,10 +12,14 @@ def get_notifications():
return return


config = get_notification_config() config = get_notification_config()
groups = config.get("for_doctype").keys() + config.get("for_module").keys()
cache = frappe.cache()


notification_count = frappe.cache().get_all("notification_count:" \
+ frappe.session.user + ":").iteritems()
notification_count = dict([(d.rsplit(":", 1)[1], v) for d, v in notification_count])
notification_count = {}
for name in groups:
count = cache.hget("notification_count:" + name, frappe.session.user)
if count is not None:
notification_count[name] = count


return { return {
"open_count_doctype": get_notifications_for_doctypes(config, notification_count), "open_count_doctype": get_notifications_for_doctypes(config, notification_count),
@@ -24,10 +28,9 @@ def get_notifications():
} }


def get_new_messages(): def get_new_messages():
cache_key = "notifications_last_update:" + frappe.session.user
last_update = frappe.cache().get_value(cache_key)
last_update = frappe.cache().hget("notifications_last_update", frappe.session.user)
now_timestamp = now() now_timestamp = now()
frappe.cache().set_value(cache_key, now_timestamp)
frappe.cache().hset("notifications_last_update", frappe.session.user, now_timestamp)


if not last_update: if not last_update:
return [] return []
@@ -51,8 +54,7 @@ def get_notifications_for_modules(config, notification_count):
else: else:
open_count_module[m] = frappe.get_attr(config.for_module[m])() open_count_module[m] = frappe.get_attr(config.for_module[m])()


frappe.cache().set_value("notification_count:" + frappe.session.user + ":" + m,
open_count_module[m])
frappe.cache().hset("notification_count:" + m, frappe.session.user, open_count_module[m])


return open_count_module return open_count_module


@@ -81,17 +83,20 @@ def get_notifications_for_doctypes(config, notification_count):


else: else:
open_count_doctype[d] = result open_count_doctype[d] = result

frappe.cache().set_value("notification_count:" + frappe.session.user + ":" + d,
result)
frappe.cache().hset("notification_count:" + d, frappe.session.user, result)


return open_count_doctype return open_count_doctype


def clear_notifications(user="*"): def clear_notifications(user="*"):
frappe.cache().delete_keys("notification_count:" + (user or frappe.session.user) + ":")
if user=="*":
frappe.cache().delete_keys("notification_count:")
else:
# delete count for user
for key in frappe.cache().get_keys("notification_count:"):
frappe.cache().hdel(key, user)


def delete_notification_count_for(doctype): def delete_notification_count_for(doctype):
frappe.cache().delete_keys("notification_count:*:" + doctype)
frappe.cache().delete_key("notification_count:" + doctype)


def clear_doctype_notifications(doc, method=None, *args, **kwargs): def clear_doctype_notifications(doc, method=None, *args, **kwargs):
config = get_notification_config() config = get_notification_config()
@@ -127,10 +132,13 @@ def get_notification_info_for_boot():
return out return out


def get_notification_config(): def get_notification_config():
config = frappe._dict()
for notification_config in frappe.get_hooks().notification_config:
nc = frappe.get_attr(notification_config)()
for key in ("for_doctype", "for_module", "for_module_doctypes"):
config.setdefault(key, {})
config[key].update(nc.get(key, {}))
return config
def _get():
config = frappe._dict()
for notification_config in frappe.get_hooks().notification_config:
nc = frappe.get_attr(notification_config)()
for key in ("for_doctype", "for_module", "for_module_doctypes"):
config.setdefault(key, {})
config[key].update(nc.get(key, {}))
return config

return frappe.cache().get_value("notification_config", _get)

+ 2
- 1
frappe/model/document.py View File

@@ -568,7 +568,8 @@ class Document(BaseDocument):
elif self._action=="update_after_submit": elif self._action=="update_after_submit":
self.run_method("on_update_after_submit") self.run_method("on_update_after_submit")


frappe.cache().set_value("last_modified:" + self.doctype, self.modified)
frappe.cache().hdel("last_modified", self.doctype)

self.latest = None self.latest = None


def check_no_back_links_exist(self): def check_no_back_links_exist(self):


+ 31
- 28
frappe/model/meta.py View File

@@ -11,16 +11,15 @@ from frappe.model.document import Document
from frappe.model.base_document import BaseDocument from frappe.model.base_document import BaseDocument
from frappe.model.db_schema import type_map from frappe.model.db_schema import type_map


######

def get_meta(doctype, cached=True): def get_meta(doctype, cached=True):
if cached: if cached:
return frappe.cache().get_value("meta:" + doctype, lambda: Meta(doctype))
return frappe.cache().hget("meta", doctype, lambda: Meta(doctype))
else: else:
return Meta(doctype) return Meta(doctype)


def get_table_columns(doctype): def get_table_columns(doctype):
return frappe.cache().get_value("table_columns:" + doctype, lambda: frappe.db.get_table_columns(doctype))
return frappe.cache().hget("table_columns", doctype,
lambda: frappe.db.get_table_columns(doctype))


def load_doctype_from_file(doctype): def load_doctype_from_file(doctype):
fname = frappe.scrub(doctype) fname = frappe.scrub(doctype)
@@ -294,30 +293,6 @@ def get_field_precision(df, doc=None, currency=None):


return precision return precision


def clear_cache(doctype=None):
prefixes = ["meta", "form_meta", "table_columns"]
def clear_single(dt):
for p in prefixes:
frappe.cache().delete_value(p + ":" + dt)

if doctype:
clear_single(doctype)

# clear all parent doctypes
for dt in frappe.db.sql("""select parent from tabDocField
where fieldtype="Table" and options=%s""", (doctype,)):
clear_single(dt[0])

# clear all notifications
from frappe.desk.notifications import delete_notification_count_for
delete_notification_count_for(doctype)

else:
# clear all
for p in prefixes:
frappe.cache().delete_keys(p + ":")

frappe.cache().delete_value("is_table")


def get_default_df(fieldname): def get_default_df(fieldname):
if fieldname in default_fields: if fieldname in default_fields:
@@ -347,3 +322,31 @@ def trim_tables():
query = """alter table `tab{doctype}` {columns}""".format( query = """alter table `tab{doctype}` {columns}""".format(
doctype=doctype, columns=columns_to_remove) doctype=doctype, columns=columns_to_remove)
frappe.db.sql_ddl(query) frappe.db.sql_ddl(query)

def clear_cache(doctype=None):
frappe.cache().delete_value("is_table")
frappe.cache().delete_value("doctype_modules")

groups = ["meta", "form_meta", "table_columns", "last_modified"]

def clear_single(dt):
for name in groups:
frappe.cache().hdel(name, dt)

if doctype:
clear_single(doctype)

# clear all parent doctypes
for dt in frappe.db.sql("""select parent from tabDocField
where fieldtype="Table" and options=%s""", (doctype,)):
clear_single(dt[0])

# clear all notifications
from frappe.desk.notifications import delete_notification_count_for
delete_notification_count_for(doctype)

else:
# clear all
for name in groups:
frappe.cache().delete_value(name)


+ 3
- 1
frappe/modules/__init__.py View File

@@ -46,7 +46,9 @@ def export_doc(doctype, name, module=None):


def get_doctype_module(doctype): def get_doctype_module(doctype):
"""Returns **Module Def** name of given doctype.""" """Returns **Module Def** name of given doctype."""
return frappe.db.get_value('DocType', doctype, 'module') or "core"
def make_modules_dict():
return dict(frappe.db.sql("select name, module from tabDocType"))
return frappe.cache().get_value("doctype_modules", make_modules_dict)[doctype]


doctype_python_modules = {} doctype_python_modules = {}
def load_doctype_module(doctype, module=None, prefix=""): def load_doctype_module(doctype, module=None, prefix=""):


+ 19
- 14
frappe/sessions.py View File

@@ -30,19 +30,23 @@ def clear(user=None):
def clear_cache(user=None): def clear_cache(user=None):
cache = frappe.cache() cache = frappe.cache()


groups = ("bootinfo", "user_recent", "user_roles", "user_doc", "lang", "time_zone")

if user: if user:
for name in groups:
cache.hdel(name, user)
cache.delete_keys("user:" + user) cache.delete_keys("user:" + user)
cache.delete_keys("user_doc:" + user)
frappe.defaults.clear_cache(user) frappe.defaults.clear_cache(user)
else: else:
cache.delete_keys("user:")
cache.delete_keys("user_doc:")
for name in groups:
cache.delete_key(name, user)
clear_global_cache() clear_global_cache()
frappe.defaults.clear_cache() frappe.defaults.clear_cache()


def clear_global_cache(): def clear_global_cache():
frappe.model.meta.clear_cache() frappe.model.meta.clear_cache()
frappe.cache().delete_value(["app_hooks", "installed_apps", "app_modules", "module_app", "time_zone"])
frappe.cache().delete_value(["app_hooks", "installed_apps",
"app_modules", "module_app", "time_zone", "notification_config"])
frappe.setup_module_map() frappe.setup_module_map()


def clear_sessions(user=None, keep_current=False): def clear_sessions(user=None, keep_current=False):
@@ -58,8 +62,8 @@ def clear_sessions(user=None, keep_current=False):
def delete_session(sid=None, user=None): def delete_session(sid=None, user=None):
if not user: if not user:
user = hasattr(frappe.local, "session") and frappe.session.user or "Guest" user = hasattr(frappe.local, "session") and frappe.session.user or "Guest"
frappe.cache().delete_value("session:" + sid, user=user)
frappe.cache().delete_value("last_db_session_update:" + sid)
frappe.cache().hdel("session", sid)
frappe.cache().hdel("last_db_session_update", sid)
frappe.db.sql("""delete from tabSessions where sid=%s""", sid) frappe.db.sql("""delete from tabSessions where sid=%s""", sid)


def clear_all_sessions(): def clear_all_sessions():
@@ -83,17 +87,18 @@ def get():
bootinfo = None bootinfo = None
if not getattr(frappe.conf,'disable_session_cache', None): if not getattr(frappe.conf,'disable_session_cache', None):
# check if cache exists # check if cache exists
bootinfo = frappe.cache().get_value("bootinfo", user=True)
bootinfo = frappe.cache().hget("bootinfo", frappe.session.user)
if bootinfo: if bootinfo:
bootinfo['from_cache'] = 1 bootinfo['from_cache'] = 1
bootinfo["notification_info"].update(get_notifications()) bootinfo["notification_info"].update(get_notifications())
bootinfo["user"]["recent"] = json.dumps(frappe.cache().get_value("recent:" + frappe.session.user))
bootinfo["user"]["recent"] = json.dumps(\
frappe.cache().hget("user_recent", frappe.session.user))


if not bootinfo: if not bootinfo:
# if not create it # if not create it
bootinfo = get_bootinfo() bootinfo = get_bootinfo()
bootinfo["notification_info"] = get_notification_info_for_boot() bootinfo["notification_info"] = get_notification_info_for_boot()
frappe.cache().set_value("bootinfo", bootinfo, user=True)
frappe.cache().hset("bootinfo", frappe.session.user, bootinfo)
try: try:
frappe.cache().ping() frappe.cache().ping()
except redis.exceptions.ConnectionError: except redis.exceptions.ConnectionError:
@@ -168,7 +173,7 @@ class Session:
(str(self.data['data']), self.data['user'], self.data['sid'])) (str(self.data['data']), self.data['user'], self.data['sid']))


# also add to memcache # also add to memcache
frappe.cache().set_value("session:" + self.data.sid, self.data, user=self.user)
frappe.cache().hset("session", self.data.sid, self.data)


def resume(self): def resume(self):
"""non-login request: load a session""" """non-login request: load a session"""
@@ -206,7 +211,7 @@ class Session:
return data return data


def get_session_data_from_cache(self): def get_session_data_from_cache(self):
data = frappe._dict(frappe.cache().get_value("session:" + self.sid, user=self.user) or {})
data = frappe._dict(frappe.cache().hget("session", self.sid) or {})
if data: if data:
session_data = data.get("data", {}) session_data = data.get("data", {})
self.time_diff = frappe.utils.time_diff_in_seconds(frappe.utils.now(), self.time_diff = frappe.utils.time_diff_in_seconds(frappe.utils.now(),
@@ -257,7 +262,7 @@ class Session:
self.data['data']['lang'] = unicode(frappe.lang) self.data['data']['lang'] = unicode(frappe.lang)


# update session in db # update session in db
last_updated = frappe.cache().get_value("last_db_session_update:" + self.sid)
last_updated = frappe.cache().hget("last_db_session_update", self.sid)
time_diff = frappe.utils.time_diff_in_seconds(now, last_updated) if last_updated else None time_diff = frappe.utils.time_diff_in_seconds(now, last_updated) if last_updated else None


# database persistence is secondary, don't update it too often # database persistence is secondary, don't update it too often
@@ -267,11 +272,11 @@ class Session:
lastupdate=NOW() where sid=%s""" , (str(self.data['data']), lastupdate=NOW() where sid=%s""" , (str(self.data['data']),
self.data['sid'])) self.data['sid']))


frappe.cache().set_value("last_db_session_update:" + self.sid, now)
frappe.cache().hset("last_db_session_update", self.sid, now)
updated_in_db = True updated_in_db = True


# set in memcache # set in memcache
frappe.cache().set_value("session:" + self.sid, self.data, user=self.user)
frappe.cache().hset("session", self.sid, self.data)


return updated_in_db return updated_in_db




+ 8
- 8
frappe/tests/test_translation.py View File

@@ -15,7 +15,7 @@ import frappe.translate
# if not messages: # if not messages:
# messages = frappe.translate.get_messages_from_page("finder") # messages = frappe.translate.get_messages_from_page("finder")
# self.assertTrue("Finder" in messages) # self.assertTrue("Finder" in messages)
#
#
# def test_report(self, messages=None): # def test_report(self, messages=None):
# if not messages: # if not messages:
# messages = frappe.translate.get_messages_from_report("ToDo") # messages = frappe.translate.get_messages_from_report("ToDo")
@@ -25,13 +25,13 @@ import frappe.translate
# if not messages: # if not messages:
# messages = frappe.translate.get_messages_from_include_files("frappe") # messages = frappe.translate.get_messages_from_include_files("frappe")
# self.assertTrue("History" in messages) # self.assertTrue("History" in messages)
#
#
# def test_server(self, messages=None): # def test_server(self, messages=None):
# if not messages: # if not messages:
# messages = frappe.translate.get_server_messages("frappe") # messages = frappe.translate.get_server_messages("frappe")
# self.assertTrue("Login" in messages) # self.assertTrue("Login" in messages)
# self.assertTrue("Did not save" in messages) # self.assertTrue("Did not save" in messages)
#
#
# def test_all_app(self): # def test_all_app(self):
# messages = frappe.translate.get_messages_for_app("frappe") # messages = frappe.translate.get_messages_for_app("frappe")
# self.test_doctype(messages) # self.test_doctype(messages)
@@ -39,14 +39,14 @@ import frappe.translate
# self.test_report(messages) # self.test_report(messages)
# self.test_include_js(messages) # self.test_include_js(messages)
# self.test_server(messages) # self.test_server(messages)
#
#
# def test_load_translations(self): # def test_load_translations(self):
# frappe.translate.clear_cache() # frappe.translate.clear_cache()
# self.assertFalse(frappe.cache().get_value("lang:de"))
#
# self.assertFalse(frappe.cache().hget("lang_full_dict", "de"))
#
# langdict = frappe.translate.get_full_dict("de") # langdict = frappe.translate.get_full_dict("de")
# self.assertEquals(langdict['Row'], 'Reihe') # self.assertEquals(langdict['Row'], 'Reihe')
#
#
# def test_write_csv(self): # def test_write_csv(self):
# tpath = frappe.get_pymodule_path("frappe", "translations", "de.csv") # tpath = frappe.get_pymodule_path("frappe", "translations", "de.csv")
# if os.path.exists(tpath): # if os.path.exists(tpath):
@@ -54,7 +54,7 @@ import frappe.translate
# frappe.translate.write_translations_file("frappe", "de") # frappe.translate.write_translations_file("frappe", "de")
# self.assertTrue(os.path.exists(tpath)) # self.assertTrue(os.path.exists(tpath))
# self.assertEquals(dict(frappe.translate.read_csv_file(tpath)).get("Row"), "Reihe") # self.assertEquals(dict(frappe.translate.read_csv_file(tpath)).get("Row"), "Reihe")
#
#
# def test_get_dict(self): # def test_get_dict(self):
# frappe.local.lang = "de" # frappe.local.lang = "de"
# self.assertEquals(frappe.get_lang_dict("doctype", "Role").get("Role"), "Rolle") # self.assertEquals(frappe.get_lang_dict("doctype", "Role").get("Role"), "Rolle")


+ 9
- 10
frappe/translate.py View File

@@ -44,7 +44,7 @@ def get_user_lang(user=None):
user = frappe.session.user user = frappe.session.user


# via cache # via cache
lang = frappe.cache().get_value("lang", user=user)
lang = frappe.cache().hget("lang", user)


if not lang: if not lang:


@@ -56,7 +56,7 @@ def get_user_lang(user=None):
default_lang = frappe.db.get_default("lang") default_lang = frappe.db.get_default("lang")
lang = default_lang or frappe.local.lang lang = default_lang or frappe.local.lang


frappe.cache().set_value("lang", lang or "en", user=user)
frappe.cache().hset("lang", user, lang or "en")


return lang return lang


@@ -90,9 +90,8 @@ def get_dict(fortype, name=None):
""" """
fortype = fortype.lower() fortype = fortype.lower()
cache = frappe.cache() cache = frappe.cache()
cache_key = "translation_assets:" + (frappe.local.lang or "en")
asset_key = fortype + ":" + (name or "-") asset_key = fortype + ":" + (name or "-")
translation_assets = cache.get_value(cache_key) or {}
translation_assets = cache.hget("translation_assets", frappe.local.lang) or {}


if not asset_key in translation_assets: if not asset_key in translation_assets:
if fortype=="doctype": if fortype=="doctype":
@@ -114,7 +113,7 @@ def get_dict(fortype, name=None):
translation_assets[asset_key] = make_dict_from_messages(messages) translation_assets[asset_key] = make_dict_from_messages(messages)
translation_assets[asset_key].update(get_dict_from_hooks(fortype, name)) translation_assets[asset_key].update(get_dict_from_hooks(fortype, name))


cache.set_value(cache_key, translation_assets)
cache.hset("translation_assets", frappe.local.lang, translation_assets)


return translation_assets[asset_key] return translation_assets[asset_key]


@@ -170,10 +169,10 @@ def get_full_dict(lang):
return {} return {}


if not frappe.local.lang_full_dict: if not frappe.local.lang_full_dict:
frappe.local.lang_full_dict = frappe.cache().get_value("lang:" + lang)
frappe.local.lang_full_dict = frappe.cache().hget("lang_full_dict", lang)
if not frappe.local.lang_full_dict: if not frappe.local.lang_full_dict:
# cache lang # cache lang
frappe.cache().set_value("lang:" + lang, frappe.local.lang_full_dict)
frappe.cache().hset("lang_full_dict", lang, frappe.local.lang_full_dict)
frappe.local.lang_full_dict = load_lang(lang) frappe.local.lang_full_dict = load_lang(lang)


return frappe.local.lang_full_dict return frappe.local.lang_full_dict
@@ -196,9 +195,9 @@ def load_lang(lang, apps=None):
def clear_cache(): def clear_cache():
"""Clear all translation assets from :meth:`frappe.cache`""" """Clear all translation assets from :meth:`frappe.cache`"""
cache = frappe.cache() cache = frappe.cache()
cache.delete_value("langinfo")
cache.delete_keys("lang:")
cache.delete_keys("translation_assets:")
cache.delete_key("langinfo")
cache.delete_key("lang_full_dict")
cache.delete_key("translation_assets")


def get_messages_for_app(app): def get_messages_for_app(app):
"""Returns all messages (list) for a specified `app`""" """Returns all messages (list) for a specified `app`"""


+ 1
- 8
frappe/utils/data.py View File

@@ -115,14 +115,7 @@ def get_user_time_zone():
if frappe.local.flags.in_test: if frappe.local.flags.in_test:
return _get_user_time_zone() return _get_user_time_zone()


if getattr(frappe.local, "user_time_zone", None) is None:
frappe.local.user_time_zone = frappe.cache().get_value("time_zone")

if not frappe.local.user_time_zone:
frappe.local.user_time_zone = _get_user_time_zone()
frappe.cache().set_value("time_zone", frappe.local.user_time_zone, user=frappe.session.user)

return frappe.local.user_time_zone
return frappe.cache().hget("time_zone", frappe.session.user, _get_user_time_zone)


def convert_utc_to_user_timezone(utc_timestamp): def convert_utc_to_user_timezone(utc_timestamp):
from pytz import timezone, UnknownTimeZoneError from pytz import timezone, UnknownTimeZoneError


+ 42
- 16
frappe/utils/redis_wrapper.py View File

@@ -2,7 +2,8 @@
# MIT License. See license.txt # MIT License. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals


import redis, frappe, pickle, re
import redis, frappe, re
import cPickle as pickle
from frappe.utils import cstr from frappe.utils import cstr


class RedisWrapper(redis.Redis): class RedisWrapper(redis.Redis):
@@ -14,15 +15,12 @@ class RedisWrapper(redis.Redis):


key = "user:{0}:{1}".format(user, key) key = "user:{0}:{1}".format(user, key)


return (frappe.conf.db_name + "|" + key).encode('utf-8')
return "{0}|{1}".format(frappe.conf.db_name, key).encode('utf-8')


def set_value(self, key, val, user=None): def set_value(self, key, val, user=None):
"""Sets cache value.""" """Sets cache value."""
key = self.make_key(key, user) key = self.make_key(key, user)
frappe.local.cache[key] = val frappe.local.cache[key] = val
if frappe.local.flags.in_install or frappe.local.flags.in_install_db:
return

try: try:
self.set(key, pickle.dumps(val)) self.set(key, pickle.dumps(val))
except redis.exceptions.ConnectionError: except redis.exceptions.ConnectionError:
@@ -39,11 +37,10 @@ class RedisWrapper(redis.Redis):


if key not in frappe.local.cache: if key not in frappe.local.cache:
val = None val = None
if not frappe.local.flags.in_install and not frappe.local.flags.in_install_db:
try:
val = self.get(key)
except redis.exceptions.ConnectionError:
pass
try:
val = self.get(key)
except redis.exceptions.ConnectionError:
pass
if val is not None: if val is not None:
val = pickle.loads(val) val = pickle.loads(val)
if val is None and generator: if val is None and generator:
@@ -78,6 +75,9 @@ class RedisWrapper(redis.Redis):
except redis.exceptions.ConnectionError: except redis.exceptions.ConnectionError:
pass pass


def delete_key(self, *args, **kwargs):
self.delete_value(*args, **kwargs)

def delete_value(self, keys, user=None, make_keys=True): def delete_value(self, keys, user=None, make_keys=True):
"""Delete value, list of values.""" """Delete value, list of values."""
if not isinstance(keys, (list, tuple)): if not isinstance(keys, (list, tuple)):
@@ -87,12 +87,38 @@ class RedisWrapper(redis.Redis):
if make_keys: if make_keys:
key = self.make_key(key) key = self.make_key(key)



if not frappe.local.flags.in_install and not frappe.local.flags.in_install_db:
try:
self.delete(key)
except redis.exceptions.ConnectionError:
pass
try:
self.delete(key)
except redis.exceptions.ConnectionError:
pass


if key in frappe.local.cache: if key in frappe.local.cache:
del frappe.local.cache[key] del frappe.local.cache[key]

def hset(self, name, key, value):
if not name in frappe.local.cache:
frappe.local.cache[name] = {}
frappe.local.cache[name][key] = value
super(redis.Redis, self).hset(self.make_key(name), key, pickle.dumps(value))

def hget(self, name, key, generator=None):
if not name in frappe.local.cache:
frappe.local.cache[name] = {}
if key in frappe.local.cache[name]:
return frappe.local.cache[name][key]
value = super(redis.Redis, self).hget(self.make_key(name), key)
if value:
value = pickle.loads(value)
frappe.local.cache[name][key] = value
elif generator:
value = generator()
self.hset(name, key, value)
return value

def hdel(self, name, keys):
if name in frappe.local.cache:
del frappe.local.cache[name]
return super(redis.Redis, self).hget(self.make_key(name), keys)

def hkeys(self, name):
return super(redis.Redis, self).hkeys(self.make_key(name))

+ 8
- 8
frappe/utils/user.py View File

@@ -47,7 +47,7 @@ class User:
return user return user


if not frappe.flags.in_install_db and not frappe.flags.in_test: if not frappe.flags.in_install_db and not frappe.flags.in_test:
user_doc = frappe.cache().get_value("user_doc:" + self.name, get_user_doc)
user_doc = frappe.cache().hget("user_doc", self.name, get_user_doc)
if user_doc: if user_doc:
self.doc = frappe.get_doc(user_doc) self.doc = frappe.get_doc(user_doc)


@@ -156,7 +156,7 @@ class User:


# update recent documents # update recent documents
def update_recent(self, dt, dn): def update_recent(self, dt, dn):
rdl = frappe.cache().get_value("recent:" + self.name) or []
rdl = frappe.cache().hget("user_recent", self.name) or []
new_rd = [dt, dn] new_rd = [dt, dn]


# clear if exists # clear if exists
@@ -171,7 +171,7 @@ class User:


rdl = [new_rd] + rdl rdl = [new_rd] + rdl


frappe.cache().set_value("recent:" + self.name, rdl)
frappe.cache().hset("user_recent", self.name, rdl)


def _get(self, key): def _get(self, key):
if not self.can_read: if not self.can_read:
@@ -193,7 +193,7 @@ class User:
self.build_permissions() self.build_permissions()


d.name = self.name d.name = self.name
d.recent = json.dumps(frappe.cache().get_value("recent:" + self.name) or [])
d.recent = json.dumps(frappe.cache().hget("user_recent", self.name) or [])


d.roles = self.get_roles() d.roles = self.get_roles()
d.defaults = self.get_defaults() d.defaults = self.get_defaults()
@@ -267,11 +267,11 @@ def get_roles(user=None, with_standard=True):
if user=='Guest': if user=='Guest':
return ['Guest'] return ['Guest']


roles = frappe.cache().get_value("roles", user=user)
if not roles:
roles = [r[0] for r in frappe.db.sql("""select role from tabUserRole
def get():
return [r[0] for r in frappe.db.sql("""select role from tabUserRole
where parent=%s and role not in ('All', 'Guest')""", (user,))] + ['All', 'Guest'] where parent=%s and role not in ('All', 'Guest')""", (user,))] + ['All', 'Guest']
frappe.cache().set_value("roles", roles, user=user)

roles = frappe.cache().hget("roles", user, get)


# filter standard if required # filter standard if required
if not with_standard: if not with_standard:


+ 6
- 4
frappe/website/context.py View File

@@ -11,7 +11,7 @@ from frappe.website.utils import can_cache


def get_context(path): def get_context(path):
context = None context = None
cache_key = "page_context:{0}:{1}".format(path, frappe.local.lang)
context_cache = {}


def add_data_path(context): def add_data_path(context):
if not context.data: if not context.data:
@@ -19,9 +19,10 @@ def get_context(path):


context.data["path"] = path context.data["path"] = path


# try from memcache
# try from cache
if can_cache(): if can_cache():
context = frappe.cache().get_value(cache_key)
context_cache = frappe.cache().hget("page_context", path) or {}
context = context_cache.get(frappe.local.lang, None)


if not context: if not context:
context = get_route_info(path) context = get_route_info(path)
@@ -30,7 +31,8 @@ def get_context(path):
add_data_path(context) add_data_path(context)


if can_cache(context.no_cache): if can_cache(context.no_cache):
frappe.cache().set_value(cache_key, context)
context_cache[frappe.local.lang] = context
frappe.cache().hset("page_context", path, context_cache)


else: else:
add_data_path(context) add_data_path(context)


+ 13
- 7
frappe/website/render.py View File

@@ -99,15 +99,19 @@ def build_response(path, data, http_status_code, headers=None):


def render_page(path): def render_page(path):
"""get page html""" """get page html"""
cache_key = ("page_context:{0}:{1}" if is_ajax() else "page:{0}:{1}").format(path, frappe.local.lang)

out = None out = None


# try cache
if can_cache(): if can_cache():
out = frappe.cache().get_value(cache_key)
if out and is_ajax():
out = out.get("data")
if is_ajax():
# ajax, send context
context_cache = frappe.cache().hget("page_context", path)
if context_cache and frappe.local.lang in context_cache:
out = context_cache[frappe.local.lang].get("data")
else:
# return rendered page
page_cache = frappe.cache().hget("website_page", path)
if page_cache and frappe.local.lang in page_cache:
out = page_cache[frappe.local.lang]


if out: if out:
frappe.local.response.from_cache = True frappe.local.response.from_cache = True
@@ -143,7 +147,9 @@ def build_page(path):
html = frappe.get_template(context.base_template_path).render(context) html = frappe.get_template(context.base_template_path).render(context)


if can_cache(context.no_cache): if can_cache(context.no_cache):
frappe.cache().set_value("page:{0}:{1}".format(path, frappe.local.lang), html)
page_cache = frappe.cache().hget("website_page", path) or {}
page_cache[frappe.local.lang] = html
frappe.cache().hset("website_page", path, page_cache)


return html return html




+ 4
- 2
frappe/website/router.py View File

@@ -12,12 +12,14 @@ def get_route_info(path):
cache_key = "sitemap_options:{0}:{1}".format(path, frappe.local.lang) cache_key = "sitemap_options:{0}:{1}".format(path, frappe.local.lang)


if can_cache(): if can_cache():
sitemap_options = frappe.cache().get_value(cache_key)
sitemap_options_cache = frappe.cache().hget("sitemap_options", path) or {}
sitemap_options = sitemap_options_cache.get(frappe.local.lang, None)


if not sitemap_options: if not sitemap_options:
sitemap_options = build_route(path) sitemap_options = build_route(path)
if can_cache(sitemap_options.no_cache): if can_cache(sitemap_options.no_cache):
frappe.cache().set_value(cache_key, sitemap_options)
sitemap_options_cache[frappe.local.lang] = sitemap_options
frappe.cache().hset("sitemap_options", path, sitemap_options_cache)


return sitemap_options return sitemap_options




+ 8
- 6
frappe/website/utils.py View File

@@ -5,12 +5,14 @@ from __future__ import unicode_literals
import frappe, re, os import frappe, re, os


def delete_page_cache(path): def delete_page_cache(path):
if not path:
path = ""
cache = frappe.cache() cache = frappe.cache()
cache.delete_keys("page:" + path)
cache.delete_keys("page_context:" + path)
cache.delete_keys("sitemap_options:" + path)
groups = ("page_context", "website_page", "sitemap_options")
if path:
for name in groups:
cache.hdel(name, path)
else:
for name in groups:
cache.delete_key(name)


def find_first_image(html): def find_first_image(html):
m = re.finditer("""<img[^>]*src\s?=\s?['"]([^'"]*)['"]""", html) m = re.finditer("""<img[^>]*src\s?=\s?['"]([^'"]*)['"]""", html)
@@ -49,7 +51,7 @@ def get_home_page():


return home_page return home_page


return frappe.cache().get_value("home_page", _get_home_page, user=True)
return frappe.cache().hget("home_page", frappe.session.user, _get_home_page)


def is_signup_enabled(): def is_signup_enabled():
if getattr(frappe.local, "is_signup_enabled", None) is None: if getattr(frappe.local, "is_signup_enabled", None) is None:


Loading…
Cancel
Save