Mercurial Hosting > luan
changeset 1392:002152af497a
hosted postgres
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 06 Sep 2019 00:19:47 -0600 |
parents | 94f48cc76de8 |
children | cc0dbca576dc |
files | examples/blog/push-local.sh examples/blog/src/lib/Db.luan src/luan/host/WebHandler.java src/luan/host/init.luan src/luan/modules/Utils.java src/luan/modules/logging/LuanLogger.java src/luan/modules/lucene/Lucene.luan src/luan/modules/lucene/LuceneIndex.java src/luan/modules/lucene/PostgresBackup.java src/luan/modules/sql/Database.java src/luan/modules/url/LuanUrl.java |
diffstat | 11 files changed, 229 insertions(+), 190 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/blog/push-local.sh Fri Sep 06 00:19:47 2019 -0600 @@ -0,0 +1,1 @@ +luan luan:host/push.luan blog.me.luan.ws word src 2>&1 | tee err
--- a/examples/blog/src/lib/Db.luan Thu Sep 05 01:29:57 2019 -0600 +++ b/examples/blog/src/lib/Db.luan Fri Sep 06 00:19:47 2019 -0600 @@ -1,16 +1,23 @@ local Lucene = require "luan:lucene/Lucene.luan" local Io = require "luan:Io.luan" +local Hosting = require "luan:host/Hosting.luan" +local Logging = require "luan:logging/Logging.luan" +local logger = Logging.logger "Db" local Db = {} -local function completer(doc) - return doc +local postgres_spec = Hosting.postgres_spec and Hosting.postgres_spec() +logger.info("postgres_spec="..postgres_spec) +if postgres_spec ~= nil then + function postgres_spec.completer(doc) + return doc + end end function Db.new(lucene_dir) local dir = Io.uri(lucene_dir) - local db = Lucene.index( dir, Lucene.type.english, {"subject","content"}, completer ) + local db = Lucene.index( dir, Lucene.type.english, {"subject","content"}, postgres_spec ) -- this is how you index a field -- db.indexed_fields.post_date = Lucene.type.long
--- a/src/luan/host/WebHandler.java Thu Sep 05 01:29:57 2019 -0600 +++ b/src/luan/host/WebHandler.java Fri Sep 06 00:19:47 2019 -0600 @@ -33,7 +33,7 @@ Luan luan = new Luan(); Log4j.newLoggerRepository(luan); - initLuan(luan,dirStr,domain,true); + initLuan(luan,dirStr,domain); return new LuanHandler(luan); } }; @@ -79,11 +79,11 @@ return true; } */ - private static void initLuan(Luan luan,String dir,String domain,boolean logging) { + private static void initLuan(Luan luan,String dir,String domain) { security(luan,dir); try { LuanFunction fn = BasicLuan.load_file(luan,"classpath:luan/host/init.luan"); - fn.call(dir,domain,logging); + fn.call(dir,domain); } catch(LuanException e) { throw new LuanRuntimeException(e); }
--- a/src/luan/host/init.luan Thu Sep 05 01:29:57 2019 -0600 +++ b/src/luan/host/init.luan Fri Sep 06 00:19:47 2019 -0600 @@ -5,12 +5,12 @@ local gsub = String.gsub or error() -local dir, domain, logging = ... +local dir, domain = ... -- logging -if logging then +do require "java" local Log4j = require "java:luan.modules.logging.Log4j" local Level = require "java:org.apache.log4j.Level" @@ -37,7 +37,6 @@ end - -- set vars local Io = require "luan:Io.luan" @@ -66,6 +65,44 @@ }.send + + +-- postgres + +local Sql = require "luan:sql/Sql.luan" +local database = Sql.database or error() +local Logging = require "luan:logging/Logging.luan" +local logger = Logging.logger "init" + +local fn = Luan.load_file("file:postgres.luan") or error() +local pg = fn() + +function Hosting.postgres_spec() + logger.info("pg="..pg.." domain="..domain) + if pg == nil then + return nil + end + local spec = { + class = "org.postgresql.Driver" + url = "jdbc:postgresql://localhost:5432/"..domain + user = domain + password = Io.password + } + local db = database(pg) + local exists = db.query("select datname from pg_database where datname=?",domain)() ~= nil; + logger.info("exists "..exists) + if not exists then + db.update( [[create user "]]..spec.user..[[" with encrypted password ']]..spec.password..[[']] ) + db.update( [[create database "]]..domain..[[" owner "]]..spec.user..[["]] ) + end + db.close() + return spec +end + + + + + -- callback to luanhost code do_file "file:init.luan"
--- a/src/luan/modules/Utils.java Thu Sep 05 01:29:57 2019 -0600 +++ b/src/luan/modules/Utils.java Fri Sep 06 00:19:47 2019 -0600 @@ -104,6 +104,13 @@ return (String)val; } + public static String removeRequiredString(Map map,String key) throws LuanException { + String s = removeString(map,key); + if( s==null ) + throw new LuanException( "parameter '"+key+"' is required" ); + return s; + } + public static Number removeNumber(Map map,String key) throws LuanException { Object val = map.remove(key); if( val!=null && !(val instanceof Number) ) @@ -111,7 +118,7 @@ return (Number)val; } - public static Integer removeInt(Map map,String key) throws LuanException { + public static Integer removeInteger(Map map,String key) throws LuanException { Object val = map.remove(key); if( val==null ) return null; @@ -137,6 +144,20 @@ return (Boolean)val; } + public static LuanFunction removeFunction(Map map,String key) throws LuanException { + Object val = map.remove(key); + if( val!=null && !(val instanceof LuanFunction) ) + throw new LuanException( "parameter '"+key+"' must be a function but is a "+Luan.type(val) ); + return (LuanFunction)val; + } + + public static LuanFunction removeRequiredFunction(Map map,String key) throws LuanException { + LuanFunction fn = removeFunction(map,key); + if( fn==null ) + throw new LuanException( "parameter '"+key+"' is required" ); + return fn; + } + public static void checkEmpty(Map map) throws LuanException { if( !map.isEmpty() ) throw new LuanException( "unrecognized options: "+map );
--- a/src/luan/modules/logging/LuanLogger.java Thu Sep 05 01:29:57 2019 -0600 +++ b/src/luan/modules/logging/LuanLogger.java Fri Sep 06 00:19:47 2019 -0600 @@ -46,6 +46,15 @@ } } + public static Logger getLogger(Luan luan,Class cls) { + tl.set(luan); + try { + return LoggerFactory.getLogger(cls); + } finally { + tl.remove(); + } + } + public static Luan luan() { return tl.get(); }
--- a/src/luan/modules/lucene/Lucene.luan Thu Sep 05 01:29:57 2019 -0600 +++ b/src/luan/modules/lucene/Lucene.luan Fri Sep 06 00:19:47 2019 -0600 @@ -35,15 +35,16 @@ Lucene.literal = SaneQueryParser.literal -function Lucene.index(index_dir,default_type,default_fields,completer) +function Lucene.index(index_dir,default_type,default_fields,postgres_spec) type(index_dir)=="table" or error "index_dir must be table" index_dir.to_uri_string and matches(index_dir.to_uri_string(),"^file:") or error "must be file" + postgres_spec==nil or type(postgres_spec)=="table" or error "postgres_spec must be table" local index = {} index.dir = index_dir - local java_index, closer = LuceneIndex.getLuceneIndex(index_dir.java.file,default_type,default_fields,completer) + local java_index, closer = LuceneIndex.getLuceneIndex(index_dir.java.file,default_type,default_fields,postgres_spec) index.java = java_index index.closer = closer or error() - index.completer = completer + index.completer = postgres_spec and postgres_spec.completer index.indexed_fields = {} local mt = {}
--- a/src/luan/modules/lucene/LuceneIndex.java Thu Sep 05 01:29:57 2019 -0600 +++ b/src/luan/modules/lucene/LuceneIndex.java Fri Sep 06 00:19:47 2019 -0600 @@ -79,6 +79,7 @@ import luan.LuanException; import luan.LuanRuntimeException; import luan.modules.parsers.LuanToString; +import luan.modules.logging.LuanLogger; import luan.lib.logging.Logger; import luan.lib.logging.LoggerFactory; @@ -98,7 +99,11 @@ public void close() throws IOException { if( !isClosed ) { - li.close(); + try { + li.close(); + } catch(SQLException e) { + throw new RuntimeException(e); + } isClosed = true; } } @@ -114,14 +119,14 @@ private static Map<String,LuceneIndex> indexes = new HashMap<String,LuceneIndex>(); - public static Object[] getLuceneIndex(Luan luan,File indexDir,FieldParser defaultFieldParser,String[] defaultFields,LuanFunction completer) - throws LuanException, IOException + public static Object[] getLuceneIndex(Luan luan,File indexDir,FieldParser defaultFieldParser,String[] defaultFields,LuanTable postgresSpec) + throws LuanException, IOException, ClassNotFoundException, SQLException { String key = indexDir.getCanonicalPath(); synchronized(indexes) { LuceneIndex li = indexes.get(key); if( li == null ) { - li = new LuceneIndex(indexDir,defaultFieldParser,defaultFields,key,completer); + li = new LuceneIndex(luan,indexDir,defaultFieldParser,defaultFields,key,postgresSpec); li.openCount = 1; indexes.put(key,li); } else { @@ -163,9 +168,10 @@ private final PostgresBackup postgresBackup; - private LuceneIndex(File indexDir,FieldParser defaultFieldParser,String[] defaultFields,String key,LuanFunction completer) - throws LuanException, IOException + private LuceneIndex(Luan luan,File indexDir,FieldParser defaultFieldParser,String[] defaultFields,String key,LuanTable postgresSpec) + throws LuanException, IOException, ClassNotFoundException, SQLException { + final Logger logger = LuanLogger.getLogger(luan,LuceneIndex.class); this.key = key; this.defaultFieldParser = defaultFieldParser; this.defaultFields = defaultFields; @@ -180,14 +186,20 @@ } this.analyzer = analyzer; boolean wasCreated = reopen(); - postgresBackup = completer!=null ? PostgresBackup.newInstance() : null; - if( postgresBackup != null ) { - if( !wasCreated && postgresBackup.wasCreated ) { - logger.error("rebuilding postgres backup"); - rebuild_postgres_backup(completer); - } else if( wasCreated && !postgresBackup.wasCreated ) { - logger.error("restoring from postgres"); - restore_from_postgres(); + if( postgresSpec == null ) { + postgresBackup = null; + } else { + Map spec = postgresSpec.asMap(); + LuanFunction completer = Utils.removeRequiredFunction(spec,"completer"); + postgresBackup = new PostgresBackup(spec); + if( postgresBackup != null ) { + if( !wasCreated && postgresBackup.wasCreated ) { + logger.error("rebuilding postgres backup"); + rebuild_postgres_backup(completer); + } else if( wasCreated && !postgresBackup.wasCreated ) { + logger.error("restoring from postgres"); + restore_from_postgres(luan); + } } } } @@ -210,7 +222,7 @@ writeCounter.incrementAndGet(); } - public void delete_all() throws IOException { + public void delete_all() throws IOException, SQLException { boolean commit = !writeLock.isHeldByCurrentThread(); writeLock.lock(); try { @@ -232,7 +244,7 @@ } private void backupDelete(Query query) - throws IOException + throws IOException, SQLException, LuanException { if( postgresBackup != null ) { final List<Long> ids = new ArrayList<Long>(); @@ -258,7 +270,7 @@ } public void delete(String queryStr) - throws IOException, ParseException + throws IOException, ParseException, SQLException, LuanException { Query query = SaneQueryParser.parseQuery(mfp,queryStr); @@ -279,10 +291,10 @@ } public void save(LuanTable doc,LuanTable boosts) - throws LuanException, IOException + throws LuanException, IOException, SQLException { if( boosts!=null && postgresBackup!=null ) - logger.error("boosts are not saved to postgres backup"); + throw new LuanException("boosts are not saved to postgres backup"); Object obj = doc.get("id"); Long id; @@ -313,7 +325,9 @@ } } - public Object run_in_transaction(LuanFunction fn) throws IOException, LuanException { + public Object run_in_transaction(LuanFunction fn) + throws IOException, LuanException, SQLException + { boolean commit = !writeLock.isHeldByCurrentThread(); writeLock.lock(); boolean ok = false; @@ -433,7 +447,7 @@ return writer.getDirectory().toString(); } - private synchronized void close() throws IOException { + private synchronized void close() throws IOException, SQLException { if( openCount > 0 ) { if( --openCount == 0 ) { doClose(); @@ -444,11 +458,11 @@ } } - public void doClose() throws IOException { + public void doClose() throws IOException, SQLException { + writer.close(); + reader.close(); if( postgresBackup != null ) postgresBackup.close(); - writer.close(); - reader.close(); } @@ -806,8 +820,10 @@ } public void rebuild_postgres_backup(LuanFunction completer) - throws IOException, LuanException + throws IOException, LuanException, SQLException { + final Logger logger = LuanLogger.getLogger(completer.luan(),LuceneIndex.class); + logger.info("start rebuild_postgres_backup"); writeLock.lock(); IndexSearcher searcher = openSearcher(); boolean ok = false; @@ -824,6 +840,8 @@ postgresBackup.add(tbl); } catch(LuanException e) { throw new LuanRuntimeException(e); + } catch(SQLException e) { + throw new RuntimeException(e); } } }; @@ -840,11 +858,14 @@ postgresBackup.rollback(); writeLock.unlock(); } + logger.info("end rebuild_postgres_backup"); } - public void restore_from_postgres() - throws IOException, LuanException + public void restore_from_postgres(Luan luan) + throws IOException, LuanException, SQLException { + final Logger logger = LuanLogger.getLogger(luan,LuceneIndex.class); + logger.warn("start restore_from_postgres"); if( postgresBackup==null ) throw new NullPointerException(); if( writeLock.isHeldByCurrentThread() ) @@ -866,6 +887,7 @@ wrote(); writeLock.unlock(); } + logger.warn("end restore_from_postgres"); } void restore(LuanTable doc) @@ -875,6 +897,7 @@ } public void check(LuanFunction completer) throws IOException, SQLException, LuanException { + final Logger logger = LuanLogger.getLogger(completer.luan(),LuceneIndex.class); logger.info("start check"); CheckIndex.Status status = new CheckIndex(fsDir).checkIndex(); if( !status.clean ) @@ -885,6 +908,7 @@ } private void checkPostgres(LuanFunction completer) throws IOException, SQLException, LuanException { + final Logger logger = LuanLogger.getLogger(completer.luan(),LuceneIndex.class); final PostgresBackup.Checker postgresChecker; final IndexSearcher searcher; writeLock.lock();
--- a/src/luan/modules/lucene/PostgresBackup.java Thu Sep 05 01:29:57 2019 -0600 +++ b/src/luan/modules/lucene/PostgresBackup.java Fri Sep 06 00:19:47 2019 -0600 @@ -10,11 +10,14 @@ 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.modules.logging.LuanLogger; import luan.lib.logging.Logger; import luan.lib.logging.LoggerFactory; @@ -22,18 +25,6 @@ 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 String url; private final Properties props = new Properties(); @@ -44,14 +35,23 @@ private int trans = 0; private final LuanToString luanToString = new LuanToString(); - private PostgresBackup() - throws ClassNotFoundException, SQLException + PostgresBackup(Map spec) + throws ClassNotFoundException, SQLException, LuanException { +/* 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(); @@ -88,15 +88,11 @@ return DriverManager.getConnection(url,props); } - void close() { - try { - insertStmt.close(); - updateStmt.close(); - deleteStmt.close(); - con.close(); - } catch(SQLException e) { - logger.error("close failed",e); - } + void close() throws SQLException { + insertStmt.close(); + updateStmt.close(); + deleteStmt.close(); + con.close(); } protected void finalize() throws Throwable { @@ -107,90 +103,58 @@ } } - void add(LuanTable doc) throws LuanException { - try { - Long id = (Long)doc.get("id"); - String data = luanToString.toString(doc); - insertStmt.setLong(1,id); - insertStmt.setString(2,data); - insertStmt.executeUpdate(); - } catch(SQLException e) { - logger.error("add failed",e); - } + 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 { - try { - 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 ) { - logger.error("update not found for id="+id+", trying add"); - add(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 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 ) { + Logger logger = LuanLogger.getLogger(doc.luan(),PostgresBackup.class); + logger.error("update not found for id="+id+", trying add"); + add(doc); + } else if( n!=1 ) + throw new RuntimeException(); } - 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 deleteAll() throws SQLException { + Statement stmt = con.createStatement(); + stmt.executeUpdate("delete from lucene"); + stmt.close(); } - void begin() { - try { - if( trans++ == 0 ) - con.setAutoCommit(false); - } catch(SQLException e) { - logger.error("begin failed",e); - } + 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 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 begin() throws SQLException { + if( trans++ == 0 ) + con.setAutoCommit(false); } - void rollback() { - try { - if( --trans != 0 ) { - logger.error("rollback failed trans="+trans); - return; - } - con.rollback(); + void commit() throws SQLException, LuanException { + if( trans <= 0 ) + throw new LuanException("commit not in transaction"); + if( --trans == 0 ) con.setAutoCommit(true); - } catch(SQLException e) { - logger.error("begin failed",e); - } + } + + void rollback() throws SQLException, LuanException { + if( --trans != 0 ) + throw new LuanException("rollback failed trans="+trans); + con.rollback(); + con.setAutoCommit(true); } private static LuanTable newEnv() { @@ -205,38 +169,28 @@ } void restoreLucene(LuceneIndex li) - throws LuanException, IOException + throws LuanException, IOException, SQLException { - try { - 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(); - } catch(SQLException e) { - logger.error("restoreLucene failed",e); - throw new RuntimeException(e); + 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 + throws LuanException, IOException, SQLException { - 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); - } + 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 {
--- a/src/luan/modules/sql/Database.java Thu Sep 05 01:29:57 2019 -0600 +++ b/src/luan/modules/sql/Database.java Fri Sep 06 00:19:47 2019 -0600 @@ -14,6 +14,7 @@ import luan.Luan; import luan.LuanTable; import luan.LuanException; +import luan.modules.Utils; public final class Database { @@ -31,12 +32,14 @@ throws LuanException, ClassNotFoundException, SQLException { Map<Object,Object> spec = specTbl.asMap(); - String cls = getString(spec,"class"); + String cls = Utils.removeRequiredString(spec,"class"); Class.forName(cls); - String url = getString(spec,"url"); + String url = Utils.removeRequiredString(spec,"url"); Properties props = new Properties(); props.putAll(spec); this.con = DriverManager.getConnection(url,props); + spec.remove("user"); + spec.remove("password"); set(spec); } @@ -45,31 +48,13 @@ } private void set(Map<Object,Object> options) throws LuanException, SQLException { - Object obj; - obj = options.remove("auto_commit"); - if( obj != null ) { - if( !(obj instanceof Boolean) ) - throw new LuanException( "parameter 'auto_commit' must be a boolean" ); - con.setAutoCommit((Boolean)obj); - } - obj = options.remove("fetch_size"); - if( obj != null ) { - Integer n = Luan.asInteger(obj); - if( n == null ) - throw new LuanException( "parameter 'fetch_size' must be an integer" ); + Boolean autoCommit = Utils.removeBoolean(options,"auto_commit"); + if( autoCommit != null ) + con.setAutoCommit(autoCommit); + Integer n = Utils.removeInteger(options,"fetch_size"); + if( n != null ) fetchSize = n; - } - if( !options.isEmpty() ) - throw new LuanException( "unrecognized parameters: "+options ); - } - - private static String getString(Map spec,String key) throws LuanException { - Object val = spec.remove(key); - if( val==null ) - throw new LuanException( "parameter '"+key+"' is required" ); - if( !(val instanceof String) ) - throw new LuanException( "parameter '"+key+"' must be a string" ); - return (String)val; + Utils.checkEmpty(options); } private void fix(Statement stmt) throws SQLException {
--- a/src/luan/modules/url/LuanUrl.java Thu Sep 05 01:29:57 2019 -0600 +++ b/src/luan/modules/url/LuanUrl.java Fri Sep 06 00:19:47 2019 -0600 @@ -159,7 +159,7 @@ } } } - Integer timeout = Utils.removeInt(map,"time_out"); + Integer timeout = Utils.removeInteger(map,"time_out"); if( timeout != null ) this.timeout = timeout; Utils.checkEmpty(map);