From: Ketmar Dark Date: Fri, 15 Apr 2016 11:29:42 +0000 (+0300) Subject: sfs: API to temporary disable volume GC X-Git-Url: http://deadsoftware.ru/gitweb?p=d2df-sdl.git;a=commitdiff_plain;h=e115314b89990a3263a0971b47cee316d20d0aab sfs: API to temporary disable volume GC --- diff --git a/src/sfs/sfs.pas b/src/sfs/sfs.pas index 7588ae7..eaabb96 100644 --- a/src/sfs/sfs.pas +++ b/src/sfs/sfs.pas @@ -199,6 +199,16 @@ function SFSFileOpen (const fName: TSFSString): TStream; // ïîñëå èñïîëüçîâàíèÿ, íàòóðàëüíî, èòåðàòîð íàäî ãðîõíóòü %-) function SFSFileList (const dataFileName: TSFSString): TSFSFileList; +// çàïðåòèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî) +procedure sfsGCDisable (); + +// ðàçðåøèòü îñâîáîæäåíèå âðåìåííûõ òîìîâ (ìîæíî âûçûâàòü ðåêóðñèâíî) +procedure sfsGCEnable (); + +// for completeness sake +procedure sfsGCCollect (); + + function SFSReplacePathDelims (const s: TSFSString; newDelim: TSFSChar): TSFSString; // èãíîðèðóåò ðåãèñòð ñèìâîëîâ function SFSStrEqu (const s0, s1: TSFSString): Boolean; @@ -478,6 +488,63 @@ type var factories: TObjectList; // TSFSVolumeFactory volumes: TObjectList; // TVolumeInfo + gcdisabled: Integer = 0; // >0: disabled + + +procedure sfsGCCollect (); +var + f, c: Integer; + vi: TVolumeInfo; + used: Boolean; +begin + // collect garbage + f := 0; + while f < volumes.Count do + begin + vi := TVolumeInfo(volumes[f]); + if vi = nil then continue; + if (not vi.fPermanent) and (vi.fVolume.fRC = 0) and (vi.fOpenedFilesCount = 0) then + begin + // this volume probably can be removed + used := false; + c := volumes.Count-1; + while not used and (c >= 0) do + begin + if (c <> f) and (volumes[c] <> nil) then + begin + used := (TVolumeInfo(volumes[c]).fStream = vi.fStream); + if not used then used := (TVolumeInfo(volumes[c]).fVolume.fFileStream = vi.fStream); + if used then break; + end; + Dec(c); + end; + if not used then + begin + {$IFDEF SFS_VOLDEBUG}writeln('000: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF} + volumes.extract(vi); // remove from list + vi.Free; // and kill + f := 0; + continue; + end; + end; + Inc(f); // next volume + end; +end; + +procedure sfsGCDisable (); +begin + Inc(gcdisabled); +end; + +procedure sfsGCEnable (); +begin + Dec(gcdisabled); + if gcdisabled <= 0 then + begin + gcdisabled := 0; + sfsGCCollect(); + end; +end; // ðàçáèòü èìÿ ôàéëà íà ÷àñòè: ïðåôèêñ ôàéëîâîé ñèñòåìû, èìÿ ôàéëà äàííûõ, @@ -754,12 +821,12 @@ begin if fOwner <> nil then begin Dec(fOwner.fOpenedFilesCount); - if not fOwner.fPermanent and (fOwner.fOpenedFilesCount < 1) then + if (gcdisabled = 0) and not fOwner.fPermanent and (fOwner.fOpenedFilesCount < 1) then begin f := volumes.IndexOf(fOwner); if f <> -1 then begin - {$IFDEF SFS_VOLDEBUG}writeln('destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF} + {$IFDEF SFS_VOLDEBUG}writeln('001: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF} volumes[f] := nil; // this will destroy the volume end; end; @@ -926,9 +993,9 @@ begin if fVolume <> nil then Dec(fVolume.fRC); Dec(TVolumeInfo(volumes[f]).fOpenedFilesCount); // óáü¸ì çàïèñü, åñëè îíà âðåìåííàÿ, è â íåé íåò áîëüøå íè÷åãî îòêðûòîãî - if not TVolumeInfo(volumes[f]).fPermanent and (TVolumeInfo(volumes[f]).fOpenedFilesCount < 1) then + if (gcdisabled = 0) and not TVolumeInfo(volumes[f]).fPermanent and (TVolumeInfo(volumes[f]).fOpenedFilesCount < 1) then begin - {$IFDEF SFS_VOLDEBUG}writeln('destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF} + {$IFDEF SFS_VOLDEBUG}writeln('002: destroying volume "', TVolumeInfo(volumes[f]).fPackName, '"');{$ENDIF} volumes[f] := nil; end; inherited Destroy(); @@ -1023,7 +1090,7 @@ begin except FreeAndNil(st); // óäàëèì íåèñïîëüçóåìûé âðåìåííûé òîì. - if not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[result] := nil; + if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[result] := nil; raise; end; // óðà. îòêðûëè ôàéë. êèäàåì â âîçäóõ ÷åï÷èêè, ïðîäîëæàåì ðàçâëå÷åíèå. @@ -1232,7 +1299,7 @@ begin ps := TOwnedPartialStream.Create(vi, result, 0, result.Size, true); except result.Free(); - if not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil; + if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil; result := CheckDisk(); // îáëîì ñ datafile, ïðîâåðèì äèñê if result = nil then raise ESFSError.Create('file not found: "'+fName+'"'); exit; @@ -1305,7 +1372,7 @@ begin result := TSFSFileList.Create(vi.fVolume); Inc(vi.fVolume.fRC); except - if not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil; + if (gcdisabled = 0) and not vi.fPermanent and (vi.fOpenedFilesCount < 1) then volumes[f] := nil; end; end;