view src/luan/modules/lucene/PostgresBackup.java @ 1393:cc0dbca576dc

better logging
author Franklin Schmidt <fschmidt@gmail.com>
date Fri, 06 Sep 2019 05:09:56 -0600
parents 002152af497a
children 67c0e47b5be3
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 java.util.List;
import java.util.ArrayList;
import java.util.Map;
import luan.Luan;
import luan.LuanTable;
import luan.LuanFunction;
import luan.LuanException;
import luan.modules.Utils;
import luan.modules.parsers.LuanToString;
import luan.lib.logging.Logger;
import luan.lib.logging.LoggerFactory;


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

	private final Logger luanLogger;

	final boolean wasCreated;
	private final String url;
	private final Properties props = new Properties();
	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();

	PostgresBackup(Luan luan,Map spec)
		throws ClassNotFoundException, SQLException, LuanException
	{
		this.luanLogger = luan.getLogger(PostgresBackup.class);
/*
		Class.forName("org.postgresql.Driver");
		url = "jdbc:postgresql://localhost:5432/luan";
		props.setProperty("user","postgres");
		props.setProperty("password","");
*/
		String cls = "org.postgresql.Driver";
		if( !Utils.removeRequiredString(spec,"class").equals(cls) )
			throw new LuanException( "parameter 'class' must be '"+cls+"'" );
		Class.forName(cls);
		url = Utils.removeRequiredString(spec,"url");
		props.setProperty( "user", Utils.removeRequiredString(spec,"user") );
		props.setProperty( "password", Utils.removeRequiredString(spec,"password") );
		Utils.checkEmpty(spec);

		con = newConnection();

		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;
	}

	Connection newConnection() throws SQLException {
		return DriverManager.getConnection(url,props);
	}

	void close() throws SQLException {
		insertStmt.close();
		updateStmt.close();
		deleteStmt.close();
		con.close();
	}

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

	void add(LuanTable doc) throws LuanException, SQLException {
		Long id = (Long)doc.get("id");
		String data = luanToString.toString(doc);
		insertStmt.setLong(1,id);
		insertStmt.setString(2,data);
		insertStmt.executeUpdate();
	}

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

	void deleteAll() throws SQLException {
		Statement stmt = con.createStatement();
		stmt.executeUpdate("delete from lucene");
		stmt.close();
	}

	void delete(long id) throws SQLException, LuanException {
		deleteStmt.setLong(1,id);
		int n = deleteStmt.executeUpdate();
		if( n==0 )
			throw new LuanException("delete not found for id="+id);
	}

	void begin() throws SQLException {
		if( trans++ == 0 )
			con.setAutoCommit(false);
	}

	void commit() throws SQLException, LuanException {
		if( trans <= 0 )
			throw new LuanException("commit not in transaction");
		if( --trans == 0 )
			con.setAutoCommit(true);
	}

	void rollback() throws SQLException, LuanException {
		if( --trans != 0 )
			throw new LuanException("rollback failed trans="+trans);
		con.rollback();
		con.setAutoCommit(true);
	}

	private static LuanTable newEnv() {
		LuanTable env = new LuanTable(new Luan());
		LuanToString.addNumberTypes(env);
		return env;
	}

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

	void restoreLucene(LuceneIndex li)
		throws LuanException, IOException, SQLException
	{
		LuanTable env = newEnv();
		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,env);
			li.restore(doc);
		}
		stmt.close();
	}

	long maxId()
		throws LuanException, IOException, SQLException
	{
		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;
	}

	final class Checker {
		private final Connection con;
		private final PreparedStatement pstmt;
		private final LuanTable env = newEnv();

		Checker() throws SQLException {
			con = newConnection();
			con.setAutoCommit(false);
			pstmt = con.prepareStatement(
				"select data from lucene where id=?"
			);
		}

		void close() throws SQLException {
			pstmt.close();
			con.close();
		}

		List<Long> getIds() throws SQLException {
			List<Long> ids = new ArrayList<Long>();
			Statement stmt = con.createStatement();
			ResultSet rs = stmt.executeQuery("select id from lucene order by id");
			while( rs.next() ) {
				long id = rs.getLong("id");
				ids.add(id);
			}
			stmt.close();
			return ids;
		}

		LuanTable getDoc(long id) throws SQLException, LuanException {
			pstmt.setLong(1,id);
			ResultSet rs = pstmt.executeQuery();
			rs.next();
			String data = rs.getString("data");
			LuanTable doc = (LuanTable)eval(data,env);
			return doc;
		}
	}

	Checker newChecker() throws SQLException {
		return new Checker();
	}

}