Candid Dauth: Kompression via Mainstream-Extension

Heißa, alle,

Ich habe einige Dateien, die ein serialisiertes Array enthalten, das dann von einem Objekt in PHP5 verwaltet wird. Solange das Objekt besteht, soll die Datei gesperrt bleiben, und die Datei wird beim Erstellen des Objekts komplett ausgelesen und unserialisiert, beim Löschen des Objekts wird das Array wieder serialisiert und voll in die Datei gespeichert, andere Dateioperationen werden nicht gebraucht.

function __construct($user)  
{  
  $this->filename = DB_DIR.'/'.urlencode($user);  
  $stream = '';  
  $this->location = $stream.$this->filename;  
  $this->file_pointer = fopen($this->location, 'r+b');  
  flock($this->file_pointer, LOCK_EX);  
  clearstatcache();  
  $this->raw = unserialize(fread($this->file_pointer, filesize($this->filename));  
}  
  
function __destruct()  
{  
  fseek($this->file_pointer, 0, SEEK_SET);  
  ftruncate($this->file_pointer, 0);  
  fwrite($this->file_pointer, serialize($this->raw));  
  flock($this->file_pointer, LOCK_UN);  
  fclose($this->file_pointer);  
}

So weit, so gut, das funktioniert bisher auch problemlos.

Da jedoch letztendlich sehr viele solche Dateien existieren, sind die Datenmengen auch recht groß, und ich wollte nun auf Kompression setzen.
Mit bzip2 habe ich da bisher die besten Erfahrungen bezüglich des Kompressionslevels gemacht. Das ist zwar ein bisschen CPU-intensiver als gzip, aber das macht mir nichts aus.

Ich setze also $stream auf 'compress.bzip2://'. Jetzt tritt dabei folgendes Problem auf: Ich erhalte in der Funktion __destruct() eine Fehlermeldung, dass bzip2 kein fseek unterstützt. Eigentlich dürfte es doch kein Problem sein, wieder an den Anfang der Datei zu springen bzw. deren Inhalt zurückzusetzen. Neu öffnen will ich nicht, da sie ja in der Zeit dann ungesperrt ist, was zum Chaos führen würde. Gibt es eine spezielle Möglichkeit, den Inhalt der Datei zurückzusetzen?
Außerdem stimmt das mit der filesize nicht, da die Dateigröße der bzip2-Datei ja anders ist als die Größe ihres Inhalts. Gibt es da eine Funktion, mit der ich die Größe des Inhalts der bzip2-Datei herausbekomme oder anderswie ihren gesamten Inhalt auslese?

Wenn ich alternativ 'compress.zlib://', also gzip-Kompression, verwende, tritt ein ganz anderes Problem auf: Die Datei lässt sich anscheinend nicht zum Lesen und Schreiben gleichzeitig öffnen. Ich müsste sie also wieder schließen, um sie neu zu beschreiben, und das gefällt mir nicht, da ich sie ja dann wieder entsperren muss.

Die Sache mit gzopen() habe ich auch schon ausprobiert, der Nachteil dort ist aber, dass sich die Dateien anscheinend nicht sperren lassen kann, und außerdem habe ich keine generalisierten Zugriffsfunktionen, wenn ich mal das Kompressionsformat ändern will.

Eine Möglichkeit, die mir jetzt einfällt, ist, zusätzliche Dateien anzulegen, die nur zur Sperrung dienen. Allerdings würden dadurch noch viel mehr Dateien entstehen, das passt mir also auch nicht so recht.

Fällt jemandem eine anständige Lösung für mein Problem ein? Oder werde ich meine eigenen Streams schreiben müssen?

Gautera!
Grüße aus Biberach Riss,
Candid Dauth

--
Ein Fußball-Fan? Noch auf der Suche eine Schlafmöglichkeit im Großraum Stuttgart für die WM 2006? Wie wäre es mit Herrenberg, einer gemütlichen Kleinstadt am Rande des Schönbuchs – von der Lage her ideal, auch für andere Vorhaben im Urlaub. Ferienwohnungen-Herrenberg.com.
http://cdauth.de/
  1. Hallo Candid,

    // http://selfhtml.bitworks.de/artikel_locking/artikel/artikel.htm

    function __construct($user)

    {
      $this->filename = DB_DIR.'/'.urlencode($user);
      $stream = '';
      $this->location = $stream.$this->filename;
      $this->file_pointer = fopen($this->location, 'r+b');
      flock($this->file_pointer, LOCK_EX);

    /* Du hast das Chaos ja schon fest einprogrammiert
          wo fängst Du ab, ob flock erfolgreich war ?!? */

    clearstatcache();
      $this->raw = unserialize(fread($this->file_pointer, filesize($this->filename));
    }

    function __destruct()
    {
      fseek($this->file_pointer, 0, SEEK_SET);
      ftruncate($this->file_pointer, 0);
      fwrite($this->file_pointer, serialize($this->raw));
      flock($this->file_pointer, LOCK_UN);
      fclose($this->file_pointer);
    }

    
    >   
    > So weit, so gut, das funktioniert bisher auch problemlos.  
      
    Das ist bis jetzt wohl eher eine Glückssache gewesen!  
      
    
    > Außerdem stimmt das mit der filesize nicht, da die Dateigröße der bzip2-Datei ja anders ist als die Größe ihres Inhalts. Gibt es da eine Funktion, mit der ich die Größe des Inhalts der bzip2-Datei herausbekomme oder anderswie ihren gesamten Inhalt auslese?  
      
    Was Du machst, ist bis jetzt doch schon mal (, bis auf flock()) der richtige Weg. Du öffnest, sperrst und liest aus einem Flatefile, setzt die Größe auf 0 Byte und schreibst darin. Nunbitte - die bzip2-Erweiterung läßt es zu STRINGS zu dekomprimieren oder diese zu komprimieren... [bzdecompress()](http://de3.php.net/manual/de/function.bzdecompress.php), [bzcompress()](http://de3.php.net/manual/de/function.bzcompress.php)  
      
    Noch ein sehr guter Verweis auf den von Tom in Arbeit befindlichen Artikel: <http://selfhtml.bitworks.de/artikel_locking/artikel/artikel.htm>  
      
      
    Gruß aus Berlin!  
    eddi
    
    1. Heißa, XaraX,

      /* Du hast das Chaos ja schon fest einprogrammiert
            wo fängst Du ab, ob flock erfolgreich war ?!? */

      Ob fopen erfolgreich war, überprüfe ich schon, nur ich habe es nicht in den von mir geposteten Quellcode geschrieben, da ich es für nicht so relevant für mein Problem hielt. Kann flock denn unabhängig vom Resultat von fopen fehlschlagen?

      Was Du machst, ist bis jetzt doch schon mal (, bis auf flock()) der richtige Weg. Du öffnest, sperrst und liest aus einem Flatefile, setzt die Größe auf 0 Byte und schreibst darin. Nunbitte - die bzip2-Erweiterung läßt es zu STRINGS zu dekomprimieren oder diese zu komprimieren... bzdecompress(), bzcompress()

      Zumindest bei gzcompress() habe ich die Erfahrung gemacht, dass ich entstehende Dateien nicht einfach mit gunzip in der Konsole dekomprimieren kann, wenn ich einmal irgendwas in der Datei herumfuhrwerken will. Ich brauch dann immer ein PHP-Script, das das für mich erledigt.
      Ich hielt das einfach für keine saubere Lösung… Gibt es dann irgendwas, wie ich aus den mit gzcompress()/bzcompress() komprimierten Daten eine über die Konsole entpackbare Datei machen kann?

      Gautera!
      Grüße aus Biberach Riss,
      Candid Dauth

      --
      Ein Fußball-Fan? Noch auf der Suche eine Schlafmöglichkeit im Großraum Stuttgart für die WM 2006? Wie wäre es mit Herrenberg, einer gemütlichen Kleinstadt am Rande des Schönbuchs – von der Lage her ideal, auch für andere Vorhaben im Urlaub. Ferienwohnungen-Herrenberg.com.
      http://cdauth.de/
      1. Hallo Candid,

        Ob fopen erfolgreich war, überprüfe ich schon, nur ich habe es nicht in den von mir geposteten Quellcode geschrieben, da ich es für nicht so relevant für mein Problem hielt. Kann flock denn unabhängig vom Resultat von fopen fehlschlagen?

        ja

        Ich hielt das einfach für keine saubere Lösung… Gibt es dann irgendwas, wie ich aus den mit gzcompress()/bzcompress() komprimierten Daten eine über die Konsole entpackbare Datei machen kann?

        PHP gibt es auch als CLI ;)

        Gruß aus Berlin!
        eddi

        --
        Wer Rechtschreibfehler findet, darf sie behalten.