Home > atmlab > handy > PersistentCachedData.m

PersistentCachedData

PURPOSE ^

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

DOWNLOAD ^

PersistentCachedData.m

SOURCE CODE ^

0001 classdef PersistentCachedData < CachedData
0002     % like CachedData but stores data on disk
0003     %
0004     % Useful to store large results of big 'read'-commands and so.
0005     % Default disk-stored cache-size is 10 GiB.
0006     %
0007     % !!!WARNING!!!
0008     %
0009     % DO NOT SET A CACHE-DIRECTORY THAT YOU ARE OTHERWISE USING!
0010     % METHODS IN THIS CLASS MIGHT DELETE FILES FROM CACHE-DIRECTORY!
0011     %
0012     % !!!WARNING!!!
0013     
0014     % $Id: PersistentCachedData.m 8901 2014-06-19 08:12:54Z seliasson $
0015     
0016     properties
0017         % maximum size of what's stored on disk. Default 10 GiB.
0018         storedsize   = 10*2^30; % maxStoredSize =  10*2^30;
0019         minFreeSpace = 5*2^30;  % minimun free space you want left over (5GiB)
0020         
0021         % directory to store cache-files
0022         %
0023         % !!!WARNING!!!
0024         %
0025         % DO NOT SET A CACHE-DIRECTORY THAT YOU ARE OTHERWISE USING!
0026         % METHODS IN THIS CLASS MIGHT DELETE FILES FROM CACHE-DIRECTORY!
0027         %
0028         % !!!WARNING!!!
0029 
0030         cachedir;
0031     end
0032     
0033     methods
0034         function self = PersistentCachedData(cachedir)
0035             % pcd = PersistentCachedData(cachedir)
0036             %
0037             % See warning!
0038             self = self@CachedData();
0039             self.cachedir = cachedir;
0040         end
0041         
0042         function data = get_entry(self, s)
0043             % get entry
0044             
0045             % first try to get it from memory
0046             try
0047                 data = get_entry@CachedData(self, s);
0048                 return
0049             catch ME
0050                 switch ME.identifier
0051                     case 'MATLAB:nonExistentField'
0052                         % get from disk instead
0053                     otherwise
0054                         ME.rethrow();
0055                 end
0056             end
0057             ldfl = fullfile(self.cachedir, [s '.mat']);
0058             d = dir(ldfl);
0059             logtext(atmlab('OUT'), 'Reading from persistent cache: %s \n(which was created %s)\n', ldfl, d.date);
0060             
0061 %             % Make the user aware of the age of this file
0062 %             [text] = exec_system_cmd(sprintf('ls -l %s',ldfl));
0063 %             x = textscan(text{1},'%s');
0064 %             % note: this is completely dependent on 'ls -l' being the same on
0065 %             % all systems.
0066 %             logtext(atmlab('OUT'),'Be aware that this read file was originally created: %s\n',sprintf('%s %s %s',x{1}{6},x{1}{7},x{1}{8}))
0067             data = loadvar(ldfl, 'data');
0068         end
0069         
0070         function v = has_entry(self, s)
0071             if has_entry@CachedData(self, s)
0072                 v = 1;
0073             elseif exist(fullfile(self.cachedir, [s '.mat']), 'file')
0074                 v = 2;
0075             else
0076                 v = 0;
0077             end
0078         end
0079         
0080         function set_entry(self, s, data, varargin)
0081             set_entry@CachedData(self, s, data);
0082             info = optargs(varargin, {struct()});
0083             svfl = fullfile(self.cachedir, [s '.mat']);
0084             logtext(atmlab('OUT'), 'Storing cache-entry to disk: %s -> %s\n', ...
0085                 s, svfl);
0086             save(svfl, '-v7.3', 'data');
0087             logtext(atmlab('OUT'), 'New size: %s\n', ...
0088                 nbytes2string(self.disk_cachesize()));
0089             if self.disk_free() + self.disk_cachesize() < self.minFreeSpace
0090                 error(['atmlab:' mfilename ':noSpace'],'df + du = %d + %d < minFreeCache = %d', ...
0091                     self.disk_free(), self.disk_cachesize(), self.minFreeSpace);
0092             end
0093             if self.disk_toolarge()
0094                 self.del_old_disk_entry()
0095             end
0096             % store info. salomon: I'll make the name a bit more unique
0097             % here
0098             infofile = fullfile(self.cachedir, ['info' [datestr(now,'ddmmyy') '-' num2str(cputime)] '.mat']);
0099             if exist(infofile, 'file')
0100                 all_info = loadvar(infofile, 'all_info');
0101             end
0102             all_info.(s) = info;
0103             save(infofile, 'all_info');
0104         end
0105         
0106         function df = disk_free(self)
0107             % get the free space using df (output in bytes)
0108             % stat -f ... %a ... gives no. of blocks available
0109             % stat -f ... %s ... gives block size
0110             if ismac
0111                 sizes = exec_system_cmd(sprintf('df %s |tail -n1|awk ''{print $4*512;}''',self.cachedir));
0112                 df = str2double(sizes{1});
0113             else
0114                 sizes = exec_system_cmd({['stat -f --printf=''%a'' ' self.cachedir], ['stat -f --printf=''%s'' ' self.cachedir]});
0115                 df = (str2double(sizes{1}) * str2double(sizes{2}));
0116             end
0117             %x = exec_system_cmd(sprintf('df -k %s',self.cachedir));
0118             %df = structfun(@str2double,regexp(x{1}(regexp(x{1},'\n'):end),'^[^ ]+ +[0-9]+ +[0-9]+ +(?<bytes>[0-9]+)','names'));
0119             %df = df*1024;
0120         end
0121         
0122         function sz = disk_cachesize(self)
0123             d = dir(self.cachedir);
0124             sz = sum(arrayfun(@(x) x.bytes, d));
0125         end
0126         
0127         function b = disk_toolarge(self)
0128             b = self.disk_cachesize() > self.storedsize || self.disk_free() < self.minFreeSpace;
0129         end
0130         
0131         function del_old_disk_entry(self)
0132             % remove oldest cache-entry on disk. Should contain only
0133             % MAT-files!
0134            
0135             % by default, Matlab issues warnings, not errors, if deletion
0136             % fails. Fortunately, this can be turned into an error with
0137             % this undocumented Matlab code.
0138             % works in 8.0.0.783 (R2012b) and many older versions.
0139             
0140             X1 = warning('error', 'MATLAB:DELETE:DirectoryDeletion');
0141             X2 = warning('error', 'MATLAB:DELETE:FileNotFound');
0142             X3 = warning('error', 'MATLAB:DELETE:Permission');
0143 
0144             d = dir(self.cachedir);
0145             % all but 2 must end in .mat
0146             for i = 1:length(d)
0147                 assert(any(strcmp(d(i).name, {'.', '..'})) || ...
0148                       ((length(d(i).name) >= 4) && strcmp(d(i).name(end-3:end), '.mat')), ...
0149                       ['atmlab:' mfilename ':NotACacheDir'], ...
0150                       ['Not a cache directory: ' self.cachedir]);
0151             end
0152             while self.disk_toolarge()
0153                 d = dir(self.cachedir);
0154                 d = d(~[d.isdir]); % don't include directories
0155                 [~, i] = min(arrayfun(@(x) x.datenum, d));
0156                 % FIXME:
0157                 delete(fullfile(self.cachedir, d(i).name));
0158             end
0159             
0160             % reset warning-config to old state
0161             warning(X1);
0162             warning(X2);
0163             warning(X3);
0164         end
0165     end
0166 end

Generated on Mon 15-Sep-2014 13:31:28 by m2html © 2005