Dateien und Verzeichnisse

Codepfade

Die Codeverzeichnisse werden von Semantics im Rahmen der Installation und der Updates gepflegt. Der größte Teil der Applikation wird unter /opt auf einem Linuxsystem installiert und ausgeführt. Die Verzeichnisse unter /opt/vls gehöhren dem User vlserver der Gruppe vls.

/opt/vls{VERSION}

VLS-Instanz in einer bestimmten Version

  • ./etc/vls/server.ini: Instanzkonfiguration: Ports, Verzeichnisse, …
  • ./domain: Mandantenkonfiguration/Code
  • ./server: Core
/opt/vls

Hostkonfiguration + Tools

  • ./bin/supervisord: Prozessmanager
  • ./bin/bucky: Monitoring
  • ./bin/diamond: Monitoring
/opt/firebird{VERSION}

Firebird-Binaries

  • ./firebird.conf: Konfiguration
  • /usr/lib64/libfbclient.so: shared Library
/etc

Systemweite Konfiguration

  • ./supervisorconf.d: registrierte VLS-Instanzen, bucky, diamond
  • ./init.d/firebird: dameon launcher

Datenpfade

Alle Datenpfade werden über die server.ini einer VLS-Instanz konfiguriert. Es gilt zu beachten, dass für verschiedene Datengruppen unterschiedliche Anforderungen an den Durchsatz bzw. die Latenz gestellt werden.

Im einfachsten Fall konfiguriert man den Pfad zur Datenbank database.file und ein Datenverzeichnis path.var in der server.ini. Das Datenverzeichnis gilt dann als Stammverzeichnis für alle Daten, die auf eine Festplatte geschrieben werden sollen. Eine derart konfigurierte Instanz enthält folgenden Satz Unterverzeichnisse im var-Verzeichnis: backup, cache, export, fulltext, import, index, log, media, purgatory, tmp, upload, zipbackup.

Eine erste sinnvolle Erweiterung ist es zwei Datenverzeichnisse anzugeben: path.varLarge und path.varFast. Wie den Namen zu entnehmen ist, wird der erste Pfad typischerweise für Datenmengen der Größenordnung 10-100 Terabyte verwendet. Der Pfad path.varFast muss nicht so groß sein, hier reichen ein paar hundert Gigabyte aus: Wichtig sind hier jedoch niedrige Latenzen bei Randomaccess, wie sie von SSDs bereitgestellt werden. Typische Datentypen, die auf path.varFast abgelegt werden, sind der Lucene-Index verschiedenste Caches und temporäre Daten.

Wenn die Anforderungen es notwendig machen, können alle Datenpfade jeweils einzeln konfiguriert werden.

Datenbank

Die Firebird-Datenbank für die operativen Daten befindet sich in einem einzelnen File, dessen Pfad in der server.ini unter database.file angegeben wird. Idealerweise befindet sich die Datenbank auf Gerät mit hoher Performance (sprich SSD). Neben dem .fdb File wird zur Laufzeit von dem AnalyzeSessionHistoryJob parallel ein FILENAME.sessions.fdb angelegt, indem die Nutzungsdaten protokolliert werden. Die operative Datenbank wächst auf etwa 10 GB bei 10 Millionen Digitalisaten und 30.000 Katalogisaten. Die Datenbank für die Protokoller der Nutzung kann je nach Nutzung auch 10-20 GB umfassen.

Die Datenbank wird nach path.backupGenerations einmal pro Nacht und nach path.backup on-demand gesichert. Für eine automatische zweite Sicherungskopie kann path.altBackup und path.altBackupGenerations gesetzt werden.

Index

Der Lucene-Index befindet sich in einem Verzeichnis, welches in der server.ini unter path.index angegeben wird. Wie bei der Datenbank, gilt für den Lucene-Index, dass sich der Speicher auf einem möglichst schnellen lokalen Gerät befindet.

Die Größe des Index ist primär davon abhängig ob OCR-Ergbnisse in der VLS-Instanz vorliegen. Ein Index, der 30.000 Katalogisate verwaltet, belegt auf einem 2.16er VLS etwa 500 MB. Ein Index mit 60.000 Katalogisaten und 3.5 Millionen Volltexten belegt etwa 11 GB.

Archiv

Die Archivdaten umfassen das importierte Imagerohmaterial welches im allgemeinen verlustfrei (.tiff) komprimiert ist. Die anfallenden großen Datenmengen werden normalerweise auf einem großen lokalen SAN oder einem S3-Object-Store abgelegt. Die Zugriffszeiten auf einzelne Objekte sollte 1-2 Sekunden nicht überschreiten (sprich keine Bandlaufwerke).

