Cache.pm - Cache-Modul für Perl - A Cache-Module for Perl
Nunja, also wer hier des Öfteren mal mitliest kann ja schnell auf den Gedanken kommen, ich würde hier nur Grundlagenforschung betreiben...
Daß das nicht so ist und ich auch so ab und zu "sinnvolle" Dinge scripte, zeigt das folgende Beispiel.
Also es war einmal...
eine Problemstellung, die eine Art Cache erforderte. Da ich so 'nen Cache schon mal öfters haben wollte, dachte ich mir, ich schreib mir mal ein Modul, damit ich ein für allemal sowas habe, wenn ich es gerade brauche.
Übrigens hab ich im Internet kein passendes Modul gefunden... damals zumindest... und auf den Servern, für die ich das brauchte, war auch nichts zu finden... also selbermachen!
Vielleicht nochmal kurz die Definition Cache:
Ein Cache ist eine Art Zwischenspeicher für irgentwelche Werte, auf die man schnell zugreifen möchte, ohne sie neu errechnen bzw. sonstwie erzeugen zu müssen.
Das bekannteste Beispiel ist vielleicht der Cache in Ihrem Browser, der Webseiten einmal herunterlädt und dann bereithält, falls man erneut die gleiche URL besucht. Die URL muß dann nicht neu geladen werden, sondern wird aus dem Cache geladen. Dies hat normalerweise Geschwindigkeitsvorteile, allerdings müssen die Daten logischerweise auf Festplatte abgelegt werden und belegen so Festplattenspeicher.
So, das zum Cache. Und genau das sollte (soll) mein Modul machen. Dazu gab ich mir folgende Vorgaben:
- Eine Vollständige Kapselung der Daten, d.h. das Modul darf keine globalen Variablen ändern
- Es müssen auch mehrere Caches nebeneinander laufen können, ohne daß es einen Datensalat gibt
- Ich hätte gerne eine freie Konfigurierbarkeit der Ordner, in denen die Daten auf Platte abgelegt werden
- Es solle eine benutzerdefinierte Verfallszeit möglich sein, d.h. defaulrmäßig gelten Daten nach 24 Stunden als veraltet, bei Bedarf kann aber auch eine benutzerdefinierte Zeit angegeben werden.
- Natürlich müssen veraltete Daten automatisch gelöscht werden, um Plattenspeicher zu sparen
- Das Dateisystem sollte optimiert sein, damit auf Windows-Plattformen nicht allzu viel Platz verschleudert wird
- Der Cache muß auch mal komplett gelöscht werden können
- Oder Einträge müssen auch einzeln gelöscht werden können
- Verfalle Einträge müssen per Befehl gelöscht werden können
- Zeilenumbrüche aller Art müssen korrekt abgespeichert werden
- Und schließlich muß das Modul ohne Installation lauffähig sein, notfalls auch von USB-Stick
Naja, da hab ich mir damals richtig was vorgenommen...
Und herausgekommen ist ein Modul, das folgendes kann
Das Modul selbst muß nur in das cgi-bin-Verzeichnis kopiert werden und die Rechte gesetzt auf 0755 (Unix,Linux).
Initialisierung per
$cache=Cache->new("Ordnername",Dateigröße,Anzahl der Digits der Cachedateien);
Daten ablegen in Cache
$cache->put("Name",Wert);
$cache->exists();
stellt fest, ob ein gültiger Wert im Cache vorliegt.
Daten abholen aus Cache
$wert=$cache->get("Name");
$wert ist der gecachte Inhalt, wenn vorhanden
Eine Abfrage kann also so aussehen:
if ($cache->exists("Name")){$wert=$cache->get("Name");}
Cache komplett leeren
$cache->clear(); oder $cache->erase();
Nur verfallene Daten leeren
$cache->purge();
Einen Datensatz gezielt löschen
$cache->delete("Name");
So, nun Beschreibung, wie man das Modul verwenden kann:
Use Cache; bindet das Modul ein, war glaub ich eh' klar.
$cache=Cache->new("Ordnername",Dateigröße,Anzahl der Digits der Cachedateien);
Es wird die Verbindung zum Cache hergestellt. Die Daten werden im Ordner "Ordnername" abgelegt, falls der nicht vorhanden ist wird er erzeugt.
Falls kein Ordnername angegeben wird, wird per Default der Ordner cache verwendet.
Die Dateigröße gibt an, wie gross eine einzelne Cache-Datei sein darf. Hintergrund ist unten erwähntes Verhalten von Windows. Große Dateien sparen etwas Speicherplatz, sind aber langsamer in der Verarbeitung.
Des weiteren kann man festlegen, wieviele Cache-Stacks erzeugt werden. Hintergrund ist der, daß viele Dateien schneller verarbeitet werden, jedoch mehr Platz auf Platte benötigen.
$cache->put("Elementname",Daten,Dauer);
Jetzt wird etwas in den Cache geschrieben. Als Identifizierung wird ein Elementname verwendet, unter dem die Daten später wiedergefunden werden können. Die Daten selbst sind eben die Daten selbst... Aber mal im Ernst: Daten können alles sein, mit Zeilenumbruch usw.
Sollte der Datensatz schon vorhanden sein, wird er mit den neuen Daten überschrieben.
Der Wert Dauer gibt an, wie viele Sekunden die Daten gültig sein sollen. Danach werden sie gelöscht. Falls keine Dauer angegeben wird, werden 24 Stunden per Default angenommen, d.h. die Daten sind einen Tag lang gültig.
Per exists(Name) kann jetzt abgefragt werden, ob ein gültiger Wert im Cache vorhanden ist.
Im Mißerfolgsfall wird jetzt kein FALSE mehr zurückgegeben. So können jetzt auch "leere" Einträge abgespeichert werden, was vorher nicht Möglich war. Und natürlich auch Einträge mit "FALSE", die vorher mit einer ungültigen Abfrage zu verwechseln gewesen wären.
Warum überhaupt ein exists()?
Man könnte ja auch eine Abfrage direkt per get() durchführen, und wenn nicht zurückgegeben wird, weiß man ja auch, daß kein gültiger Wert da war.
Aber: exists() ist wesentlich schneller als ein get(), da get() zusätzlich verfallene Daten in der gleichen Cache-Datei löscht. Soll es also mal schnell gehen, ist ein exists() dem get() vorzuziehen.
$daten=$cache->get("Elementname");
Daten werden aus dem Cache geholt. Falls Daten gültig sind bzw. vorhanden, werden sie zurückgegeben.
Übrigens: get() löscht verfallene Daten, die in der gleichen Cache-Datei liegen. So wird das "zumüllen" des Speichers vermieden.
$cache->purge();
Löscht alle Daten im Cache, die als verfallen gelten, deren Zeit also abgelaufen ist.
$cache->delete("Elementname");
Löscht das Element mit dem entsprechenden Namen.
Die Verwendung ist also wirklich einfach, man muß sich um nichts kümmern, außer daß genug Plattenspeicher da ist, hat nicht irgentwelche Konventionen einzuhalten.
Das Modul kann übrigens, wie gewünscht, auch parallel mehrere Caches bearbeiten, ohne sich ins Gehege zu kommen.
Hintergründiges
Zuerst sollte man sagen, daß die Verwendung eines Caches ein zweischneidiges Schwert ist: Man kann schnell Daten ablegen, um sie später wieder zu verwenden, aber natürlich verballert man im ungünstigsten Fall Festplattenspeicher. Einen Cache sollte man also nur verwenden, wenn die Erstellung der Daten sehr lange dauert und man genug Platten-Speicher hat.
So ist es natürlich auch bei meinem Modul.
Dazu kam noch eine Besonderheit von Windows: Wenn man unter Windows eine Datei anlegt, die nur 1 Byte enthält, werden trotzdem gleich mehrere KB belegt. Im ungünstigsten Fall müllt man sich also durch viele kleine Dateien die Platte zu.
Das Modul verwendet also Stackdateien, die zu den eigentlichen Inhalten zeigen. Diese Stackdateien können schnell durchsucht werden und im Fall des Verfalls von Datensätzen schnell geupdated werden.
Die eigentlichen Daten liegen im Unterordner cache, und zwar so, daß sie möglichst wenig Speicher verbraten. Das Modul ist so programmiert, daß es immer erst kleinere Dateien auffüllt, bevor es neue anlegt. Die Zahl der Daten-Dateien ist übrigens auf 100.000 begrenzt... aber das nur so am Rande.
Verfallene Einträge werden nach und nach gelöscht, falls man es nicht ausdrücklich per purge() anweist. Das bedeutet, daß verfallene Daten nicht sofort alle weg sind, sondern erst dann, wenn gerade auf einen Datensatz in der Datendatei zugegriffen wird.
Und was macht man nun damit?
Da gibts viele Möglichkeiten... Zum Beispiel kann man einen Web-Proxy damit erstellen. Angesurfte Seiten werden im Cache abgelegt und beim späteren Wiederansurfen aus dem Cache geladen. Das spart Übertragungskapazitäten.
Oder natürlich bei Anwendungen, die schon mal etwas länger dauern und man sich den Systemspeicher freihalten will. Zwischenergebnisse werden im Cache abgelegt und bei Bedarf wieder herausgeholt.
Und da gibts bestimmt noch Tausend anderer Möglichkeiten...
Was noch zu tun ist
Also... das Modul ist schon über 2 Jahre alt, wer sich den Quelltext etwas ansieht, merkt, daß verschiedene Programmierstile vorkommen, je nachdem, inwieweit ich neue Erkenntnisse gesammelt habe.
Der Quelltext sollte sich also noch ändern.
Einige Dinge sind noch nicht optimiert, denke ich, da ich gerade durch diesen Blog hier noch einiges Neues gelernt habe.
Und natürlich das Modul selbst... Eigentlich hab ich das für mich geschrieben, deswegen ist keine Dokumentation enthalten.
Allerdings gibts da ne Menge zu beachten, was ich mir erst anlesen muß...
Wichtig
Lesen Sie hier die Neuerungen!!!
Das Modul gibts hier zum Download.
Bugfixes Bitte beachten Sie:
Versionen > 1 sind nicht kompatibel zur Versionen < 1.
Bei einem Upgrade bitte alle Cachedateien löschen und neu anlegen!
Bugfix am 15.1.2008 -> all_elements
all_elements gab pro Elementenname ein \n am Ende zurück