view src/luan/modules/lucene/PostgresBackup.java @ 1388:2024d23ddd64

add restore_from_postgres
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 03 Sep 2019 22:12:53 -0600
parents bc40bc9aab3a
children 94f48cc76de8
line wrap: on
line source

package luan.modules.lucene;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.util.Properties;
import luan.Luan;
import luan.LuanTable;
import luan.LuanFunction;
import luan.LuanException;
import luan.modules.parsers.LuanToString;
import luan.lib.logging.Logger;
import luan.lib.logging.LoggerFactory;


final class PostgresBackup {
	private static final Logger logger = LoggerFactory.getLogger(PostgresBackup.class);

	static PostgresBackup newInstance() {
		try {
			return new PostgresBackup();
		} catch(ClassNotFoundException e) {
			logger.error("creation failed",e);
			return null;
		} catch(SQLException e) {
			logger.error("creation failed",e);
			return null;
		}
	}

	final boolean wasCreated;
	private final Connection con;
	private final PreparedStatement insertStmt;
	private final PreparedStatement updateStmt;
	private final PreparedStatement deleteStmt;
	private int trans = 0;
	private final LuanToString luanToString = new LuanToString();
	private final LuanTable env = new LuanTable(new Luan());

	private PostgresBackup()
		throws ClassNotFoundException, SQLException
	{
		Class.forName("org.postgresql.Driver");

		String url = "jdbc:postgresql://localhost:5432/luan";
		Properties props = new Properties();
		props.setProperty("user","postgres");
		props.setProperty("password","");

		con = DriverManager.getConnection(url,props);

		Statement stmt = con.createStatement();
		boolean hasTable = stmt.executeQuery(
			"select * from information_schema.tables where table_name='lucene'"
		).next();
		if( !hasTable ) {
			stmt.executeUpdate(
				"create table lucene ("
				+"	id integer not null primary key,"
				+"	data text not null"
				+")"
			);
		}
		stmt.close();
		wasCreated = !hasTable;

		insertStmt = con.prepareStatement(
			"insert into lucene (id,data) values (?,?)"
		);
		updateStmt = con.prepareStatement(
			"update lucene set data=? where id=?"
		);
		deleteStmt = con.prepareStatement(
			"delete from lucene where id=?"
		);

		luanToString.strict = true;
		luanToString.numberTypes = true;
		LuanToString.addNumberTypes(env);
	}

	void close() {
		try {
			insertStmt.close();
			updateStmt.close();
			deleteStmt.close();
			con.close();
		} catch(SQLException e) {
			logger.error("close failed",e);
		}
	}

	protected void finalize() throws Throwable {
		super.finalize();
		if( !con.isClosed() ) {
			logger.error("con not closed");
			con.close();
		}
	}

	void add(long id,LuanTable doc) throws LuanException {
		try {
//logger.info("getAutoCommit="+con.getAutoCommit());
			String data = luanToString.toString(doc);
			insertStmt.setLong(1,id);
			insertStmt.setString(2,data);
			insertStmt.executeUpdate();
		} catch(SQLException e) {
			logger.error("add failed",e);
		}
	}

	void update(long id,LuanTable doc) throws LuanException {
		try {
			String data = luanToString.toString(doc);
			updateStmt.setString(1,data);
			updateStmt.setLong(2,id);
			int n = updateStmt.executeUpdate();
			if( n==0 ) {
				logger.error("update not found for id="+id+", trying add");
				add(id,doc);
			} else if( n!=1 )
				throw new RuntimeException();
		} catch(SQLException e) {
			logger.error("update failed",e);
		}
	}

	void deleteAll() {
		try {
			Statement stmt = con.createStatement();
			stmt.executeUpdate("delete from lucene");
			stmt.close();
		} catch(SQLException e) {
			logger.error("update failed",e);
		}
	}

	void delete(long id) {
		try {
			deleteStmt.setLong(1,id);
			int n = deleteStmt.executeUpdate();
			if( n==0 ) {
				logger.error("delete not found for id="+id);
			}
		} catch(SQLException e) {
			logger.error("update failed",e);
		}
	}

	void begin() {
		try {
			if( trans++ == 0 )
				con.setAutoCommit(false);
		} catch(SQLException e) {
			logger.error("begin failed",e);
		}
	}

	void commit() {
		try {
			if( trans <= 0 ) {
				logger.error("commit not in transaction");
				return;
			}
			if( --trans == 0 )
				con.setAutoCommit(true);
		} catch(SQLException e) {
			logger.error("begin failed",e);
		}
	}

	void rollback() {
		try {
			if( --trans != 0 ) {
				logger.error("rollback failed trans="+trans);
				return;
			}
			con.rollback();
			con.setAutoCommit(true);
		} catch(SQLException e) {
			logger.error("begin failed",e);
		}
	}

	private final Luan luanEval = new Luan();

	private Object eval(String s) throws LuanException {
		LuanFunction fn = env.luan().load( "return "+s, "PostgresBackup", env );
		return fn.call();
	}

	void restoreLucene(LuceneIndex li)
		throws LuanException, IOException
	{
		try {
			Statement stmt = con.createStatement();
			ResultSet rs = stmt.executeQuery("select data from lucene");
			while( rs.next() ) {
				String data = rs.getString("data");
				LuanTable doc = (LuanTable)eval(data);
				li.restore(doc);
			}
			stmt.close();
		} catch(SQLException e) {
			logger.error("restoreLucene failed",e);
			throw new RuntimeException(e);
		}
	}

	long maxId()
		throws LuanException, IOException
	{
		try {
			Statement stmt = con.createStatement();
			ResultSet rs = stmt.executeQuery("select max(id) as m from lucene");
			rs.next();
			long m = rs.getLong("m");
			stmt.close();
			return m;
		} catch(SQLException e) {
			logger.error("maxId failed",e);
			throw new RuntimeException(e);
		}
	}

}