VL unterscheidet 6 verschiedene Typen von Archivdaten, die in 4 unterschiedlichen Default-Stores abgelegt werden.

  • MASTER: initialer .tiff Import (default in Store master)
  • LOSSY MASTER: initialer .jpeg Import (default in Store remastered)
  • DELETED: Kapsel-Exported mit Master-Delete, 0er Webcache wird neuer Master. (Store remastered)
  • PDFRASTER: Derivate aus PDF-Cutter Operationen (Store pdfcutted)
  • HTTPSOURCE: Cache für Remote-Resources, Z.B. aus OAI-Import. (Store httpsource)
  • MIRROR: Cache für Mirror Situation, nur Dev-Systeme. (Store httpsource)

Konfiguration der Archive-Stores

Die Archivdaten werden in Stores abgelegt. Im Default sind 4 Stores definiert, deren FS-Pfad direkt über Einträge in config.path.* gändert werden können. Im Default liegen die Verzeichnise für diese Stores unter var/media (bzw. varLarge).

  • master: config.path.archive
  • remastered: config.path.jpgarchive
  • pdfcutted: config.path.pdfarchive
  • httpsource: config.path.httparchive

Der komplizierte Teil der Konfiguration befindet sich in der config.archive Sektion. Dort sind 4 Stores vordefiniert und dort können weitere Stores ergänzt bzw. deren Eigenschaften verändert werden. Weiterhin können Default-Zordnungen unter config.archive.defaultStores für die obigen 6 Archivedatentypen vorgenommen werden.

Ein Standard-Use-Case besteht darin, ein weiteren Archive-Store einzurichten. Dafür wäre folgende Konfiguration notwendig:

[archive]
    [[anotherLargeSAN]]
        fsroot = /media/san2/vl_archive

Wenn die obige Konfiguration aktiv ist, dann kann man mit dem MoveArchiveJob aus dem default master Store in den neuen anotherLargeSAN Store verschieben.

Es bietet sich eventuell an, neue Importdaten direkt in den neuen anotherLargeSAN Store importieren zu lassen. Dadurch entfällt die Notwendigkeit, den master Store periodisch mit dem MoveArchiveJob abzubauen.

[archive]
    [[defaultStores]]
        MASTER = anotherLargeSAN

Die komplette Konfiguration der 4 Default-Stores sieht so aus:

[archive]
    # default mapping of OP_State values (OPSTATE constant names) to names of storage endpoints
    [[defaultStores]]
        # Attention: In the wild we have i.e. LOSSYMASTER in other stores than the default ones defined here.
        UNDEFINED = string(default=legacy)
        MASTER = string(default=master)  # initially imported tiff
        DELETED = string(default=remastered)  # master image has been deleted (i.e. after zip-capsule export)
        MIRRORED = string(default=httpsource)  # image source access on other VLS instance via config.info.mirror + otid
        PDFRASTER = string(default=pdfcutted)  # image generated py pdfcutter
        HTTPSOURCE = string(default=httpsource)  # image source access somewhere on the web via OP_Url
        LOSSYMASTER = string(default=remastered)  # initially imported jpg (as opposed to tiff)

    # default storage for OP_State=1 (lossless master (tiff, png))
    [[master]]
        on = boolean(default=true)
        type = string(default=buckets10k)
        # aligned with OP_State for convenience
        id = integer(default=1)
        fsroot = path(noCreate, default=${archive})
        # unlimited default size
        maxSizeTB = float(default=0.0)
        # not applicable for buckets10k
        maxCacheSizeGB = integer(default=0)
        [[[props]]]
            hardlinks = string(default=None)

    # default storage for OP_State=2 (capsule exported, ex-0er wc is new master)
    # and OP_State=6 (master import is already jpeg)
    [[remastered]]
        on = boolean(default=true)
        type = string(default=buckets10k)
        # aligned with OP_State for convenience
        id = integer(default=2)
        fsroot = path(noCreate, default=${jpgarchive})
        # unlimited default size
        maxSizeTB = float(default=0.0)
        # not applicable for buckets10k
        maxCacheSizeGB = integer(default=0)
        [[[props]]]
            hardlinks = string(default=None)

    # default storage for OP_State=4
    [[pdfcutted]]
        # auto on if cutter.on=true
        on = boolean(default=false)
        type = string(default=buckets10k)
        # aligned with OP_State for convenience
        id = integer(default=4)
        fsroot = path(noCreate, default=${pdfarchive})
        # not applicable for PDFRASTER states
        maxSizeTB = float(default=0.0)
        # 100 GB default max cache for PDFRASTER
        maxCacheSizeGB = integer(default=100)

    # default storage for OP_State=3 (mirror), OP_State=5 (plain url)
    [[httpsource]]
        # auto on if info.mirror declared
        on = boolean(default=false)
        type = string(default=buckets10k)
        # aligned with OP_State for convenience
        id = integer(default=3)
        fsroot = path(noCreate, default=${httparchive})
        # not applicable for HTTPSOURCE/MIRRORED states
        maxSizeTB = float(default=0.0)
        # 100 GB default max cache for HTTPSOURCE/MIRRORED
        maxCacheSizeGB = integer(default=100)

    [[__many__]]
        # will create fsroot if on=true
        on = boolean(default=true)
        # storage backend configurations:
        #   flatlegacy: local fs, one directory flat with OP_Url %patharchive% resolving
        #   buckets10k: local fs, subdir is determined by otid modulo 10k
        #   s3: S3-API compatible object store
        #   fakes3, atmos: semi S3-API compatible stores
        type = option(flatlegacy, buckets10k, s3, atmos, fakes3, default=buckets10k)
        # value of OP_ArchiveCfg (16bit int)
        id = integer(default=0, min=0, max=32767)
        # filesystem root for buckets10k and flatlegacy
        # used as cache for s3 types (also in buckets10k fs layout)
        fsroot = path(noCreate, default=None)
        # limit the capacity of this storage-endpoint
        # not implemented
        maxSizeTB = float(default=0.0)
        # limit the capacity of the cache aspect of this storage-endpoint
        # ensured by runs of CleanupArchiveCache, can therefore be temporarily violated
        maxCacheSizeGB = integer(default=0)

        # currently used for s3 types, but probably pretty generic
        [[[connection]]]
            host = string(default='127.0.0.1')
            # default from fake-s3
            port = integer(default=4569)
            access_key_id = string(default='UNCONFIGURED')
            secret_access_key = string(default='UNCONFIGURED')
            # use ssl?
            is_secure = boolean(default=True)
            bucket_name = string(default='vls')

        # other generic properties
        [[[props]]]
            # a file-copy below this given path will use hardlinking
            # you will probably use the import directory here
            hardlinks = string(default=None)

