/** * Formats a LSN long value as a String value which can be used for outputting user-friendly LSN values. * * @param lsn the LSN value * @return a String format of the value, never {@code null} */ static String format(long lsn) { return LogSequenceNumber.valueOf(lsn).asString(); }
@Override public void flushLsn(long lsn) throws SQLException { doFlushLsn(LogSequenceNumber.valueOf(lsn)); }
private ByteBuffer processXLogData(ByteBuffer buffer) { long startLsn = buffer.getLong(); lastServerLSN = LogSequenceNumber.valueOf(buffer.getLong()); long systemClock = buffer.getLong(); switch (replicationType) { case LOGICAL: lastReceiveLSN = LogSequenceNumber.valueOf(startLsn); break; case PHYSICAL: int payloadSize = buffer.limit() - buffer.position(); lastReceiveLSN = LogSequenceNumber.valueOf(startLsn + payloadSize); break; } if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.log(Level.FINEST, " <=BE XLogData(currWal: {0}, lastServerWal: {1}, clock: {2})", new Object[]{lastReceiveLSN.asString(), lastServerLSN.asString(), systemClock}); } return buffer.slice(); }
/** * Create LSN instance by string represent LSN. * * @param strValue not null string as two hexadecimal numbers of up to 8 digits each, separated by * a slash. For example {@code 16/3002D50}, {@code 0/15D68C50} * @return not null LSN instance where if specified string represent have not valid form {@link * LogSequenceNumber#INVALID_LSN} */ public static LogSequenceNumber valueOf(String strValue) { int slashIndex = strValue.lastIndexOf('/'); if (slashIndex <= 0) { return INVALID_LSN; } String logicalXLogStr = strValue.substring(0, slashIndex); int logicalXlog = (int) Long.parseLong(logicalXLogStr, 16); String segmentStr = strValue.substring(slashIndex + 1, strValue.length()); int segment = (int) Long.parseLong(segmentStr, 16); ByteBuffer buf = ByteBuffer.allocate(8); buf.putInt(logicalXlog); buf.putInt(segment); buf.position(0); long value = buf.getLong(); return LogSequenceNumber.valueOf(value); }
/** * Returns the current position in the server tx log. * * @return a long value, never negative * @throws SQLException if anything unexpected fails. */ public long currentXLogLocation() throws SQLException { AtomicLong result = new AtomicLong(0); int majorVersion = connection().getMetaData().getDatabaseMajorVersion(); query(majorVersion >= 10 ? "select * from pg_current_wal_lsn()" : "select * from pg_current_xlog_location()", rs -> { if (!rs.next()) { throw new IllegalStateException("there should always be a valid xlog position"); } result.compareAndSet(0, LogSequenceNumber.valueOf(rs.getString(1)).asLong()); }); return result.get(); }
private boolean processKeepAliveMessage(ByteBuffer buffer) { lastServerLSN = LogSequenceNumber.valueOf(buffer.getLong()); if (lastServerLSN.asLong() > lastReceiveLSN.asLong()) { lastReceiveLSN = lastServerLSN; } long lastServerClock = buffer.getLong(); boolean replyRequired = buffer.get() != 0; if (LOGGER.isLoggable(Level.FINEST)) { Date clockTime = new Date( TimeUnit.MILLISECONDS.convert(lastServerClock, TimeUnit.MICROSECONDS) + POSTGRES_EPOCH_2000_01_01); LOGGER.log(Level.FINEST, " <=BE Keepalive(lastServerWal: {0}, clock: {1} needReply: {2})", new Object[]{lastServerLSN.asString(), clockTime, replyRequired}); } return replyRequired; }
@Override public ReplicationStream startStreaming(Long offset) throws SQLException, InterruptedException { connect(); if (offset == null || offset <= 0) { offset = defaultStartingPos; } LogSequenceNumber lsn = LogSequenceNumber.valueOf(offset); LOGGER.debug("starting streaming from LSN '{}'", lsn.asString()); return createReplicationStream(lsn); }
@Override protected synchronized void commit(long lsn) { LoggingContext.PreviousContext previousContext = taskContext.configureLoggingContext(CONTEXT_NAME); try { ReplicationStream replicationStream = this.replicationStream.get(); if (replicationStream != null) { if (logger.isDebugEnabled()) { logger.debug("Flushing LSN to server: {}", LogSequenceNumber.valueOf(lsn)); } // tell the server the point up to which we've processed data, so it can be free to recycle WAL segments replicationStream.flushLsn(lsn); } else { logger.debug("Streaming has already stopped, ignoring commit callback..."); } } catch (SQLException e) { throw new ConnectException(e); } finally { previousContext.restore(); } }
private Long tryParseLsn(String slotName, String pluginName, String database, ResultSet rs, String column) throws ConnectException, SQLException { Long lsn = null; String lsnStr = rs.getString(column); if (lsnStr == null) { return null; } try { lsn = LogSequenceNumber.valueOf(lsnStr).asLong(); } catch (Exception e) { throw new ConnectException("Value " + column + " in the pg_replication_slots table for slot = '" + slotName + "', plugin = '" + pluginName + "', database = '" + database + "' is not valid. This is an abnormal situation and the database status should be checked."); } if (lsn == LogSequenceNumber.INVALID_LSN.asLong()) { throw new ConnectException("Invalid LSN returned from database"); } return lsn; }
xlogStart.compareAndSet(0, LogSequenceNumber.valueOf(xlogpos).asLong());
/** * Formats a LSN long value as a String value which can be used for outputting user-friendly LSN values. * * @param lsn the LSN value * @return a String format of the value, never {@code null} */ static String format(long lsn) { return LogSequenceNumber.valueOf(lsn).asString(); }
@Override public void flushLsn(long lsn) throws SQLException { doFlushLsn(LogSequenceNumber.valueOf(lsn)); }
/** * Returns the current position in the server tx log. * * @return a long value, never negative * @throws SQLException if anything unexpected fails. */ public long currentXLogLocation() throws SQLException { AtomicLong result = new AtomicLong(0); int majorVersion = connection().getMetaData().getDatabaseMajorVersion(); query(majorVersion >= 10 ? "select * from pg_current_wal_lsn()" : "select * from pg_current_xlog_location()", rs -> { if (!rs.next()) { throw new IllegalStateException("there should always be a valid xlog position"); } result.compareAndSet(0, LogSequenceNumber.valueOf(rs.getString(1)).asLong()); }); return result.get(); }
@Override public ReplicationStream startStreaming(Long offset) throws SQLException, InterruptedException { connect(); if (offset == null || offset <= 0) { offset = defaultStartingPos; } LogSequenceNumber lsn = LogSequenceNumber.valueOf(offset); LOGGER.debug("starting streaming from LSN '{}'", lsn.asString()); return createReplicationStream(lsn); }
@Override protected synchronized void commit(long lsn) { LoggingContext.PreviousContext previousContext = taskContext.configureLoggingContext(CONTEXT_NAME); try { ReplicationStream replicationStream = this.replicationStream.get(); if (replicationStream != null) { if (logger.isDebugEnabled()) { logger.debug("Flushing LSN to server: {}", LogSequenceNumber.valueOf(lsn)); } // tell the server the point up to which we've processed data, so it can be free to recycle WAL segments replicationStream.flushLsn(lsn); } else { logger.debug("Streaming has already stopped, ignoring commit callback..."); } } catch (SQLException e) { throw new ConnectException(e); } finally { previousContext.restore(); } }
private Long tryParseLsn(String slotName, String pluginName, String database, ResultSet rs, String column) throws ConnectException, SQLException { Long lsn = null; String lsnStr = rs.getString(column); if (lsnStr == null) { return null; } try { lsn = LogSequenceNumber.valueOf(lsnStr).asLong(); } catch (Exception e) { throw new ConnectException("Value " + column + " in the pg_replication_slots table for slot = '" + slotName + "', plugin = '" + pluginName + "', database = '" + database + "' is not valid. This is an abnormal situation and the database status should be checked."); } if (lsn == LogSequenceNumber.INVALID_LSN.asLong()) { throw new ConnectException("Invalid LSN returned from database"); } return lsn; }
.orElse(LogSequenceNumber.valueOf("0/0"));
xlogStart.compareAndSet(0, LogSequenceNumber.valueOf(xlogpos).asLong());