Improve cache logic for lookup operations

This commit is contained in:
Ivan Kravets
2015-04-23 14:11:30 +01:00
parent 31a2880c3c
commit 97044bf5a5
3 changed files with 106 additions and 71 deletions

View File

@@ -8,28 +8,24 @@ from time import time
import click import click
from platformio import exception, telemetry from platformio import exception, telemetry, util
from platformio.app import get_state_item, set_state_item from platformio.app import get_state_item, set_state_item
from platformio.downloader import FileDownloader from platformio.downloader import FileDownloader
from platformio.unpacker import FileUnpacker from platformio.unpacker import FileUnpacker
from platformio.util import get_api_result, get_home_dir, get_systype
class PackageManager(object): class PackageManager(object):
def __init__(self): def __init__(self):
self._package_dir = join(get_home_dir(), "packages") self._package_dir = join(util.get_home_dir(), "packages")
if not isdir(self._package_dir): if not isdir(self._package_dir):
makedirs(self._package_dir) makedirs(self._package_dir)
assert isdir(self._package_dir) assert isdir(self._package_dir)
@classmethod @classmethod
@util.memoized
def get_manifest(cls): def get_manifest(cls):
try: return util.get_api_result("/packages/manifest")
return cls._cached_manifest
except AttributeError:
cls._cached_manifest = get_api_result("/packages/manifest")
return cls._cached_manifest
@staticmethod @staticmethod
def download(url, dest_dir, sha1=None): def download(url, dest_dir, sha1=None):
@@ -63,7 +59,7 @@ class PackageManager(object):
raise exception.UnknownPackage(name) raise exception.UnknownPackage(name)
# check system platform # check system platform
systype = get_systype() systype = util.get_systype()
builds = ([b for b in manifest[name] if b['system'] == "all" or systype builds = ([b for b in manifest[name] if b['system'] == "all" or systype
in b['system']]) in b['system']])
if not builds: if not builds:

View File

@@ -132,12 +132,9 @@ class PlatformFactory(object):
return module return module
@classmethod @classmethod
def get_platforms(cls, installed=False): @util.memoized
def _lookup_platforms(cls):
platforms = {} platforms = {}
try:
platforms = cls.get_platforms_cache
except AttributeError:
for d in (util.get_home_dir(), util.get_source_dir()): for d in (util.get_home_dir(), util.get_source_dir()):
pdir = join(d, "platforms") pdir = join(d, "platforms")
if not isdir(pdir): if not isdir(pdir):
@@ -157,7 +154,11 @@ class PlatformFactory(object):
platforms[type_] = path platforms[type_] = path
except exception.UnknownPlatform: except exception.UnknownPlatform:
pass pass
cls.get_platforms_cache = platforms return platforms
@classmethod
def get_platforms(cls, installed=False):
platforms = cls._lookup_platforms()
if not installed: if not installed:
return platforms return platforms

View File

@@ -1,6 +1,8 @@
# Copyright (C) Ivan Kravets <me@ikravets.com> # Copyright (C) Ivan Kravets <me@ikravets.com>
# See LICENSE for details. # See LICENSE for details.
import collections
import functools
import json import json
import os import os
import re import re
@@ -53,6 +55,39 @@ class AsyncPipe(Thread):
self.join() self.join()
class memoized(object):
'''
Decorator. Caches a function's return value each time it is called.
If called later with the same arguments, the cached value is returned
(not reevaluated).
https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize
'''
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
if not isinstance(args, collections.Hashable):
# uncacheable. a list, for instance.
# better to not cache than blow up.
return self.func(*args)
if args in self.cache:
return self.cache[args]
else:
value = self.func(*args)
self.cache[args] = value
return value
def __repr__(self):
'''Return the function's docstring.'''
return self.func.__doc__
def __get__(self, obj, objtype):
'''Support instance methods.'''
return functools.partial(self.__call__, obj)
def get_systype(): def get_systype():
data = uname() data = uname()
return ("%s_%s" % (data[0], data[4])).lower() return ("%s_%s" % (data[0], data[4])).lower()
@@ -239,11 +274,9 @@ def get_api_result(path, params=None, data=None):
return result return result
def get_boards(type_=None): @memoized
def _lookup_boards():
boards = {} boards = {}
try:
boards = get_boards._cache # pylint: disable=W0212
except AttributeError:
bdirs = [join(get_source_dir(), "boards")] bdirs = [join(get_source_dir(), "boards")]
if isdir(join(get_home_dir(), "boards")): if isdir(join(get_home_dir(), "boards")):
bdirs.append(join(get_home_dir(), "boards")) bdirs.append(join(get_home_dir(), "boards"))
@@ -254,7 +287,11 @@ def get_boards(type_=None):
continue continue
with open(join(bdir, json_file)) as f: with open(join(bdir, json_file)) as f:
boards.update(json.load(f)) boards.update(json.load(f))
get_boards._cache = boards # pylint: disable=W0212 return boards
def get_boards(type_=None):
boards = _lookup_boards()
if type_ is None: if type_ is None:
return boards return boards
@@ -264,12 +301,9 @@ def get_boards(type_=None):
return boards[type_] return boards[type_]
def get_frameworks(type_=None): @memoized
def _lookup_frameworks():
frameworks = {} frameworks = {}
try:
frameworks = get_frameworks._cache # pylint: disable=W0212
except AttributeError:
frameworks_path = join( frameworks_path = join(
get_source_dir(), "builder", "scripts", "frameworks") get_source_dir(), "builder", "scripts", "frameworks")
@@ -290,7 +324,11 @@ def get_frameworks(type_=None):
"url": doclines[-1], "url": doclines[-1],
"script": script_path "script": script_path
} }
get_frameworks._cache = frameworks # pylint: disable=W0212 return frameworks
def get_frameworks(type_=None):
frameworks = _lookup_frameworks()
if type_ is None: if type_ is None:
return frameworks return frameworks