Webcache

Der Webcache enthält Derivate der Archivdaten. Hier werden .jpgs, .pngs und in Ausnahmefällen .tiffs aus den Archivmastern erzeugt um diese im Frontend an auszuliefern bzw. in andere Derivate wie PDFs einzubetten. Das Zielverzeichnis wird unter path.webcache in der Serverkonfiguration definiert. Das Verzeichnis enthält für jede konfigurierte Bildbreite ein Unterverzeichnis mit Namen der Breite (./128, ./304, …). In diesen Unterverzeichnissen werden die Bilder dann flach abgelegt. Die Dateinamen entsprechen der Regel VLID.jpg bzw. VLID.png. Pro Archivmaster fallen je nach Konfiguration 3-8 MB Webcache an.

Volltexte

Volltextdateien entstehen beim Einsatz der integrierten OCR oder bei der Extraktion von PDF-Mastern. Dabei handelt es sich um .xml Dateien, die in dem VFS Verzeichnis (path.vfs) gespeichert werden. In diesem Verzeichnis sind 256x256 Unterverzeichnisse auf zwei Ebenen. Auf der untersten Ebene wird für jede VLID ein Verzeichnis (on-demand) angelegt wobei die Zielebene aus dem MD5-Hash der VLID ermittelt wird. Z.B. path_to_vfs/3D/F9/8262892/.

Der Volltext wird dort als fulltext.xml abgelegt. Ein Finereader-OCR Ergebnis kann bis zu 1 MB gross werden, deswegen ist es auch möglich die Volltextdateien mit GZIP zu komprimieren (Faktor 10-20). In diesem Fall werden die Dateien als fulltext.xml.gz abgelegt.

Wordcache

Aus jedem Volltext werden aus Effizienzgründen zwei Wordcachedateien extrahiert. In dem ersten File sind alle Wörter gelistet und in dem zweiten File alle Boundingboxen (x1, y1, x2, y2), also die Positionen der Wörter relativ zu dem Archivmaster. Bei 1 Million Volltexten erwarten wir etwa 50 GB Platzbedarf. Idealerweise werden diese Daten auf einer SSD abgelegt, da bei Frontentoperationen wie der “Suche in Volltexten” auf diese Daten schnell zugegriffen werden muss.

PDFs

