/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2001-2003 * Sleepycat Software. All rights reserved. * * $Id: DbServer.java,v 1.2 2004/03/30 01:24:00 jtownsen Exp $ */ package com.sleepycat.db.rpcserver; import com.sleepycat.db.*; import java.io.*; import java.util.*; import org.acplt.oncrpc.OncRpcException; import org.acplt.oncrpc.server.OncRpcCallInformation; /** * Main entry point for the Java version of the Berkeley DB RPC server */ public class DbServer extends DbDispatcher { public static long idleto = 10 * 60 * 1000; // 5 minutes public static long defto = 5 * 60 * 1000; // 5 minutes public static long maxto = 60 * 60 * 1000; // 1 hour public static String passwd = null; public static PrintWriter err; long now, hint; // updated each operation FreeList env_list = new FreeList(); FreeList db_list = new FreeList(); FreeList txn_list = new FreeList(); FreeList cursor_list = new FreeList(); public DbServer() throws IOException, OncRpcException { super(); init_lists(); } public void dispatchOncRpcCall(OncRpcCallInformation call, int program, int version, int procedure) throws OncRpcException, IOException { long newnow = System.currentTimeMillis(); // DbServer.err.println("Dispatching RPC call " + procedure + " after delay of " + (newnow - now)); now = newnow; try { super.dispatchOncRpcCall(call, program, version, procedure); } catch(Throwable t) { System.err.println("Caught " + t + " while dispatching RPC call " + procedure); t.printStackTrace(DbServer.err); } finally { doTimeouts(); DbServer.err.flush(); } } // Internal methods to track context private void init_lists() { // We do this so that getEnv/Db/etc(0) == null env_list.add(null); db_list.add(null); txn_list.add(null); cursor_list.add(null); } int addEnv(RpcDbEnv rdbenv) { rdbenv.timer.last_access = now; int id = env_list.add(rdbenv); return id; } int addDb(RpcDb rdb) { int id = db_list.add(rdb); return id; } int addTxn(RpcDbTxn rtxn) { rtxn.timer.last_access = now; int id = txn_list.add(rtxn); return id; } int addCursor(RpcDbc rdbc) { rdbc.timer.last_access = now; int id = cursor_list.add(rdbc); return id; } void delEnv(RpcDbEnv rdbenv, boolean dispose) { env_list.del(rdbenv); // cursors and transactions will already have been cleaned up for(LocalIterator i = db_list.iterator(); i.hasNext(); ) { RpcDb rdb = (RpcDb)i.next(); if (rdb != null && rdb.rdbenv == rdbenv) delDb(rdb, true); } if (dispose) rdbenv.dispose(); } void delDb(RpcDb rdb, boolean dispose) { db_list.del(rdb); for(LocalIterator i = cursor_list.iterator(); i.hasNext(); ) { RpcDbc rdbc = (RpcDbc)i.next(); if (rdbc != null && rdbc.timer == rdb) { i.remove(); rdbc.dispose(); } } if (dispose) rdb.dispose(); } void delTxn(RpcDbTxn rtxn, boolean dispose) { txn_list.del(rtxn); for(LocalIterator i = cursor_list.iterator(); i.hasNext(); ) { RpcDbc rdbc = (RpcDbc)i.next(); if (rdbc != null && rdbc.timer == rtxn) { i.remove(); rdbc.dispose(); } } for(LocalIterator i = txn_list.iterator(); i.hasNext(); ) { RpcDbTxn rtxn_child = (RpcDbTxn)i.next(); if (rtxn_child != null && rtxn_child.timer == rtxn) { i.remove(); rtxn_child.dispose(); } } if (dispose) rtxn.dispose(); } void delCursor(RpcDbc rdbc, boolean dispose) { cursor_list.del(rdbc); if (dispose) rdbc.dispose(); } RpcDbEnv getEnv(int envid) { RpcDbEnv rdbenv = (RpcDbEnv)env_list.get(envid); if (rdbenv != null) rdbenv.timer.last_access = now; return rdbenv; } RpcDb getDb(int dbid) { RpcDb rdb = (RpcDb)db_list.get(dbid); if (rdb != null) rdb.rdbenv.timer.last_access = now; return rdb; } RpcDbTxn getTxn(int txnid) { RpcDbTxn rtxn = (RpcDbTxn)txn_list.get(txnid); if (rtxn != null) rtxn.timer.last_access = rtxn.rdbenv.timer.last_access = now; return rtxn; } RpcDbc getCursor(int dbcid) { RpcDbc rdbc = (RpcDbc)cursor_list.get(dbcid); if (rdbc != null) rdbc.last_access = rdbc.timer.last_access = rdbc.rdbenv.timer.last_access = now; return rdbc; } void doTimeouts() { if (now < hint) { // DbServer.err.println("Skipping cleaner sweep - now = " + now + ", hint = " + hint); return; } // DbServer.err.println("Starting a cleaner sweep"); hint = now + DbServer.maxto; for(LocalIterator i = cursor_list.iterator(); i.hasNext(); ) { RpcDbc rdbc = (RpcDbc)i.next(); if (rdbc == null) continue; long end_time = rdbc.timer.last_access + rdbc.rdbenv.timeout; // DbServer.err.println("Examining " + rdbc + ", time left = " + (end_time - now)); if (end_time < now) { DbServer.err.println("Cleaning up " + rdbc); delCursor(rdbc, true); } else if (end_time < hint) hint = end_time; } for(LocalIterator i = txn_list.iterator(); i.hasNext(); ) { RpcDbTxn rtxn = (RpcDbTxn)i.next(); if (rtxn == null) continue; long end_time = rtxn.timer.last_access + rtxn.rdbenv.timeout; // DbServer.err.println("Examining " + rtxn + ", time left = " + (end_time - now)); if (end_time < now) { DbServer.err.println("Cleaning up " + rtxn); delTxn(rtxn, true); } else if (end_time < hint) hint = end_time; } for(LocalIterator i = env_list.iterator(); i.hasNext(); ) { RpcDbEnv rdbenv = (RpcDbEnv)i.next(); if (rdbenv == null) continue; long end_time = rdbenv.timer.last_access + rdbenv.idletime; // DbServer.err.println("Examining " + rdbenv + ", time left = " + (end_time - now)); if (end_time < now) { DbServer.err.println("Cleaning up " + rdbenv); delEnv(rdbenv, true); } } // if we didn't find anything, reset the hint if (hint == now + DbServer.maxto) hint = 0; // DbServer.err.println("Finishing a cleaner sweep"); } // Some constants that aren't available elsewhere static final int EINVAL = 22; static final int DB_SERVER_FLAGMASK = Db.DB_LOCKDOWN | Db.DB_PRIVATE | Db.DB_RECOVER | Db.DB_RECOVER_FATAL | Db.DB_SYSTEM_MEM | Db.DB_USE_ENVIRON | Db.DB_USE_ENVIRON_ROOT; static final int DB_SERVER_ENVFLAGS = Db.DB_INIT_CDB | Db.DB_INIT_LOCK | Db.DB_INIT_LOG | Db.DB_INIT_MPOOL | Db.DB_INIT_TXN | Db.DB_JOINENV; static final int DB_SERVER_DBFLAGS = Db.DB_DIRTY_READ | Db.DB_NOMMAP | Db.DB_RDONLY; static final int DB_SERVER_DBNOSHARE = Db.DB_EXCL | Db.DB_TRUNCATE; static Vector homes = new Vector(); static void add_home(String home) { File f = new File(home); try { home = f.getCanonicalPath(); } catch(IOException e) {} homes.addElement(home); } static boolean check_home(String home) { if (home == null) return false; File f = new File(home); try { home = f.getCanonicalPath(); } catch(IOException e) {} return homes.contains(home); } public static void main(String[] args) { System.out.println("Starting DbServer..."); for (int i = 0; i < args.length; i++) { if (args[i].charAt(0) != '-') usage(); switch (args[i].charAt(1)) { case 'h': add_home(args[++i]); break; case 'I': idleto = Long.parseLong(args[++i]) * 1000L; break; case 'P': passwd = args[++i]; break; case 't': defto = Long.parseLong(args[++i]) * 1000L; break; case 'T': maxto = Long.parseLong(args[++i]) * 1000L; break; case 'V': // version; break; case 'v': // verbose break; default: usage(); } } try { DbServer.err = new PrintWriter(new FileOutputStream("JavaRPCServer.trace", true)); // DbServer.err = new PrintWriter(System.err); DbServer server = new DbServer(); server.run(); } catch (Throwable e) { System.out.println("DbServer exception:"); e.printStackTrace(DbServer.err); } finally { if (DbServer.err != null) DbServer.err.close(); } System.out.println("DbServer stopped."); } static void usage() { System.err.println("usage: java com.sleepycat.db.rpcserver.DbServer \\"); System.err.println("[-Vv] [-h home] [-P passwd] [-I idletimeout] [-L logfile] [-t def_timeout] [-T maxtimeout]"); System.exit(1); } }