You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

persistent_cache.py 4.3 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. # -*- coding: utf-8 -*-
  2. import argparse
  3. import contextlib
  4. import getpass
  5. import os
  6. import sys
  7. import urllib.parse
  8. import filelock
  9. from ..core._imperative_rt import PersistentCache as _PersistentCache
  10. from ..logger import get_logger
  11. from ..version import __version__, git_version
  12. class PersistentCacheOnServer(_PersistentCache):
  13. def __init__(self):
  14. super().__init__()
  15. cache_type = os.getenv("MGE_FASTRUN_CACHE_TYPE")
  16. if cache_type not in ("FILE", "MEMORY"):
  17. try:
  18. redis_config = self.get_redis_config()
  19. except Exception as exc:
  20. get_logger().error(
  21. "failed to connect to cache server {!r}; try fallback to "
  22. "in-file cache".format(exc)
  23. )
  24. else:
  25. if redis_config is not None:
  26. self.add_config(
  27. "redis",
  28. redis_config,
  29. "fastrun use redis cache",
  30. "failed to connect to cache server",
  31. )
  32. if cache_type != "MEMORY":
  33. path = self.get_cache_file(self.get_cache_dir())
  34. self.add_config(
  35. "in-file",
  36. {"path": path},
  37. "fastrun use in-file cache in {}".format(path),
  38. "failed to create cache file in {}".format(path),
  39. )
  40. self.add_config(
  41. "in-memory",
  42. {},
  43. "fastrun use in-memory cache",
  44. "failed to create in-memory cache",
  45. )
  46. def get_cache_dir(self):
  47. cache_dir = os.getenv("MGE_FASTRUN_CACHE_DIR")
  48. if not cache_dir:
  49. from ..hub.hub import _get_megengine_home
  50. cache_dir = os.path.expanduser(
  51. os.path.join(_get_megengine_home(), "persistent_cache")
  52. )
  53. os.makedirs(cache_dir, exist_ok=True)
  54. return cache_dir
  55. def get_cache_file(self, cache_dir):
  56. cache_file = os.path.join(cache_dir, "cache.bin")
  57. with open(cache_file, "a"):
  58. pass
  59. return cache_file
  60. @contextlib.contextmanager
  61. def lock_cache_file(self, cache_dir):
  62. lock_file = os.path.join(cache_dir, "cache.lock")
  63. with filelock.FileLock(lock_file):
  64. yield
  65. def get_redis_config(self):
  66. url = os.getenv("MGE_FASTRUN_CACHE_URL")
  67. if url is None:
  68. return None
  69. assert sys.platform != "win32", "redis cache on windows not tested"
  70. prefix = "mgbcache:{}:MGB{}:GIT:{}::".format(
  71. getpass.getuser(), __version__, git_version
  72. )
  73. parse_result = urllib.parse.urlparse(url)
  74. assert not parse_result.username, "redis conn with username unsupported"
  75. if parse_result.scheme == "redis":
  76. assert parse_result.hostname and parse_result.port, "invalid url"
  77. assert not parse_result.path
  78. config = {
  79. "hostname": parse_result.hostname,
  80. "port": str(parse_result.port),
  81. }
  82. elif parse_result.scheme == "redis+socket":
  83. assert not (parse_result.hostname or parse_result.port)
  84. assert parse_result.path
  85. config = {
  86. "unixsocket": parse_result.path,
  87. }
  88. else:
  89. assert False, "unsupported scheme"
  90. if parse_result.password is not None:
  91. config["password"] = parse_result.password
  92. config["prefix"] = prefix
  93. return config
  94. def flush(self):
  95. if self.config is not None and self.config.type == "in-file":
  96. with self.lock_cache_file(self.get_cache_dir()):
  97. super().flush()
  98. def _clean():
  99. nr_del = PersistentCacheOnServer().clean()
  100. if nr_del is not None:
  101. print("{} cache entries deleted".format(nr_del))
  102. def main():
  103. parser = argparse.ArgumentParser(description="manage persistent cache")
  104. subp = parser.add_subparsers(description="action to be performed", dest="cmd")
  105. subp.required = True
  106. subp_clean = subp.add_parser("clean", help="clean all the cache of current user")
  107. subp_clean.set_defaults(action=_clean)
  108. args = parser.parse_args()
  109. args.action()
  110. if __name__ == "__main__":
  111. main()