Mittwoch, 22. März 2017

Managing Gigabytes of files

Vor einiger Zeit hatte ich ein Apex Projekt für die Verteilung von Dokumenten und Fotos.
Dabei sollten die Dokumente in einer Ordner Hierarchie angezeigt und zum Download bereitgestellt werden. Es sollten dann über 3GB an Dateien veröffentlicht werden. Da bot es sich an Zip-Archive für den Upload und Download zu verwenden.
Die open source library as_zip enthielt die dafür benötigten Funktionen.
https://technology.amis.nl/2010/06/09/parsing-a-microsoft-word-docx-and-unzip-zipfiles-with-plsql/

Bei Auslesen größerer Archive mit tausenden Dateien mit der Funktion as_zip.get_file versagte jedoch die Performance. Die Ursache war schnell gefunden: Die Funktion macht eine sequenziellen Scann durch das Archiv bis der übergebene Datei Pfadname gefunden wird. Vor dem Vergleich muss der binäre Inhalt auch noch nach Unicode konvertiert werden.
Es wird also ein Index für das Archiv benötigt, damit die Funktion as_zip.get_file direkt zugreifen kann. Nachdem ich mit der Prozedur as_zip.get_file_date_list schon eine Datumsliste aus dem Verzeichnis erstellt hatte, war es nicht schwer auch den Datei-Offset für jede enthaltene Datei in einem Array zu kalkulieren. Damit konnte as_zip.get_file nun richtig loslegen und große Archive in proportionaler Zeit zur Dateigröße einlesen. 

Um den Prozess weiter zu beschleunigen, habe ich die library unzip_parallel entwickelt. Diese library liest ein Zip-Archiv aus einer Sql-Tabelle und schreibt alle enthaltenen Dateien in zwei Tabellen.
Ein für die Dateien and die zweite für die Ordner Struktur als rekursive parent - child Relation.
(So kann die Ordner Struktur einfache in einer Tree-Region dargestellt werden.)
Für größere Archive verwendet die library das oracle package dbms_parallel_execute. 
Damit lies sich die Verarbeitungszeit noch einmal halbieren.

Die Funktionalität dieser library habe ich nun als Apex Plug-in veröffentlicht:

Process plug-in for reading a zip file from a table, storing all expanded files 
in one table and the folders for the files in a second table.
The table for the files has a least the two columns for file_name varchar2, file_content blob
and optionally file_date date, file_size number, mime_type varchar2(300), folder_id number.
The table for the folders has at least a folder_id number, parent_id number, folder_name varchar2.
When no folder definition is provided in the Folder Query attribute, full pathnames are stored in the file_name field of the files table.
Zip file larger than 5MB will be processed in parallel to reduce the processing time when parallel execution is enabled.

A demo of the plugin can be found here:

Keine Kommentare:

Kommentar veröffentlichen

Hinweis: Nur ein Mitglied dieses Blogs kann Kommentare posten.