JDBC LargeObjects - Speicherplatz

Ich verwende per JDBC die LargeObjectManager API um große Files auf meinen Postgres Server zu speichern. Genauso auch die API zum Löschen der Objekte. Grundsätzlich funktioniert das einwandfrei.

Ich habe dazu zwei Probleme

  • Der Speicherplatz wird nie freigeben und somit wird die Datenbank immer größer wird
  • In der Tabelle pg_largeobject sind keine Einträge ersichtlich, obwohl die Daten gespeichert worden sind. Ist das normal (Zumindest in der pg_largeobject_metadata ist ein Eintrag für den Connect User da aber ohne die Spalte lomacl zu befüllen) ?

Laut meiner Recherche gibt es drei Mechanismen um den Speicherplatz wieder freizugeben:

  1. vacuumlo
  2. vacuum full (ausgeführt als postgres user und als user der benutzten Datenbank)
  3. vacuumdb

Server: Debian Squeeze mit Postgres 9.3 (upgrade von 9.0 -> 9.1 -> 9.3), JDK 1.7_u40, JDBC Treiber Version 9.2.1004 JDBC4

Alle Maßnahmen haben keinen Effekt auf den Speicherplatz. Er wird nicht freiggeben. Wenn ich das löschen nicht durchführe räumt zwar vacuumlo das nicht mehr verwendete Objekt auf, allerdings wird kein Speicherplatz freigegeben.

Anbei noch mein kleiner Test mittels JDBC wo man zuschauen kann wie der Speicherplatz steigt:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package postgres.jdbc.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
import org.postgresql.largeobject.LargeObject;
import org.postgresql.largeobject.LargeObjectManager;

/**
 *
 * @author Clemens
 */
public class UploadBigDataFile {

    private Connection conn;

    public UploadBigDataFile() throws SQLException {
        String url = "jdbc:postgresql://localhost/accidentsim";
        Properties props = new Properties();
        props.setProperty("user", "db_unfall");
        props.setProperty("password", "accident");
        //props.setProperty("ssl", "false");
        conn = DriverManager.getConnection(url, props);
    }

    public long insertIntoDB() throws SQLException, FileNotFoundException, IOException {
        // All LargeObject API calls must be within a transaction block
        conn.setAutoCommit(false);

// Get the Large Object Manager to perform operations with
        LargeObjectManager lobj = ((org.postgresql.PGConnection) conn).getLargeObjectAPI();

// Create a new large object
        long oid = lobj.createLO(LargeObjectManager.READ | LargeObjectManager.WRITE);

// Open the large object for writing
        LargeObject obj = lobj.open(oid, LargeObjectManager.WRITE);

// Now open the file
        File file = new File("/Users/selfemp/Pictures/Videos/short.mp4");
        FileInputStream fis = new FileInputStream(file);

// Copy the data from the file to the large object
        byte buf[] = new byte[2048];
        int s, tl = 0;
        while ((s = fis.read(buf, 0, 2048)) > 0) {
            obj.write(buf, 0, s);
            tl += s;
        }
// Close the large object
        obj.close();

// Now insert the row into imageslo
        PreparedStatement ps = conn.prepareStatement("UPDATE accidentmedia SET realmediadata = ? where accidentmedia_accidentcaseid = ? and accidentmediaid = ?");
        ps.setLong(1, obj.getLongOID());
        ps.setLong(2, 5);
        ps.setLong(3, 5);
        ps.executeUpdate();
        ps.close();
        fis.close();

// Finally, commit the transaction.
        conn.commit();
        return oid;
    }

    public void removeBigData(long oid) throws SQLException {
        conn.setAutoCommit(false);
        // Get the Large Object Manager to perform operations with
        LargeObjectManager lobj = ((org.postgresql.PGConnection) conn).getLargeObjectAPI();
        lobj.delete(oid);        
        conn.commit();
    }
}

Jetzt ist meine Testdatenbank, die aktuell leer ist schon fast 19GB groß ohne Daten. Wie kann ich den Speicherplatz wieder freigeben ?

Hab nie mit LargeObjects innerhalb der DB gearbeitet, würde Dir aber PostgreSQL: Documentation: 16: F.22. lo — manage large objects empfehlen. Falls Du das schon nutzt: sorry für’s rauschen.

Den Link kenne ich schon und das habe ich auch schon installiert. Leider wird der Speicherplatz auch damit nicht freigegeben.

rufst auch lo_unlink auf?

Ja ich rufe lo_unlink auf.

Allerdings habe ich folgende Entdeckung gemacht:

  • Am Testserver unter OSX 10.8 wird der Speicherplatz nicht freigegeben
  • Am Produktivserver unter Debian scheint es zu funktionieren, allerdings bin ich gerade dabei das zu prüfen

Ich werde nun versuchen unter OSX den Server zu deinstallieren und anschließend per Macports zu installieren. Ich hoffe damit das der Server dann ähnlich funktioniert als unter Debian. Denn auf dem Produktivserver kann ich solche Tests nicht durchführen.