@Override public Long lastReceivedLsn() { return lastReceivedLSN != null ? lastReceivedLSN.asLong() : null; }
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; }
private byte[] prepareUpdateStatus(LogSequenceNumber received, LogSequenceNumber flushed, LogSequenceNumber applied, boolean replyRequired) { ByteBuffer byteBuffer = ByteBuffer.allocate(1 + 8 + 8 + 8 + 8 + 1); long now = System.currentTimeMillis(); long systemClock = TimeUnit.MICROSECONDS.convert((now - POSTGRES_EPOCH_2000_01_01), TimeUnit.MICROSECONDS); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.log(Level.FINEST, " FE=> StandbyStatusUpdate(received: {0}, flushed: {1}, applied: {2}, clock: {3})", new Object[]{received.asString(), flushed.asString(), applied.asString(), new Date(now)}); } byteBuffer.put((byte) 'r'); byteBuffer.putLong(received.asLong()); byteBuffer.putLong(flushed.asLong()); byteBuffer.putLong(applied.asLong()); byteBuffer.putLong(systemClock); if (replyRequired) { byteBuffer.put((byte) 1); } else { byteBuffer.put(received == LogSequenceNumber.INVALID_LSN ? (byte) 1 : (byte) 0); } lastStatusUpdate = now; return byteBuffer.array(); }
/** * 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 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; }
@Override public void readPending(ReplicationMessageProcessor processor) throws SQLException, InterruptedException { ByteBuffer read = stream.readPending(); // the lsn we started from is inclusive, so we need to avoid sending back the same message twice if (read == null || lsnLong >= stream.getLastReceiveLSN().asLong()) { return; } deserializeMessages(read, processor); }
@Override public void read(ReplicationMessageProcessor processor) throws SQLException, InterruptedException { ByteBuffer read = stream.read(); // the lsn we started from is inclusive, so we need to avoid sending back the same message twice if (lsnLong >= stream.getLastReceiveLSN().asLong()) { return; } deserializeMessages(read, processor); }
xlogStart.compareAndSet(0, LogSequenceNumber.valueOf(xlogpos).asLong());
final long lsnLong = lsn.asLong(); return new ReplicationStream() { private static final int CHECK_WARNINGS_AFTER_COUNT = 100;
@Override public Long lastReceivedLsn() { return lastReceivedLSN != null ? lastReceivedLSN.asLong() : null; }
/** * 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 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; }
@Override public void readPending(ReplicationMessageProcessor processor) throws SQLException, InterruptedException { ByteBuffer read = stream.readPending(); // the lsn we started from is inclusive, so we need to avoid sending back the same message twice if (read == null || lsnLong >= stream.getLastReceiveLSN().asLong()) { return; } deserializeMessages(read, processor); }
@Override public void read(ReplicationMessageProcessor processor) throws SQLException, InterruptedException { ByteBuffer read = stream.read(); // the lsn we started from is inclusive, so we need to avoid sending back the same message twice if (lsnLong >= stream.getLastReceiveLSN().asLong()) { return; } deserializeMessages(read, processor); }
.parse(JSonMapper.fromJson(messageString, PostgresWalMessage.class), stream.getLastReceiveLSN().asLong(), replicationSlotName) .forEach(eventConsumer);
xlogStart.compareAndSet(0, LogSequenceNumber.valueOf(xlogpos).asLong());
private void receiveStream() throws SQLException { assert !stream.isClosed(); assert !connection.isClosed(); //non blocking receive message ByteBuffer msg = stream.readPending(); if (msg == null) { TimeUtils.sleepInMills(10L); return; } int offset = msg.arrayOffset(); byte[] source = msg.array(); int length = source.length - offset; LogSequenceNumber lsn = stream.getLastReceiveLSN(); InvokeContext ctx = new InvokeContext(); ctx.setMessage(new String(source, offset, length)); ctx.setJdbcUrl(this.jdbcConfig.getUrl()); ctx.setJdbcUser(this.jdbcConfig.getUsername()); ctx.setJdbcPass(this.jdbcConfig.getPassword()); ctx.setSlotName(this.slotName); ctx.setServerId(this.serverId); ctx.setLsn(lsn.asLong()); eventParser.parse(ctx); //feedback stream.setAppliedLSN(lsn); stream.setFlushedLSN(lsn); }
final long lsnLong = lsn.asLong(); return new ReplicationStream() { private static final int CHECK_WARNINGS_AFTER_COUNT = 100;