NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

cacheDirectoryLimitSvc.py (5135B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\client\script\util\cacheDirectoryLimitSvc.py
      2 import datetime
      3 import os
      4 import stat
      5 import blue
      6 import telemetry
      7 import threading
      8 import uthread
      9 from carbon.common.script.sys.service import Service
     10 from carbon.common.script.sys.serviceConst import ROLE_ANY
     11 from watchdog.events import FileSystemEventHandler
     12 from watchdog.observers import Observer
     13 
     14 class AutoPrunedDirectory(object):
     15 
     16     def __init__(self, directory, maxDirectorySizeInMB, maxAgeInDays = None):
     17         self.directory = directory
     18         self.maxDirectorySizeInMB = maxDirectorySizeInMB
     19         self.maxAgeInDays = maxAgeInDays
     20         self.currentSize = 0
     21         self.lastChecked = None
     22 
     23 
     24 @telemetry.ZONE_FUNCTION
     25 def ProcessCacheDirectory(cacheSvc, rootPath, d):
     26     filesInDirectory = []
     27     now = datetime.datetime.now()
     28     five_minutes = datetime.timedelta(minutes=5)
     29     max_age = None if d.maxAgeInDays is None else datetime.timedelta(days=d.maxAgeInDays)
     30     if d.lastChecked is not None:
     31         if now - d.lastChecked < five_minutes:
     32             return
     33     d.lastChecked = now
     34     d.currentSize = 0
     35     for r, _, files in os.walk(rootPath):
     36         for f in files:
     37             fullpath = os.path.join(r, f)
     38             fileSize = os.stat(fullpath)[stat.ST_SIZE]
     39             lastAccessed = datetime.datetime.fromtimestamp(os.path.getmtime(fullpath))
     40             if max_age is not None and now - lastAccessed > max_age:
     41                 cacheSvc.LogInfo('Removing %s from cache. It was last accessed: %s' % (fullpath, lastAccessed))
     42                 try:
     43                     os.remove(fullpath)
     44                 except OSError:
     45                     continue
     46 
     47             else:
     48                 d.currentSize += fileSize
     49                 filesInDirectory.append((lastAccessed, fileSize, fullpath))
     50 
     51     currentSize = d.currentSize
     52     maxSize = d.maxDirectorySizeInMB * 1024 * 1024
     53     if currentSize > maxSize:
     54         cacheSvc.LogNotice('Cache Directory %s is over the allocated file size (%sMB, currently %sMB)' % (d.directory, d.maxDirectorySizeInMB, currentSize / 1048576.0))
     55         filesInDirectory.sort(reverse=True)
     56         while currentSize > maxSize:
     57             fileToDelete = filesInDirectory.pop()
     58             if now - fileToDelete[0] < five_minutes:
     59                 break
     60             cacheSvc.LogInfo('Removing %s from cache. It was last accessed: %s' % (fileToDelete[2], fileToDelete[0]))
     61             try:
     62                 os.remove(fileToDelete[2])
     63                 currentSize -= fileToDelete[1]
     64             except OSError:
     65                 continue
     66 
     67     else:
     68         cacheSvc.LogInfo('Cache Directory %s is currently %sMB (max %sMB)' % (d.directory, currentSize / 1048576.0, d.maxDirectorySizeInMB))
     69 
     70 
     71 class FileHandler(FileSystemEventHandler):
     72 
     73     def __init__(self, cacheSvc, rootPath, dirInfo):
     74         self.cacheSvc = cacheSvc
     75         self.rootPath = rootPath
     76         self.dirInfo = dirInfo
     77 
     78     def _ProcessDirectoryInThreadClosure(self):
     79         ProcessCacheDirectory(self.cacheSvc, self.rootPath, self.dirInfo)
     80 
     81     def on_any_event(self, event):
     82         now = datetime.datetime.now()
     83         five_minutes = datetime.timedelta(minutes=5)
     84         if self.dirInfo.lastChecked is not None:
     85             if now - self.dirInfo.lastChecked < five_minutes:
     86                 return
     87         thread = threading.Thread(target=self._ProcessDirectoryInThreadClosure)
     88         thread.start()
     89 
     90 
     91 class CacheDirectoryLimitService(Service):
     92     __guid__ = 'svc.cacheDirectoryLimit'
     93     __exportedcalls__ = {'PruneCache': {'role': ROLE_ANY},
     94      'RegisterCacheDirectory': {'role': ROLE_ANY}}
     95 
     96     def __init__(self):
     97         super(CacheDirectoryLimitService, self).__init__()
     98         self.autoPruneDirectories = []
     99         self._observers = []
    100 
    101     def Run(self, *etc):
    102         Service.Run(self, *etc)
    103         self.RegisterCacheDirectory('Avatars', 1024, 5)
    104         self.PruneCache()
    105 
    106     def PruneCache(self):
    107         uthread.new(self._PruneCache_t)
    108 
    109     def _PruneCache_t(self):
    110         cacheDir = blue.paths.ResolvePath(u'cache:/')
    111         for d in self.autoPruneDirectories:
    112             rootPath = os.path.join(cacheDir, d.directory)
    113             uthread.CallOnThread(ProcessCacheDirectory, args=(self, rootPath, d))
    114 
    115     def RegisterCacheDirectory(self, directory, maxSize, maxLastAccessedAgeInDays = None):
    116         for d in self.autoPruneDirectories:
    117             if d.directory == directory:
    118                 d.maxDirectorySizeInMB = maxSize
    119                 d.maxAgeInDays = maxLastAccessedAgeInDays
    120                 return
    121 
    122         cacheDir = blue.paths.ResolvePath(u'cache:/')
    123         rootPath = os.path.join(cacheDir, directory)
    124         d = AutoPrunedDirectory(directory, maxSize, maxLastAccessedAgeInDays)
    125         self.autoPruneDirectories.append(d)
    126         self.LogNotice('Setting up cache directory watch on %s' % rootPath)
    127         observer = Observer()
    128         try:
    129             observer.schedule(FileHandler(self, rootPath, d), rootPath, recursive=True)
    130             observer.start()
    131         except OSError:
    132             return
    133 
    134         self._observers.append(observer)