DEADSOFTWARE

sfs: API to temporary disable volume GC
authorKetmar Dark <ketmar@ketmar.no-ip.org>
Fri, 15 Apr 2016 11:29:42 +0000 (14:29 +0300)
committerKetmar Dark <ketmar@ketmar.no-ip.org>
Fri, 15 Apr 2016 11:30:37 +0000 (14:30 +0300)
src/sfs/sfs.pas

index 7588ae7fc7bfad89bb544866293272e1dffe887c..eaabb964a9e0bb9f55a8f952deabbd9ecf29b8fc 100644 (file)
@@ -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;