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

99 lines
2.4KB

  1. #! /usr/bin/env python
  2. # encoding: utf-8
  3. # Thomas Nagy 2011
  4. import os, shutil, re
  5. from waflib import Options, Build, Logs
  6. """
  7. Apply a least recently used policy to the Waf cache.
  8. For performance reasons, it is called after the build is complete.
  9. We assume that the the folders are written atomically
  10. Do export WAFCACHE=/tmp/foo_xyz where xyz represents the cache size in bytes
  11. If missing, the default cache size will be set to 10GB
  12. """
  13. re_num = re.compile('[a-zA-Z_-]+(\d+)')
  14. CACHESIZE = 10*1024*1024*1024 # in bytes
  15. CLEANRATIO = 0.8
  16. DIRSIZE = 4096
  17. def compile(self):
  18. if Options.cache_global and not Options.options.nocache:
  19. try:
  20. os.makedirs(Options.cache_global)
  21. except:
  22. pass
  23. try:
  24. self.raw_compile()
  25. finally:
  26. if Options.cache_global and not Options.options.nocache:
  27. self.sweep()
  28. def sweep(self):
  29. global CACHESIZE
  30. CACHEDIR = Options.cache_global
  31. # get the cache max size from the WAFCACHE filename
  32. re_num = re.compile('[a-zA-Z_]+(\d+)')
  33. val = re_num.sub('\\1', os.path.basename(Options.cache_global))
  34. try:
  35. CACHESIZE = int(val)
  36. except:
  37. pass
  38. # map folder names to timestamps
  39. flist = {}
  40. for x in os.listdir(CACHEDIR):
  41. j = os.path.join(CACHEDIR, x)
  42. if os.path.isdir(j) and len(x) == 64: # dir names are md5 hexdigests
  43. flist[x] = [os.stat(j).st_mtime, 0]
  44. for (x, v) in flist.items():
  45. cnt = DIRSIZE # each entry takes 4kB
  46. d = os.path.join(CACHEDIR, x)
  47. for k in os.listdir(d):
  48. cnt += os.stat(os.path.join(d, k)).st_size
  49. flist[x][1] = cnt
  50. total = sum([x[1] for x in flist.values()])
  51. Logs.debug('lru: Cache size is %r' % total)
  52. if total >= CACHESIZE:
  53. Logs.debug('lru: Trimming the cache since %r > %r' % (total, CACHESIZE))
  54. # make a list to sort the folders by timestamp
  55. lst = [(p, v[0], v[1]) for (p, v) in flist.items()]
  56. lst.sort(key=lambda x: x[1]) # sort by timestamp
  57. lst.reverse()
  58. while total >= CACHESIZE * CLEANRATIO:
  59. (k, t, s) = lst.pop()
  60. p = os.path.join(CACHEDIR, k)
  61. v = p + '.del'
  62. try:
  63. os.rename(p, v)
  64. except:
  65. # someone already did it
  66. pass
  67. else:
  68. try:
  69. shutil.rmtree(v)
  70. except:
  71. # this should not happen, but who knows?
  72. Logs.warn('If you ever see this message, report it (%r)' % v)
  73. total -= s
  74. del flist[k]
  75. Logs.debug('lru: Total at the end %r' % total)
  76. Build.BuildContext.raw_compile = Build.BuildContext.compile
  77. Build.BuildContext.compile = compile
  78. Build.BuildContext.sweep = sweep