<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def cleanCache(self, newJobReqs):
 """ Cleanup all files in the cache directory to ensure that at lead newJobReqs are available for use. :param float newJobReqs: the total number of bytes of files allowed in the cache. """

        with self._CacheState.open(self) as cacheInfo:
            # Add the new job's disk requirements to the sigmaJobDisk variable
            cacheInfo.sigmaJob += newJobReqs
            # Initialize the job state here. we use a partial in the jobSpecificFiles call so
            # that this entire thing is pickleable. Based on answer by user Nathaniel Gentile at
            # http://stackoverflow.com/questions/2600790
            assert self.jobID not in cacheInfo.jobState
            cacheInfo.jobState[self.jobID] = {
                'jobName': self.jobName,
                'jobReqs': newJobReqs,
                'jobDir': self.localTempDir,
                'jobSpecificFiles': defaultdict(partial(defaultdict,int)),
                'filesToFSIDs': defaultdict(set),
                'pid': os.getpid(),
                'deferredFunctions': []}
            # If the caching equation is balanced, do nothing.
            if cacheInfo.isBalanced():
                return None

            # List of deletable cached files.  A deletable cache file is one
            #  that is not in use by any other worker (identified by the number of symlinks to
            # the file)
            allCacheFiles = [os.path.join(self.localCacheDir, x)
                             for x in os.listdir(self.localCacheDir)
                             if not self._isHidden(x)]
            allCacheFiles = [(path, os.stat(path)) for path in allCacheFiles]
            # TODO mtime vs ctime
            deletableCacheFiles = {(path, inode.st_mtime, inode.st_size)
                                   for path, inode in allCacheFiles
                                   if inode.st_nlink == self.nlinkThreshold}

            # Sort in descending order of mtime so the first items to be popped from the list
            # are the least recently created.
            deletableCacheFiles = sorted(deletableCacheFiles, key=lambda x: (-x[1], -x[2]))
            logger.debug('CACHE: Need %s bytes for new job. Detecting an estimated %s (out of a '
                         'total %s) bytes available for running the new job. The size of the cache '
                         'is %s bytes.', newJobReqs,
                         (cacheInfo.total - (cacheInfo.cached + cacheInfo.sigmaJob - newJobReqs)),
                         cacheInfo.total, cacheInfo.cached)
            logger.debug('CACHE: Evicting files to make room for the new job.')

            # Now do the actual file removal
            totalEvicted = 0
            while not cacheInfo.isBalanced() and len(deletableCacheFiles) > 0:
                cachedFile, fileCreateTime, cachedFileSize = deletableCacheFiles.pop()
                os.remove(cachedFile)
                cacheInfo.cached -= cachedFileSize if self.nlinkThreshold != 2 else 0
                totalEvicted += cachedFileSize
                assert cacheInfo.cached >= 0
                logger.debug('CACHE: Evicted  file with ID \'%s\' (%s bytes)' %
                             (self.decodedFileID(cachedFile), cachedFileSize))
            logger.debug('CACHE: Evicted a total of %s bytes. Available space is now %s bytes.',
                         totalEvicted,
                         (cacheInfo.total - (cacheInfo.cached + cacheInfo.sigmaJob - newJobReqs)))
            if not cacheInfo.isBalanced():
                raise CacheUnbalancedError()