Es gibt zwei Arten von PDF-Dateien, die von VLS verwendet werden. Einmal die Derivate, die in der Retrodigitaliserung von VL erzeugt werden (PDFJob). Und weiterhin Born-Digital PDFs, die z.B in Publikationsservern importiert werden. Erstere enthalten Rasterimages und OCR-Ergebnisse und letztere Verktordaten. Erstere können mehrere hundert Megabyte gross sein, letztere sind normalerweise wenige Megabyte oder hunderte Kilobyte groß.

Die Retro-PDFs werden als document.pdf im VFS gespeichert. Die Born-Digital-PDFs als upload.pdf.

EPUBs

Born-Digital Dokumente im .epub Format werden im VFS unter epubfile.epub abgelegt. Diese Dateien sind im Allgemeinen nur wenige hunderte Kilobyte gross.

MP3/MP4

Audio und Videodateien werden im VFS unter video.mp4 bzw. audio.mp abgelegt. Videodateien können mehrere Gigabyte belegen.

Import

Die Importverzeichnisse stellen eine besondere Klasse von Verzeichnissen dar, da sie keine operativen Daten enthalten, sondern als Importinterface auf das System verwendet werden. Es gibt zwei Rootverzeichnisse für den Import in VL. In path.upload werden .zip oder .tar Dateien erwartet. Diese (unkomprimierten) Pakete enthalten dann volständig digitalisierte Werke und sind eventuell über FTP hochgeladen worden. Eine Importvorstufe (ReleaseZipUploadJob) entpackt diese Pakete in das eigentliche Importverzeichnis path.import. Dort arbeitet der ImportJob die verfügbaren Dateien und Verzeichnisse ab.

Das upload und das import Verzeichnis haben für jede Domain ein Unterverzeichnis mit Domainnamen. Eine Anlieferung in ein solches Unterverzeichnis importiert die Daten dann in die jeweilige Domain. Weitere Unterverzeichnisse können zur Importsteuerung verwendet werden. So kann es Verzeichnisse für Kollektionen geben, welche z.B. eine Verlinkung der Datensätze auslösen.

Export/Kapseln

Im Rahmen der Langzeitarchivierung, werden Zipkapseln erzeugt, die die Archivmaster und die Struktur+Anreicherung in .mets Files enthalten. Das Verzeichnis wird unter path.zipBackup konfiguriert. Nach path.zipBackupCopy kann eine Kopie gespeichert werden. VL erwartet, dass ein externes System dieses Verzeichnis abräumt.

Für Exportoperationen von spezielleren Workflows wird path.export verwendet. Z.B. für CE-Pakete, Moodle-PDFs, OBV-OAI-Export und den SUUB-Volltextexport.

Logs

Die Logdateien, die VL für die verschiedenen Komponenten und Prozesse (Jobs) schreibt, werden nach path.log gespeichert. Jeder Logkanal (normalerweise einer pro VL-Komponente) belegt eine Datei mit dem Namen component-name.log. Wenn diese Datei größer als 20 MB (im default) wird, dann wird sie über 10 Generationen wegrotiert.

In path.joblog` werden für jeden Job mindestens zwei Dateien geschrieben. Eine plaintext Logdatei und ein .xml. In letzteren werden besondere Ereignisse (Logeinträge vom Typ “Event”) abgespeichert, die in Jobreports visualisiert werden.

Temp/Cache

Wenn in VL-Komponenten Daten anfallen, die nicht notwendigerweise im RAM gehalten werden müssen, oder die einen Serverrestart überstehen sollen, dann werden diese in path.temp und path.cache abgelegt. Die Daten in path.cache können immer gelöscht werden wenn die VL-Instanz nicht läuft. Bei Daten in path.temp ist das nicht immer der Fall denn bei einigen Unterverzeichnissen werden die Daten von Analysejobs verarbeitet.

Besondere Verzeichnisse

  • purgatory : Wenn (seltene) Löschoperationen anfallen, dann werden die Masterimages in dieses Verzeichnis verschoben.
  • sessions : Speichert alle Daten zu einer Session (Laufzeit und Expiration). Wächst ohne scheduled AnalyzeSessionHistoryJob.
  • tilecache : Speichert die Kacheln, die für die Zoomview im Frontend verwendet werden. Nur die letzten 100 Kachelpyramiden werden aufgehoben.
  • rawImport : Alle Importpakete werden (im default) in diesem Verzeichnis gebackuped. Die Verzeichnisse für fehlgeschlagene Importpakete werden mit fail_ geprefixed. Bei Erfolg wird das Prefix succ_ verwendet und die Pakete werden nach zwei Wochen vom CleanupMediaImportJob weggeräumt. fail_ Verzeichnisse/Pakete werden nie weggeräumt.