/** * {@inheritDoc} * * @see com.continuent.tungsten.replicator.storage.Store#status() */ @Override public TungstenProperties status() { TungstenProperties props = new TungstenProperties(); props.setLong(Replicator.MIN_STORED_SEQNO, getMinStoredSeqno()); props.setLong(Replicator.MAX_STORED_SEQNO, getMaxStoredSeqno()); props.setLong("activeSeqno", diskLog.getActiveSeqno()); props.setBoolean("doChecksum", doChecksum); props.setString("logDir", logDir); props.setInt("logFileSize", logFileSize); props.setLong("logFileRetainMillis", logFileRetainMillis); props.setLong("logFileSize", diskLog.getLogFileSize()); props.setLong("timeoutMillis", diskLog.getTimeoutMillis()); props.setBoolean("fsyncOnFlush", fsyncOnFlush); props.setLong("flushIntervalMillis", diskLog.getFlushIntervalMillis()); props.setLong("timeoutMillis", diskLog.getTimeoutMillis()); props.setLong("logConnectionTimeout", logConnectionTimeout); props.setBoolean("readOnly", readOnly); return props; }
/** * Get the last applied event. We first try the disk log then if that is absent try the catalog. * If there is nothing there we must be starting from scratch and return null. * * @return An event header or null if log is newly initialized * @throws InterruptedException * @throws ReplicatorException */ public ReplDBMSHeader getLastAppliedEvent() throws ReplicatorException, InterruptedException { // Look for maximum sequence number in log and use that if available. if (diskLog != null) { long maxSeqno = diskLog.getMaxSeqno(); if (maxSeqno > -1) { LogConnection conn = null; try { // Try to connect and find the event. THLEvent thlEvent = null; conn = diskLog.connect(true); conn.seek(maxSeqno); while ((thlEvent = conn.next(false)) != null && thlEvent.getSeqno() == maxSeqno) { // Return only the last fragment. if (thlEvent.getLastFrag()) { ReplEvent event = thlEvent.getReplEvent(); if (event instanceof ReplDBMSEvent) return (ReplDBMSEvent) event; else if (event instanceof ReplControlEvent) return ((ReplControlEvent) event).getHeader(); } } // If we did not find the last fragment of the event // we need to warn somebody. if (thlEvent != null) logger.warn("Unable to find last fragment of event: seqno=" + maxSeqno); } finally { conn.release(); } } } // If that does not work, try the catalog. if (catalog != null) { return catalog.getLastEvent(); } // If we get to this point, the log is newly initialized and there is no // such event to return. return null; }
/** * {@inheritDoc} * * @see * com.continuent.tungsten.replicator.plugin.ReplicatorPlugin#release(com.continuent.tungsten.replicator.plugin.PluginContext) */ public synchronized void release(PluginContext context) throws InterruptedException, ReplicatorException { // Cancel server. if (server != null) { try { server.stop(); } catch (InterruptedException e) { logger.warn("Server stop operation was unexpectedly interrupted", e); } finally { server = null; } } if (catalog != null) { catalog.close(); catalog = null; } if (diskLog != null) { diskLog.release(); diskLog = null; } }
/** Returns true if the indicated sequence number is available. */ public boolean pollSeqno(long seqno) { return seqno <= diskLog.getMaxSeqno(); }
/** * Connect to the log. Adapters must call this to use the log. * * @param readonly If true, this is a readonly connection * @return A disk log client */ public LogConnection connect(boolean readonly) throws ReplicatorException { return diskLog.connect(readonly); }
/** * {@inheritDoc} * * @see * com.continuent.tungsten.replicator.plugin.ReplicatorPlugin#prepare(com.continuent.tungsten.replicator.plugin.PluginContext) */ public synchronized void prepare(PluginContext context) throws ReplicatorException, InterruptedException { // Prepare database connection. if (url != null && url.trim().length() > 0) { logger.info("Preparing SQL catalog tables"); ReplicatorRuntime runtime = (ReplicatorRuntime) context; String metadataSchema = context.getReplicatorSchemaName(); catalog = new CatalogManager(runtime); catalog.connect(url, user, password, metadataSchema, vendor); catalog.prepareSchema(); } else logger.info("SQL catalog tables are disabled"); // Configure and prepare the log. diskLog = new DiskLog(); diskLog.setDoChecksum(doChecksum); diskLog.setEventSerializerClass(eventSerializer); diskLog.setLogDir(logDir); diskLog.setLogFileSize(logFileSize); diskLog.setLogFileRetainMillis(logFileRetainMillis); diskLog.setLogConnectionTimeoutMillis(logConnectionTimeout * 1000); diskLog.setBufferSize(bufferSize); diskLog.setFsyncOnFlush(fsyncOnFlush); if (fsyncOnFlush) { // Only used with fsync. diskLog.setFlushIntervalMillis(flushIntervalMillis); } diskLog.setReadOnly(readOnly); diskLog.prepare(); logger.info("Log preparation is complete"); // Start server for THL connections. if (context.isRemoteService() == false) { try { server = new Server(context, sequencer, this); server.start(); } catch (IOException e) { throw new ReplicatorException("Unable to start THL server", e); } } }
/** * Updates the active sequence number on the log. Log files can only be deleted if their last * sequence number is below this value. */ public void updateActiveSeqno(long activeSeqno) { diskLog.setActiveSeqno(activeSeqno); }
/** Return minimum stored sequence number. */ public long getMinStoredSeqno() { return diskLog.getMinSeqno(); }