From fe23abdde630cf73bb7999c0513100bc069b643e Mon Sep 17 00:00:00 2001 From: lishanglin Date: Thu, 7 Mar 2024 19:04:22 +0800 Subject: [PATCH] keeper support fsync with rordb (#772) Co-authored-by: lishanglin --- .../com/ctrip/xpipe/cache/TimeBoundCache.java | 76 +++++ .../payload/ByteArrayOutputStreamPayload.java | 1 - .../redis/checker/cache/TimeBoundCache.java | 57 ---- .../redis/console/cache/impl/DcCacheImpl.java | 2 +- .../config/impl/DefaultConsoleDbConfig.java | 2 +- .../api/migrate/MigrationInfoApi.java | 2 +- .../resources/AbstractPersistenceCache.java | 2 +- .../console/resources/DefaultMetaCache.java | 2 +- .../resources/DefaultOuterClientCache.java | 2 +- .../impl/DefaultSentinelBalanceService.java | 2 +- .../ctrip/xpipe/redis/core/protocal/CAPA.java | 3 +- .../redis/core/protocal/PsyncObserver.java | 5 +- .../protocal/cmd/AbstractConfigCommand.java | 3 +- .../cmd/AbstractReplicationStorePsync.java | 26 +- .../core/protocal/cmd/ConfigGetCommand.java | 53 +++- .../redis/core/redis/rdb/RdbConstant.java | 13 + .../redis/core/redis/rdb/RdbParseContext.java | 16 +- .../core/redis/rdb/RdbParseListener.java | 4 +- .../redis/rdb/parser/AbstractRdbParser.java | 5 +- .../redis/rdb/parser/AuxOnlyRdbParser.java | 3 +- .../rdb/parser/DefaultRdbParseContext.java | 4 + .../redis/rdb/parser/DefaultRdbParser.java | 12 +- .../redis/core/store/DumpedRdbStore.java | 10 +- .../redis/core/store/FULLSYNC_FAIL_CAUSE.java | 3 +- .../redis/core/store/FullSyncListener.java | 2 + .../xpipe/redis/core/store/MetaStore.java | 6 +- .../xpipe/redis/core/store/RdbDumpState.java | 1 + .../xpipe/redis/core/store/RdbStore.java | 19 +- .../redis/core/store/RdbStoreListener.java | 2 - .../redis/core/store/ReplicationStore.java | 14 +- .../core/store/ReplicationStoreMeta.java | 82 +++-- .../xpipe/redis/core/AbstractRedisTest.java | 35 +++ .../core/protocal/cmd/DefaultPsyncTest.java | 6 +- .../protocal/cmd/PartialOnlyPsyncTest.java | 6 +- .../rdb/parser/AuxOnlyRdbParserTest.java | 3 +- .../rdb/parser/DefaultRdbParserTest.java | 3 +- .../redis/rdb/parser/ManualRdbParseTest.java | 7 +- .../core/server/AbstractRedisAction.java | 16 + .../redis/core/server/FakeRedisServer.java | 39 ++- .../core/server/FakeRedisServerAction.java | 43 ++- .../core/store/ReplicationStoreMetaTest.java | 25 -- .../redis/core/utils/SimplePsyncObserver.java | 8 +- .../keeper/KeeperFastStateChangeTest.java | 4 + .../integratedtest/keeper/TwoKeepers.java | 1 + .../keeper/manul/GtidKeeperTest.java | 4 +- .../ctrip/xpipe/redis/keeper/RdbDumper.java | 7 +- .../ctrip/xpipe/redis/keeper/RedisMaster.java | 5 +- .../redis/keeper/RedisMasterReplication.java | 2 + .../ctrip/xpipe/redis/keeper/RedisSlave.java | 5 +- .../ctrip/xpipe/redis/keeper/SLAVE_STATE.java | 1 - .../xsync/DefaultCommandDispatcher.java | 8 +- .../redis/keeper/config/TestKeeperConfig.java | 2 +- .../keeper/handler/CommandHandlerManager.java | 7 +- .../keeper/handler/keeper/ConfigHandler.java | 47 +++ .../redis/keeper/impl/AbstractRdbDumper.java | 44 +-- .../impl/AbstractRedisMasterReplication.java | 50 +-- .../keeper/impl/DefaultRedisKeeperServer.java | 113 ++++--- .../redis/keeper/impl/DefaultRedisMaster.java | 50 ++- .../impl/DefaultRedisMasterReplication.java | 7 + .../redis/keeper/impl/DefaultRedisSlave.java | 24 +- .../impl/RdbonlyRedisMasterReplication.java | 24 +- .../keeper/impl/RedisMasterNewRdbDumper.java | 20 +- .../impl/RedisMasterReplicationRdbDumper.java | 5 + ...yBucketBasedMasterReplicationListener.java | 8 +- .../keeper/store/DefaultDumpedRdbStore.java | 11 +- .../keeper/store/DefaultFullSyncListener.java | 7 + .../redis/keeper/store/DefaultRdbStore.java | 43 ++- .../keeper/store/DefaultReplicationStore.java | 295 +++++++++++------- .../keeper/store/DumpedGtidRdbStore.java | 12 +- .../redis/keeper/store/FullSyncContext.java | 10 + .../redis/keeper/store/GtidCommandStore.java | 1 + .../redis/keeper/store/GtidRdbStore.java | 28 +- .../keeper/store/GtidReplicationStore.java | 62 +--- .../keeper/store/RdbOnlyReplicationStore.java | 45 ++- .../keeper/store/meta/AbstractMetaStore.java | 47 +++ .../keeper/store/meta/DefaultMetaStore.java | 55 +++- .../redis/keeper/AbstractFakeRedisTest.java | 18 +- .../redis/keeper/AbstractRedisKeeperTest.java | 6 +- .../ctrip/xpipe/redis/keeper/AllTests.java | 3 + .../handler/keeper/ConfigHandlerTest.java | 67 ++++ .../keeper/impl/AbstractRdbDumperTest.java | 10 +- .../RdbonlyRedisMasterReplicationTest.java | 10 +- .../impl/RedisMasterNewRdbDumperTest.java | 6 +- .../impl/RordbReplicationSupportTest.java | 274 ++++++++++++++++ ...disKeeperServerConnectToFakeRedisTest.java | 6 +- .../fakeredis/FakeRedisExceptionTest.java | 8 +- .../redis/keeper/protocal/cmd/PsyncTest.java | 187 +++++++---- .../redis/keeper/ratelimit/RateLimitTest.java | 1 + .../store/DefaultRdbStoreEofMarkTest.java | 4 +- .../keeper/store/DefaultRdbStoreTest.java | 2 +- .../DefaultReplicationStoreManagerTest.java | 6 +- .../store/DefaultReplicationStoreTest.java | 29 +- .../manual/GtidReplicationManualTest.java | 3 +- 93 files changed, 1641 insertions(+), 678 deletions(-) create mode 100644 core/src/main/java/com/ctrip/xpipe/cache/TimeBoundCache.java delete mode 100644 redis/redis-checker/src/main/java/com/ctrip/xpipe/redis/checker/cache/TimeBoundCache.java create mode 100644 redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/handler/keeper/ConfigHandler.java create mode 100644 redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/handler/keeper/ConfigHandlerTest.java create mode 100644 redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/RordbReplicationSupportTest.java diff --git a/core/src/main/java/com/ctrip/xpipe/cache/TimeBoundCache.java b/core/src/main/java/com/ctrip/xpipe/cache/TimeBoundCache.java new file mode 100644 index 000000000..8e4579835 --- /dev/null +++ b/core/src/main/java/com/ctrip/xpipe/cache/TimeBoundCache.java @@ -0,0 +1,76 @@ +package com.ctrip.xpipe.cache; + +import java.util.function.LongSupplier; +import java.util.function.Supplier; + +/** + * @author lishanglin + * date 2021/4/17 + */ +public class TimeBoundCache { + + private T data; + + private long lastRefreshAt; + + private long expiredAt; + + private LongSupplier timeoutMillSupplier; + + private Supplier dataSupplier; + + public TimeBoundCache(LongSupplier timeoutMillSupplier, Supplier dataSupplier) { + this.data = null; + this.expiredAt = 0L; + this.lastRefreshAt = 0L; + this.timeoutMillSupplier = timeoutMillSupplier; + this.dataSupplier = dataSupplier; + } + + // allow data timeout + public T getCurrentData() { + return this.data; + } + + public T getData() { + return getData(false); + } + + public T getData(boolean disableCache) { + long current = System.currentTimeMillis(); + if (current < lastRefreshAt) { + // system time roll back + resetExpireAt(); + } + + if (!disableCache && null != data && expiredAt > current) { + return data; + } + + synchronized (this) { + if (!disableCache && null != data && expiredAt > current) return data; + data = dataSupplier.get(); + refreshExpireAt(); + return data; + } + } + + public synchronized void refresh() { + this.data = dataSupplier.get(); + refreshExpireAt(); + } + + private void resetExpireAt() { + this.lastRefreshAt = 0L; + this.expiredAt = 0L; + } + + private void refreshExpireAt() { + long timeout = timeoutMillSupplier.getAsLong(); + this.lastRefreshAt = System.currentTimeMillis(); + this.expiredAt = lastRefreshAt + timeout; + // expiredAt exceeds max long + if (this.expiredAt < timeout) this.expiredAt = Long.MAX_VALUE; + } + +} diff --git a/core/src/main/java/com/ctrip/xpipe/payload/ByteArrayOutputStreamPayload.java b/core/src/main/java/com/ctrip/xpipe/payload/ByteArrayOutputStreamPayload.java index b80e48b27..5c028ebb7 100644 --- a/core/src/main/java/com/ctrip/xpipe/payload/ByteArrayOutputStreamPayload.java +++ b/core/src/main/java/com/ctrip/xpipe/payload/ByteArrayOutputStreamPayload.java @@ -1,7 +1,6 @@ package com.ctrip.xpipe.payload; import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; import java.io.IOException; import java.nio.ByteBuffer; diff --git a/redis/redis-checker/src/main/java/com/ctrip/xpipe/redis/checker/cache/TimeBoundCache.java b/redis/redis-checker/src/main/java/com/ctrip/xpipe/redis/checker/cache/TimeBoundCache.java deleted file mode 100644 index 1689b528d..000000000 --- a/redis/redis-checker/src/main/java/com/ctrip/xpipe/redis/checker/cache/TimeBoundCache.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.ctrip.xpipe.redis.checker.cache; - -import java.util.function.LongSupplier; -import java.util.function.Supplier; - -/** - * @author lishanglin - * date 2021/4/17 - */ -public class TimeBoundCache { - - private T data; - - private long expiredAt; - - private LongSupplier timeoutMillSupplier; - - private Supplier dataSupplier; - - public TimeBoundCache(LongSupplier timeoutMillSupplier, Supplier dataSupplier) { - this.data = null; - this.expiredAt = 0L; - this.timeoutMillSupplier = timeoutMillSupplier; - this.dataSupplier = dataSupplier; - } - - // allow data timeout - public T getCurrentData() { - return this.data; - } - - public T getData() { - return getData(false); - } - - public T getData(boolean disableCache) { - if (!disableCache && null != data && expiredAt > System.currentTimeMillis()) { - return data; - } - - synchronized (this) { - if (!disableCache && null != data && expiredAt > System.currentTimeMillis()) return data; - this.data = dataSupplier.get(); - long timeout = timeoutMillSupplier.getAsLong(); - this.expiredAt = System.currentTimeMillis() + timeout; - // expiredAt exceeds max long - if (this.expiredAt < timeout) this.expiredAt = Long.MAX_VALUE; - return this.data; - } - } - - public synchronized void refresh() { - this.data = dataSupplier.get(); - this.expiredAt = System.currentTimeMillis() + timeoutMillSupplier.getAsLong(); - } - -} diff --git a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/cache/impl/DcCacheImpl.java b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/cache/impl/DcCacheImpl.java index 413bc23d0..7393ce9c9 100644 --- a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/cache/impl/DcCacheImpl.java +++ b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/cache/impl/DcCacheImpl.java @@ -1,6 +1,6 @@ package com.ctrip.xpipe.redis.console.cache.impl; -import com.ctrip.xpipe.redis.checker.cache.TimeBoundCache; +import com.ctrip.xpipe.cache.TimeBoundCache; import com.ctrip.xpipe.redis.console.cache.DcCache; import com.ctrip.xpipe.redis.console.config.ConsoleConfig; import com.ctrip.xpipe.redis.console.model.DcTbl; diff --git a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/config/impl/DefaultConsoleDbConfig.java b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/config/impl/DefaultConsoleDbConfig.java index 88ae36f6e..70a3475b3 100644 --- a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/config/impl/DefaultConsoleDbConfig.java +++ b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/config/impl/DefaultConsoleDbConfig.java @@ -2,7 +2,7 @@ import com.ctrip.xpipe.config.AbstractConfigBean; import com.ctrip.xpipe.redis.checker.alert.AlertDbConfig; -import com.ctrip.xpipe.redis.checker.cache.TimeBoundCache; +import com.ctrip.xpipe.cache.TimeBoundCache; import com.ctrip.xpipe.redis.console.config.ConsoleConfig; import com.ctrip.xpipe.redis.console.config.ConsoleDbConfig; import com.ctrip.xpipe.redis.console.model.ConfigModel; diff --git a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/controller/api/migrate/MigrationInfoApi.java b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/controller/api/migrate/MigrationInfoApi.java index 0915535d2..d0c8c110e 100644 --- a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/controller/api/migrate/MigrationInfoApi.java +++ b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/controller/api/migrate/MigrationInfoApi.java @@ -1,6 +1,6 @@ package com.ctrip.xpipe.redis.console.controller.api.migrate; -import com.ctrip.xpipe.redis.checker.cache.TimeBoundCache; +import com.ctrip.xpipe.cache.TimeBoundCache; import com.ctrip.xpipe.redis.console.config.ConsoleConfig; import com.ctrip.xpipe.redis.console.controller.AbstractConsoleController; import com.ctrip.xpipe.redis.console.controller.api.migrate.meta.MigrationProgress; diff --git a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/resources/AbstractPersistenceCache.java b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/resources/AbstractPersistenceCache.java index da6588433..a988c1a8b 100644 --- a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/resources/AbstractPersistenceCache.java +++ b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/resources/AbstractPersistenceCache.java @@ -1,7 +1,7 @@ package com.ctrip.xpipe.redis.console.resources; import com.ctrip.xpipe.redis.checker.PersistenceCache; -import com.ctrip.xpipe.redis.checker.cache.TimeBoundCache; +import com.ctrip.xpipe.cache.TimeBoundCache; import com.ctrip.xpipe.redis.checker.config.CheckerConfig; import com.ctrip.xpipe.utils.VisibleForTesting; import org.slf4j.Logger; diff --git a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/resources/DefaultMetaCache.java b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/resources/DefaultMetaCache.java index f7ba92cf2..fe967d24a 100644 --- a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/resources/DefaultMetaCache.java +++ b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/resources/DefaultMetaCache.java @@ -3,7 +3,7 @@ import com.ctrip.xpipe.api.monitor.Task; import com.ctrip.xpipe.api.monitor.TransactionMonitor; import com.ctrip.xpipe.concurrent.AbstractExceptionLogTask; -import com.ctrip.xpipe.redis.checker.cache.TimeBoundCache; +import com.ctrip.xpipe.cache.TimeBoundCache; import com.ctrip.xpipe.redis.console.cluster.ConsoleLeaderAware; import com.ctrip.xpipe.redis.console.config.ConsoleConfig; import com.ctrip.xpipe.redis.console.exception.DataNotFoundException; diff --git a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/resources/DefaultOuterClientCache.java b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/resources/DefaultOuterClientCache.java index e11c8a285..43f0eab79 100644 --- a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/resources/DefaultOuterClientCache.java +++ b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/resources/DefaultOuterClientCache.java @@ -5,7 +5,7 @@ import com.ctrip.xpipe.api.migration.OuterClientService; import com.ctrip.xpipe.lifecycle.AbstractLifecycle; import com.ctrip.xpipe.redis.checker.OuterClientCache; -import com.ctrip.xpipe.redis.checker.cache.TimeBoundCache; +import com.ctrip.xpipe.cache.TimeBoundCache; import com.ctrip.xpipe.redis.console.config.ConsoleConfig; import com.ctrip.xpipe.utils.XpipeThreadFactory; import com.ctrip.xpipe.utils.job.DynamicDelayPeriodTask; diff --git a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/sentinel/impl/DefaultSentinelBalanceService.java b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/sentinel/impl/DefaultSentinelBalanceService.java index b6f139564..4c453878b 100644 --- a/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/sentinel/impl/DefaultSentinelBalanceService.java +++ b/redis/redis-console/src/main/java/com/ctrip/xpipe/redis/console/sentinel/impl/DefaultSentinelBalanceService.java @@ -1,7 +1,7 @@ package com.ctrip.xpipe.redis.console.sentinel.impl; import com.ctrip.xpipe.cluster.ClusterType; -import com.ctrip.xpipe.redis.checker.cache.TimeBoundCache; +import com.ctrip.xpipe.cache.TimeBoundCache; import com.ctrip.xpipe.redis.console.config.ConsoleConfig; import com.ctrip.xpipe.redis.console.model.SentinelGroupModel; import com.ctrip.xpipe.redis.console.sentinel.SentinelBalanceService; diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/CAPA.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/CAPA.java index 141fef032..5849a6dd1 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/CAPA.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/CAPA.java @@ -8,7 +8,8 @@ public enum CAPA { EOF, - PSYNC2; + PSYNC2, + RORDB; public static CAPA of(String capaString) { diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/PsyncObserver.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/PsyncObserver.java index 604c091d6..6c7c35b82 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/PsyncObserver.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/PsyncObserver.java @@ -4,6 +4,7 @@ import com.ctrip.xpipe.redis.core.store.RdbStore; import java.io.IOException; +import java.util.Map; /** * @author wenchao.meng @@ -28,9 +29,7 @@ public interface PsyncObserver { */ void beginWriteRdb(EofType eofType, String replId, long masterRdbOffset) throws IOException; - void readRdbGtidSet(RdbStore rdbStore, String gtidSet); - - void readAuxEnd(RdbStore rdbStore); + void readAuxEnd(RdbStore rdbStore, Map auxMap); void endWriteRdb(); diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/cmd/AbstractConfigCommand.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/cmd/AbstractConfigCommand.java index a0bf8e247..eeef2c3e3 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/cmd/AbstractConfigCommand.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/cmd/AbstractConfigCommand.java @@ -32,7 +32,8 @@ public static enum REDIS_CONFIG_TYPE{ DISKLESS_SYNC_DELAY("repl-diskless-sync-delay"), SLAVE_READONLY("slave-read-only"), - SLAVE_REPL_ALL("slave-repl-all")//extend for xredis + SLAVE_REPL_ALL("slave-repl-all"), //extend for xredis + RORDB_SYNC("swap-repl-rordb-sync") // extend for ror ; private String configName; diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/cmd/AbstractReplicationStorePsync.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/cmd/AbstractReplicationStorePsync.java index d064686f4..eacba27f8 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/cmd/AbstractReplicationStorePsync.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/cmd/AbstractReplicationStorePsync.java @@ -15,10 +15,9 @@ import io.netty.buffer.ByteBuf; import java.io.IOException; +import java.util.Map; import java.util.concurrent.ScheduledExecutorService; -import static com.ctrip.xpipe.redis.core.redis.rdb.RdbConstant.REDIS_RDB_AUX_KEY_GTID; - /** * @author marsqing * @@ -98,7 +97,7 @@ protected RdbBulkStringParser createRdbReader() { @Override protected void beginReadRdb(EofType eofType) { try { - rdbStore = currentReplicationStore.beginRdb(replId, masterRdbOffset, eofType); + rdbStore = currentReplicationStore.prepareRdb(replId, masterRdbOffset, eofType); inOutPayloadReplicationStore.setRdbStore(rdbStore); super.beginReadRdb(eofType); } catch (IOException e) { @@ -129,38 +128,21 @@ public void onRedisOp(RedisOp redisOp) { @Override public void onAux(String key, String value) { - //this part should be in AbstractPsync - if (REDIS_RDB_AUX_KEY_GTID.equalsIgnoreCase(key)) { - readRdbGtidSet(value); - } } @Override - public void onAuxFinish() { + public void onAuxFinish(Map auxMap) { getLogger().info("[onAuxFinish] aux is finish"); for (PsyncObserver observer : observers) { try { - observer.readAuxEnd(rdbStore); + observer.readAuxEnd(rdbStore, auxMap); } catch (Throwable th) { getLogger().error("[onAuxFinish]" + this, th); } } } - protected void readRdbGtidSet(String gtidSet) { - - getLogger().info("[readRdbGtidSet]{}, gtidset:{}", this, gtidSet); - - for (PsyncObserver observer : observers) { - try { - observer.readRdbGtidSet(rdbStore, gtidSet); - } catch (Throwable th) { - getLogger().error("[readRdbGtidSet]" + this, th); - } - } - } - @Override public void onFinish(RdbParser parser) { diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/cmd/ConfigGetCommand.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/cmd/ConfigGetCommand.java index e9e9eb005..ed4824379 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/cmd/ConfigGetCommand.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/protocal/cmd/ConfigGetCommand.java @@ -37,7 +37,7 @@ protected T format(Object payload) { @Override public ByteBuf getRequest() { - return new RequestStringParser(CONFIG, " get " + getConfigName()).format(); + return new RequestStringParser(CONFIG, "get", getConfigName()).format(); } protected abstract String getConfigName(); @@ -65,21 +65,26 @@ protected String getConfigName() { } } - public static class ConfigGetDisklessSync extends ConfigGetCommand{ + public static abstract class ConfigGetBool extends ConfigGetCommand { - public ConfigGetDisklessSync(SimpleObjectPool clientPool, ScheduledExecutorService scheduled) { + public ConfigGetBool(SimpleObjectPool clientPool, ScheduledExecutorService scheduled) { super(clientPool, scheduled); } - public ConfigGetDisklessSync(SimpleObjectPool clientPool, ScheduledExecutorService scheduled, - int commandTimeoutMilli) { + public ConfigGetBool(SimpleObjectPool clientPool, ScheduledExecutorService scheduled, + int commandTimeoutMilli) { super(clientPool, scheduled, commandTimeoutMilli); } + protected Boolean defaultValue() { + return null; + } + @Override protected Boolean doFormat(Object[] payload) { - + if(payload.length < 2){ + if (null != defaultValue()) return defaultValue(); throw new IllegalStateException(getName() + " result length not right:" + payload.length); } String result = payloadToString(payload[1]); @@ -89,9 +94,45 @@ protected Boolean doFormat(Object[] payload) { if(result.equalsIgnoreCase("no")){ return false; } + if (null != defaultValue()) return defaultValue(); throw new IllegalStateException("expected yes or no, but:" + result); } + } + + public static class ConfigGetRordbSync extends ConfigGetBool { + + public ConfigGetRordbSync(SimpleObjectPool clientPool, ScheduledExecutorService scheduled) { + super(clientPool, scheduled); + } + + public ConfigGetRordbSync(SimpleObjectPool clientPool, ScheduledExecutorService scheduled, + int commandTimeoutMilli) { + super(clientPool, scheduled, commandTimeoutMilli); + } + + @Override + protected Boolean defaultValue() { + return false; + } + + @Override + protected String getConfigName() { + return REDIS_CONFIG_TYPE.RORDB_SYNC.getConfigName(); + } + + } + + public static class ConfigGetDisklessSync extends ConfigGetBool { + + public ConfigGetDisklessSync(SimpleObjectPool clientPool, ScheduledExecutorService scheduled) { + super(clientPool, scheduled); + } + + public ConfigGetDisklessSync(SimpleObjectPool clientPool, ScheduledExecutorService scheduled, + int commandTimeoutMilli) { + super(clientPool, scheduled, commandTimeoutMilli); + } @Override protected String getConfigName() { diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/RdbConstant.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/RdbConstant.java index 7d8c04754..3bec12514 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/RdbConstant.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/RdbConstant.java @@ -41,6 +41,18 @@ private RdbConstant() { public static final short REDIS_RDB_TYPE_LIST_QUICKLIST = 14; public static final short REDIS_RDB_TYPE_STREAM_LISTPACKS = 15; + // extend for rordb + public static final short REDIS_RORDB_OP_CODE_SWAP_VERSION = 128; + public static final short REDIS_RORDB_OP_CODE_SST = 129; + public static final short REDIS_RORDB_OP_CODE_KEY_NUM = 130; + public static final short REDIS_RORDB_OP_CODE_CUCKOO_FILTER = 131; + public static final short REDIS_RORDB_OP_CODE_HASH = 132; + public static final short REDIS_RORDB_OP_CODE_SET = 133; + public static final short REDIS_RORDB_OP_CODE_ZSET = 134; + public static final short REDIS_RORDB_OP_CODE_LIST = 135; + public static final short REDIS_RORDB_OP_CODE_BITMAP = 136; + public static final short REDIS_RORDB_OP_CODE_LIMIT = 137; + public static final short REDIS_RDB_OP_CODE_MODULE_AUX = 247; public static final short REDIS_RDB_OP_CODE_IDLE = 248; public static final short REDIS_RDB_OP_CODE_FREQ = 249; @@ -52,5 +64,6 @@ private RdbConstant() { public static final short REDIS_RDB_OP_CODE_EOF = 255; public static final String REDIS_RDB_AUX_KEY_GTID = "gtid"; + public static final String REDIS_RDB_AUX_KEY_RORDB = "rordb"; } diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/RdbParseContext.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/RdbParseContext.java index 391bf2516..91133f8a5 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/RdbParseContext.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/RdbParseContext.java @@ -37,6 +37,8 @@ public interface RdbParseContext { String getAux(String key); + Map getAllAux(); + RdbParseContext setKey(RedisKey key); RedisKey getKey(); @@ -82,7 +84,19 @@ enum RdbType { EXPIRETIME_MS(RdbConstant.REDIS_RDB_OP_CODE_EXPIRETIME_MS, true, RdbExpiretimeMsParser::new), EXPIRETIME(RdbConstant.REDIS_RDB_OP_CODE_EXPIRETIME, true, RdbExpiretimeParser::new), SELECTDB(RdbConstant.REDIS_RDB_OP_CODE_SELECTDB, true, RdbSelectDbParser::new), - EOF(RdbConstant.REDIS_RDB_OP_CODE_EOF, true, null); + EOF(RdbConstant.REDIS_RDB_OP_CODE_EOF, true, null), + + // extend for rordb + RORDB_SWAP_VERSION(RdbConstant.REDIS_RORDB_OP_CODE_SWAP_VERSION, true, null), + RORDB_SST(RdbConstant.REDIS_RORDB_OP_CODE_SST, true, null), + RORDB_KEY_NUM(RdbConstant.REDIS_RORDB_OP_CODE_KEY_NUM, true, null), + RORDB_CUCKOO_FILTER(RdbConstant.REDIS_RORDB_OP_CODE_CUCKOO_FILTER, true, null), + RORDB_HASH(RdbConstant.REDIS_RORDB_OP_CODE_HASH, true, null), + RORDB_SET(RdbConstant.REDIS_RORDB_OP_CODE_SET, true, null), + RORDB_ZSET(RdbConstant.REDIS_RORDB_OP_CODE_ZSET, true, null), + RORDB_LIST(RdbConstant.REDIS_RORDB_OP_CODE_LIST, true, null), + RORDB_BITMAP(RdbConstant.REDIS_RORDB_OP_CODE_BITMAP, true, null), + RORDB_LIMIT(RdbConstant.REDIS_RORDB_OP_CODE_LIMIT, true, null); private short code; diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/RdbParseListener.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/RdbParseListener.java index 93edf5ee5..7d2a29997 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/RdbParseListener.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/RdbParseListener.java @@ -2,6 +2,8 @@ import com.ctrip.xpipe.redis.core.redis.operation.RedisOp; +import java.util.Map; + /** * @author lishanglin * date 2022/5/28 @@ -14,6 +16,6 @@ public interface RdbParseListener { void onFinish(RdbParser parser); - void onAuxFinish(); + void onAuxFinish(Map auxMap); } diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/AbstractRdbParser.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/AbstractRdbParser.java index c8bbf9a3c..335931614 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/AbstractRdbParser.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/AbstractRdbParser.java @@ -12,6 +12,7 @@ import org.slf4j.Logger; import java.util.HashSet; +import java.util.Map; import java.util.Set; /** @@ -176,11 +177,11 @@ protected void notifyAux(String key, String value) { } } - protected void notifyAuxEnd() { + protected void notifyAuxEnd(Map axuMap) { getLogger().debug("[notifyAuxEnd]"); for (RdbParseListener listener : listeners) { try { - listener.onAuxFinish(); + listener.onAuxFinish(axuMap); } catch (Throwable t){ getLogger().info("[notifyAuxEnd][fail][{}]", listener, t); } diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/AuxOnlyRdbParser.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/AuxOnlyRdbParser.java index 2e3a87b6c..ad1989b45 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/AuxOnlyRdbParser.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/AuxOnlyRdbParser.java @@ -21,8 +21,7 @@ public AuxOnlyRdbParser(RdbParseContext parserManager) { @Override public boolean isFinish() { - // RDB end or start reading DB - return super.isFinish() || RdbParseContext.RdbType.SELECTDB.equals(getContext().getCurrentType()); + return super.isFinish() || isAuxFinish(); } @Override diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/DefaultRdbParseContext.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/DefaultRdbParseContext.java index 8cec99cbb..df16d3007 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/DefaultRdbParseContext.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/DefaultRdbParseContext.java @@ -126,6 +126,10 @@ public String getAux(String key) { return auxMap.get(key); } + public Map getAllAux() { + return Collections.unmodifiableMap(auxMap); + } + @Override public RdbParseContext setKey(RedisKey key) { this.redisKey.set(key); diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/DefaultRdbParser.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/DefaultRdbParser.java index 5b52f1301..6d54b99b7 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/DefaultRdbParser.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/DefaultRdbParser.java @@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory; import java.nio.charset.StandardCharsets; +import java.util.concurrent.atomic.AtomicBoolean; /** * @author lishanglin @@ -30,6 +31,8 @@ public class DefaultRdbParser extends AbstractRdbParser implements RdbPars private short rdbVersion; + private AtomicBoolean auxFinished = new AtomicBoolean(false); + private static final Logger logger = LoggerFactory.getLogger(DefaultRdbParser.class); protected enum STATE { @@ -86,8 +89,9 @@ public Void read(ByteBuf byteBuf) { case READ_TYPE: short type = byteBuf.readUnsignedByte(); RdbParseContext.RdbType newType = RdbParseContext.RdbType.findByCode(type); - if (isAuxFinish(newType)) { - notifyAuxEnd(); + if (currentType == RdbParseContext.RdbType.AUX && newType != RdbParseContext.RdbType.AUX) { + auxFinished.set(true); + notifyAuxEnd(rdbParseContext.getAllAux()); } currentType = newType; @@ -157,8 +161,8 @@ public Void read(ByteBuf byteBuf) { return null; } - private boolean isAuxFinish(RdbParseContext.RdbType newType) { - return currentType == RdbParseContext.RdbType.AUX && newType != RdbParseContext.RdbType.AUX; + protected boolean isAuxFinish() { + return auxFinished.get(); } private int checkMagic(ByteBuf byteBuf, int checkIdx) { diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/DumpedRdbStore.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/DumpedRdbStore.java index effcd9ff3..607166fe1 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/DumpedRdbStore.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/DumpedRdbStore.java @@ -2,21 +2,17 @@ import com.ctrip.xpipe.redis.core.protocal.protocal.EofType; -import java.io.File; - /** * @author wenchao.meng * * Aug 26, 2016 */ public interface DumpedRdbStore extends RdbStore{ + + void setReplId(String replId); void setEofType(EofType eofType); - - EofType getEofType(); - + void setRdbOffset(long rdbLastOffset); - - File getRdbFile(); } diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/FULLSYNC_FAIL_CAUSE.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/FULLSYNC_FAIL_CAUSE.java index 6ad4f07d7..70aaedd14 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/FULLSYNC_FAIL_CAUSE.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/FULLSYNC_FAIL_CAUSE.java @@ -8,9 +8,8 @@ public enum FULLSYNC_FAIL_CAUSE { MISS_CMD_AFTER_RDB, TOO_MUCH_CMD_AFTER_RDB, - FULLSYNC_TYPE_NOT_SUPPORTED, + FULLSYNC_PROGRESS_NOT_SUPPORTED, RDB_NOT_OK, - RDB_GTIDSET_NOT_READY } diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/FullSyncListener.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/FullSyncListener.java index c45b2fb28..e289152e5 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/FullSyncListener.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/FullSyncListener.java @@ -7,4 +7,6 @@ */ public interface FullSyncListener extends RdbFileListener, CommandsListener { + boolean supportRdb(RdbStore.Type rdbType); + } diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/MetaStore.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/MetaStore.java index 739fa59a2..e97f87135 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/MetaStore.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/MetaStore.java @@ -53,7 +53,9 @@ public interface MetaStore { * @throws IOException */ void becomeBackup() throws IOException; - + + ReplicationStoreMeta rdbConfirm(String replId, long beginOffset, String gtidSet, String rdbFile, RdbStore.Type type, EofType eofType, String cmdFilePrefix) throws IOException; + ReplicationStoreMeta rdbBegun(String replId, long beginOffset, String rdbFile, EofType eofType, String cmdFilePrefix) throws IOException; boolean attachRdbGtidSet(String rdbFile, String gtidSet) throws IOException; @@ -65,6 +67,8 @@ public interface MetaStore { @Deprecated void masterChanged(long keeperOffset, DefaultEndPoint newMasterEndpoint, String newMasterRunid, long newMasterReplOffset) throws IOException; + ReplicationStoreMeta checkReplIdAndUpdateRdbInfo(String rdbFile, RdbStore.Type type, EofType eofType, long rdbOffset, String gtidSet, String expectedReplId) throws IOException; + ReplicationStoreMeta checkReplIdAndUpdateRdbInfo(String rdbFile, EofType eofType, long rdbOffset, String expectedReplId) throws IOException; void updateKeeperRunid(String keeperRunid) throws IOException; diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/RdbDumpState.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/RdbDumpState.java index 4180b6189..548c6218a 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/RdbDumpState.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/RdbDumpState.java @@ -9,6 +9,7 @@ public enum RdbDumpState { NORMAL, WAIT_DUMPPING, + AUX_PARSED, DUMPING, FAIL diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/RdbStore.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/RdbStore.java index 9e476c344..645a3342f 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/RdbStore.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/RdbStore.java @@ -1,6 +1,7 @@ package com.ctrip.xpipe.redis.core.store; import com.ctrip.xpipe.api.lifecycle.Destroyable; +import com.ctrip.xpipe.redis.core.protocal.protocal.EofType; import io.netty.buffer.ByteBuf; import java.io.Closeable; @@ -13,10 +14,26 @@ public enum Status { Writing, Success, Fail }; - boolean updateRdbGtidSet(String gtidSet); + public enum Type { + UNKNOWN, NORMAL, RORDB + } + + void updateRdbType(Type type); + + Type getRdbType(); + + String getReplId(); + + long getRdbOffset(); + + EofType getEofType(); String getGtidSet(); + File getRdbFile(); + + boolean updateRdbGtidSet(String gtidSet); + boolean isGtidSetInit(); boolean supportGtidSet(); diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/RdbStoreListener.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/RdbStoreListener.java index 4c2969c5f..0b1bde70b 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/RdbStoreListener.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/RdbStoreListener.java @@ -7,8 +7,6 @@ */ public interface RdbStoreListener { - void onRdbGtidSet(String gtidSet); - void onEndRdb(); } diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/ReplicationStore.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/ReplicationStore.java index 16d521356..018979c19 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/ReplicationStore.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/ReplicationStore.java @@ -18,16 +18,18 @@ public interface ReplicationStore extends Closeable, Destroyable { public static String BACKUP_REPLICATION_STORE_REDIS_MASTER_META_NAME = "BACKUP_REDIS_MASTER"; - // rdb related - RdbStore beginRdb(String replId, long rdbOffset, EofType eofType) throws IOException; + RdbStore prepareRdb(String replId, long rdbOffset, EofType eofType) throws IOException; + + // use in dumped, broken if replId dismatch with default repl + void checkReplId(String expectReplId); + + void confirmRdb(RdbStore rdbStore) throws IOException; void continueFromOffset(String replId, long continueOffset) throws IOException; DumpedRdbStore prepareNewRdb() throws IOException; - void checkReplIdAndUpdateRdb(DumpedRdbStore dumpedRdbStore, String expectedReplId) throws IOException; - - void checkAndUpdateRdbGtidSet(RdbStore rdbStore, String rdbGtidSet) throws IOException; + void checkReplIdAndUpdateRdb(RdbStore rdbStore) throws IOException; // command related int appendCommands(ByteBuf byteBuf) throws IOException; @@ -37,6 +39,8 @@ public interface ReplicationStore extends Closeable, Destroyable { // full sync FULLSYNC_FAIL_CAUSE fullSyncIfPossible(FullSyncListener fullSyncListener) throws IOException; + FULLSYNC_FAIL_CAUSE fullSyncIfPossible(FullSyncListener fullSyncListener, boolean masterSupportRordb) throws IOException; + //create index FULLSYNC_FAIL_CAUSE createIndexIfPossible(ExecutorService indexingExecutors); diff --git a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/ReplicationStoreMeta.java b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/ReplicationStoreMeta.java index 6109285a9..985f1fad0 100644 --- a/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/ReplicationStoreMeta.java +++ b/redis/redis-core/src/main/java/com/ctrip/xpipe/redis/core/store/ReplicationStoreMeta.java @@ -37,6 +37,12 @@ public class ReplicationStoreMeta implements Serializable{ private long rdbFileSize; private String rdbEofMark; private String rdbGtidSet; + + private String rordbFile; + private Long rordbLastOffset; + private long rordbFileSize; + private String rordbEofMark; + private String rordbGtidSet; // last offset of rdb in keeper coordinate private String cmdFilePrefix; @@ -44,14 +50,6 @@ public class ReplicationStoreMeta implements Serializable{ private KeeperState keeperState; private String keeperRunid; - - //these fieled are to be deleted after upgrade to new version - @Deprecated - private Long rdbLastKeeperOffset; - @Deprecated - private Long keeperBeginOffset; - - public ReplicationStoreMeta() { } @@ -66,10 +64,15 @@ public ReplicationStoreMeta(ReplicationStoreMeta proto) { this.rdbFile = proto.rdbFile; this.rdbLastOffset = proto.rdbLastOffset; - this.rdbFileSize = proto.rdbFileSize; this.rdbEofMark = proto.rdbEofMark; this.rdbGtidSet = proto.rdbGtidSet; + + this.rordbFile = proto.rordbFile; + this.rordbLastOffset = proto.rordbLastOffset; + this.rordbFileSize = proto.rordbFileSize; + this.rordbEofMark = proto.rordbEofMark; + this.rordbGtidSet = proto.rordbGtidSet; this.cmdFilePrefix = proto.cmdFilePrefix; this.keeperState = proto.keeperState; @@ -122,7 +125,6 @@ public Long getBeginOffset() { public void setBeginOffset(Long beginOffset) { this.beginOffset = beginOffset; - ajastRdbLastOffset(); } @@ -180,30 +182,45 @@ public KeeperState getKeeperState() { public void setKeeperState(KeeperState keeperState) { this.keeperState = keeperState; } - - @Deprecated - public void setMasterRunid(String masterRunid) { - this.replId = masterRunid; + + public String getRordbFile() { + return rordbFile; } - @Deprecated - public void setRdbLastKeeperOffset(Long rdbLastKeeperOffset) { - this.rdbLastKeeperOffset = rdbLastKeeperOffset; - ajastRdbLastOffset(); + public void setRordbFile(String rordbFile) { + this.rordbFile = rordbFile; } - - @Deprecated - public void setKeeperBeginOffset(Long keeperBeginOffset) { - this.keeperBeginOffset = keeperBeginOffset; - ajastRdbLastOffset(); + + public Long getRordbLastOffset() { + return rordbLastOffset; } - private void ajastRdbLastOffset() { - - if(rdbLastKeeperOffset != null && keeperBeginOffset != null && beginOffset != null ){ - this.rdbLastOffset = beginOffset + (rdbLastKeeperOffset - keeperBeginOffset); - logger.info("[ajastRdbLastOffset]begin:{}, keeperBegin:{}, rdbLastKeeper:{} ===> rdbLast:{}", beginOffset, keeperBeginOffset, rdbLastKeeperOffset, rdbLastOffset); - } + public void setRordbLastOffset(Long rordbLastOffset) { + this.rordbLastOffset = rordbLastOffset; + } + + public long getRordbFileSize() { + return rordbFileSize; + } + + public void setRordbFileSize(long rordbFileSize) { + this.rordbFileSize = rordbFileSize; + } + + public String getRordbEofMark() { + return rordbEofMark; + } + + public void setRordbEofMark(String rordbEofMark) { + this.rordbEofMark = rordbEofMark; + } + + public String getRordbGtidSet() { + return rordbGtidSet; + } + + public void setRordbGtidSet(String rordbGtidSet) { + this.rordbGtidSet = rordbGtidSet; } @Override @@ -219,6 +236,11 @@ public String toString() { ", rdbFileSize=" + rdbFileSize + ", rdbEofMark='" + rdbEofMark + '\'' + ", rdbGtidSet='" + rdbGtidSet + '\'' + + ", rordbFile='" + rordbFile + '\'' + + ", rordbLastOffset=" + rordbLastOffset + + ", rordbFileSize=" + rordbFileSize + + ", rordbEofMark='" + rordbEofMark + '\'' + + ", rordbGtidSet='" + rordbGtidSet + '\'' + ", cmdFilePrefix='" + cmdFilePrefix + '\'' + ", keeperState=" + keeperState + ", keeperRunid='" + keeperRunid + '\'' + @@ -227,7 +249,7 @@ public String toString() { @Override public boolean equals(Object obj) { - return EqualsBuilder.reflectionEquals(this, obj, "rdbLastKeeperOffset", "keeperBeginOffset"); + return EqualsBuilder.reflectionEquals(this, obj); } @Override diff --git a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/AbstractRedisTest.java b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/AbstractRedisTest.java index 4580709c6..4b96a47f5 100644 --- a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/AbstractRedisTest.java +++ b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/AbstractRedisTest.java @@ -15,6 +15,10 @@ import com.ctrip.xpipe.redis.core.protocal.cmd.InfoCommand; import com.ctrip.xpipe.redis.core.protocal.cmd.InfoResultExtractor; import com.ctrip.xpipe.redis.core.protocal.protocal.CommandBulkStringParser; +import com.ctrip.xpipe.redis.core.redis.operation.RedisOp; +import com.ctrip.xpipe.redis.core.redis.rdb.RdbParseListener; +import com.ctrip.xpipe.redis.core.redis.rdb.RdbParser; +import com.ctrip.xpipe.redis.core.redis.rdb.parser.AuxOnlyRdbParser; import com.ctrip.xpipe.redis.core.server.FakeRedisServer; import com.ctrip.xpipe.redis.core.server.FakeXsyncHandler; import com.ctrip.xpipe.redis.core.server.FakeXsyncServer; @@ -24,6 +28,7 @@ import com.ctrip.xpipe.utils.IpUtils; import com.ctrip.xpipe.utils.StringUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.ExecuteException; @@ -40,6 +45,7 @@ import java.util.*; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; /** * @author wenchao.meng @@ -614,4 +620,33 @@ protected KeeperMeta newRandomFakeKeeperMeta(String ip, int port) { dcMeta.addCluster(clusterMeta); return keeper; } + + protected Map parseRdbAux(byte[] rdb) { + AuxOnlyRdbParser parser = new AuxOnlyRdbParser(); + AtomicReference> auxMapRef = new AtomicReference<>(); + parser.registerListener(new RdbParseListener() { + @Override + public void onRedisOp(RedisOp redisOp) { + } + + @Override + public void onAux(String key, String value) { + } + + @Override + public void onFinish(RdbParser parser) { + } + + @Override + public void onAuxFinish(Map auxMap) { + auxMapRef.set(auxMap); + } + }); + + ByteBuf payload = Unpooled.wrappedBuffer(rdb); + while (!parser.isFinish()) parser.read(payload); + + return auxMapRef.get(); + } + } diff --git a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/protocal/cmd/DefaultPsyncTest.java b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/protocal/cmd/DefaultPsyncTest.java index a950251e5..c14e51d34 100644 --- a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/protocal/cmd/DefaultPsyncTest.java +++ b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/protocal/cmd/DefaultPsyncTest.java @@ -26,6 +26,7 @@ import org.mockito.junit.MockitoJUnitRunner; import java.io.IOException; +import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.function.Function; @@ -133,10 +134,7 @@ public void onKeeperContinue(String replId, long beginOffset) { latch.countDown(); } @Override - public void readRdbGtidSet(RdbStore rdbStore, String gtidSet) { - } - @Override - public void readAuxEnd(RdbStore rdbStore) { + public void readAuxEnd(RdbStore rdbStore, Map auxMap) { } }); partialOnlyPsync.execute().addListener(new CommandFutureListener() { diff --git a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/protocal/cmd/PartialOnlyPsyncTest.java b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/protocal/cmd/PartialOnlyPsyncTest.java index 0bc3518d5..a7cefa752 100644 --- a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/protocal/cmd/PartialOnlyPsyncTest.java +++ b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/protocal/cmd/PartialOnlyPsyncTest.java @@ -21,6 +21,7 @@ import org.mockito.junit.MockitoJUnitRunner; import java.io.IOException; +import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.function.Function; @@ -93,11 +94,8 @@ public void onContinue(String requestReplId, String responseReplId) { public void onKeeperContinue(String replId, long beginOffset) { latch.countDown(); } - @Override - public void readRdbGtidSet(RdbStore rdbStore, String gtidSet) { - } @Override - public void readAuxEnd(RdbStore rdbStore) { + public void readAuxEnd(RdbStore rdbStore, Map auxMap) { } }); psync.execute().addListener(new CommandFutureListener() { diff --git a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/AuxOnlyRdbParserTest.java b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/AuxOnlyRdbParserTest.java index 67d60a191..96369fccf 100644 --- a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/AuxOnlyRdbParserTest.java +++ b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/AuxOnlyRdbParserTest.java @@ -11,6 +11,7 @@ import org.junit.Before; import org.junit.Test; +import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import static com.ctrip.xpipe.redis.core.redis.rdb.RdbConstant.REDIS_RDB_AUX_KEY_GTID; @@ -67,7 +68,7 @@ public void onFinish(RdbParser parser) { } @Override - public void onAuxFinish() { + public void onAuxFinish(Map auxMap) { logger.info("[onAuxFinish] {}", parser); } } diff --git a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/DefaultRdbParserTest.java b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/DefaultRdbParserTest.java index cecf4479a..a0227d7c8 100644 --- a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/DefaultRdbParserTest.java +++ b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/DefaultRdbParserTest.java @@ -12,6 +12,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import static com.ctrip.xpipe.redis.core.redis.rdb.parser.RdbDataBytes.*; @@ -247,7 +248,7 @@ public void onFinish(RdbParser parser) { } @Override - public void onAuxFinish() { + public void onAuxFinish(Map auxMap) { logger.info("[onAuxFinish]"); } } diff --git a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/ManualRdbParseTest.java b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/ManualRdbParseTest.java index 9cbbd3ec0..e68fe336c 100644 --- a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/ManualRdbParseTest.java +++ b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/redis/rdb/parser/ManualRdbParseTest.java @@ -13,6 +13,7 @@ import java.io.File; import java.nio.ByteBuffer; +import java.util.Map; /** * @author lishanglin @@ -20,7 +21,7 @@ */ public class ManualRdbParseTest extends AbstractTest implements RdbParseListener { - private String filePath = "./dump.rdb"; + private String filePath = "/Users/ccsa/prog/demo/redis-test/redis6379/data/dump6379.rdb"; private DefaultRdbParser rdbParser; @@ -70,8 +71,8 @@ public void onFinish(RdbParser parser) { } @Override - public void onAuxFinish() { - logger.info("[onAuxFinish]"); + public void onAuxFinish(Map auxMap) { + logger.info("[onAuxFinish] {}", auxMap); } } diff --git a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/server/AbstractRedisAction.java b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/server/AbstractRedisAction.java index 5ada9c9b0..10fa83186 100644 --- a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/server/AbstractRedisAction.java +++ b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/server/AbstractRedisAction.java @@ -24,6 +24,8 @@ public abstract class AbstractRedisAction extends AbstractIoAction implements So private boolean slaveof = false; private List slaveOfCommands = new ArrayList(); + protected boolean capaRordb = false; + public AbstractRedisAction(Socket socket) { super(socket); } @@ -62,6 +64,9 @@ protected void doWrite(OutputStream ous, Object readResult) throws IOException { if(line.startsWith("replconf")){ towrite = handleReplconf(line); } + if (line.startsWith("config get")) { + towrite = handleConfigGet(line); + } if(line.equalsIgnoreCase("PING")){ towrite = "+PONG\r\n".getBytes(); @@ -127,6 +132,10 @@ protected void doWrite(OutputStream ous, Object readResult) throws IOException { } } + protected byte[] handleConfigGet(String line) throws NumberFormatException, IOException { + return "*0\r\n".getBytes(); + } + protected byte[] handleReplconf(String line) throws NumberFormatException, IOException{ String []sp = line.split("\\s+"); @@ -148,6 +157,13 @@ protected byte[] handleReplconf(String line) throws NumberFormatException, IOExc } } + + if (option.equals("capa")) { + for (int i = 2; i < sp.length; i++) { + if (sp[i].equalsIgnoreCase("rordb")) this.capaRordb = true; + } + } + return OK; } diff --git a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/server/FakeRedisServer.java b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/server/FakeRedisServer.java index abdbe1213..e96ee4ef1 100644 --- a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/server/FakeRedisServer.java +++ b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/server/FakeRedisServer.java @@ -7,6 +7,8 @@ import com.ctrip.xpipe.simpleserver.IoActionFactory; import com.ctrip.xpipe.simpleserver.Server; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.net.Socket; import java.util.LinkedList; import java.util.List; @@ -25,11 +27,13 @@ public class FakeRedisServer extends AbstractLifecycle{ private int sendBatchIntervalMilli = 10; private int port; - private String rdbContent = ""; + private byte[] rdbContent = new byte[0]; private String commands = ""; private int rdbOffset = 1; private Server server; private String runId = RunidGenerator.DEFAULT.generateRunid(); + + private boolean supportRordb = false; private boolean eof = Boolean.parseBoolean(System.getProperty("EOF", "true")); @@ -86,7 +90,7 @@ public int getPort() { return port; } - public String getRdbContent() { + public byte[] getRdbContent() { return rdbContent; } @@ -102,12 +106,25 @@ public int getSleepBeforeSendRdb() { return sleepBeforeSendRdb; } - public synchronized void reGenerateRdb() { - + public synchronized void reGenerateRdb(boolean capaRordb) throws IOException { rdbOffset += commands.length(); String prefix = String.format("rdb_rdboffset:%d--", rdbOffset); - rdbContent = "REDIS0009" + '\0' + prefix + AbstractTest.randomString(rdbSize - prefix.length()); + // "REDIS0009" + AUX(redis-ver:6.2.6) + SELECTDB 0 + byte[] magic = new byte[] {0x52, 0x45, 0x44, 0x49, 0x53, 0x30, 0x30, 0x30, 0x39}; + byte[] aux = new byte[] {(byte)0xfa, 0x09, 0x72, 0x65, 0x64, 0x69, 0x73, 0x2d, + 0x76, 0x65, 0x72, 0x05, 0x36, 0x2e, 0x32, 0x2e, 0x36}; + byte[] selectDb0 = new byte[] {(byte)0xfe, 0x00}; + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + os.write(magic); + os.write(aux); + // AUX(rordb:00001) + if (capaRordb && this.supportRordb) os.write(new byte[] {(byte)0xfa, 0x05, 0x72, 0x6f, 0x72, 0x64, 0x62, 0x05, 0x30, 0x30, 0x30, 0x30, 0x31}); + os.write(selectDb0); + os.write(prefix.getBytes()); + os.write(AbstractTest.randomString(rdbSize - prefix.length()).getBytes()); + rdbContent = os.toByteArray(); if (commandsLength < 0) return; prefix = String.format("cmd_rdboffset:%d--", rdbOffset); @@ -115,6 +132,10 @@ public synchronized void reGenerateRdb() { addCommands(commands); } + public synchronized void reGenerateRdb() throws IOException { + reGenerateRdb(false); + } + public void propagate(String cmd) { addCommands(cmd); } @@ -209,6 +230,14 @@ public void setEof(boolean eof) { this.eof = eof; } + public boolean isSupportRordb() { + return supportRordb; + } + + public void setSupportRordb(boolean supportRordb) { + this.supportRordb = supportRordb; + } + public void increasePsyncCount() { psyncCount.incrementAndGet(); } diff --git a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/server/FakeRedisServerAction.java b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/server/FakeRedisServerAction.java index 4ac028d80..a3bc936ce 100644 --- a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/server/FakeRedisServerAction.java +++ b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/server/FakeRedisServerAction.java @@ -1,13 +1,19 @@ package com.ctrip.xpipe.redis.core.server; +import com.ctrip.xpipe.api.payload.InOutPayload; import com.ctrip.xpipe.concurrent.AbstractExceptionLogTask; import com.ctrip.xpipe.netty.ByteBufUtils; +import com.ctrip.xpipe.payload.ByteArrayOutputStreamPayload; +import com.ctrip.xpipe.payload.StringInOutPayload; import com.ctrip.xpipe.redis.core.protocal.cmd.AbstractPsync; import com.ctrip.xpipe.redis.core.protocal.protocal.RdbBulkStringParser; import com.ctrip.xpipe.redis.core.redis.RunidGenerator; import com.ctrip.xpipe.utils.StringUtil; import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.apache.commons.lang3.ArrayUtils; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -131,7 +137,7 @@ private String[] split(String command) { private void handleFullSync(final OutputStream ous) throws IOException, InterruptedException { logger.info("[handleFullSync]{}", getSocket()); - fakeRedisServer.reGenerateRdb(); + fakeRedisServer.reGenerateRdb(this.capaRordb); fakeRedisServer.addCommandsListener(this); try { @@ -159,19 +165,29 @@ private void handleFullSync(final OutputStream ous) throws IOException, Interrup byte []rdb = null; int rdbStartPos = 0; - String rdbContent = fakeRedisServer.getRdbContent(); + byte[] rdbContent = fakeRedisServer.getRdbContent(); if(fakeRedisServer.isEof()){ String mark = RunidGenerator.DEFAULT.generateRunid(); - String content = "$EOF:" + mark + "\r\n" ; - rdbStartPos = content.length(); - content += rdbContent + mark; - rdb = content.getBytes(); + String header = "$EOF:" + mark + "\r\n" ; + rdbStartPos = header.length(); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + os.write(header.getBytes()); + os.write(rdbContent); + os.write(mark.getBytes()); + + rdb = os.toByteArray(); waitAckToSendCommands = true; }else{ - RdbBulkStringParser bulkStringParser = new RdbBulkStringParser(rdbContent); + InOutPayload payload = new ByteArrayOutputStreamPayload(); + payload.startInput(); + payload.in(Unpooled.wrappedBuffer(rdbContent)); + payload.endInput(); + + RdbBulkStringParser bulkStringParser = new RdbBulkStringParser(payload); ByteBuf byteBuf = bulkStringParser.format(); rdb = ByteBufUtils.readToBytes(byteBuf); - rdbStartPos = 3 + String.valueOf(rdbContent.length()).length(); + rdbStartPos = 3 + String.valueOf(rdbContent.length).length(); waitAckToSendCommands = false; } if(logger.isDebugEnabled()){ @@ -179,7 +195,7 @@ private void handleFullSync(final OutputStream ous) throws IOException, Interrup } if(fakeRedisServer.getAndDecreaseSendHalfRdbAndCloseConnectionCount() > 0){ - ous.write(rdb, 0, rdbStartPos + rdbContent.length()/2); + ous.write(rdb, 0, rdbStartPos + rdbContent.length/2); ous.flush(); logger.info("[handleFullSync]halfsync after write half data,close socket:{}", getSocket()); ous.close(); @@ -193,6 +209,15 @@ private void handleFullSync(final OutputStream ous) throws IOException, Interrup } } + protected byte[] handleConfigGet(String line) throws NumberFormatException, IOException { + String []sp = line.split("\\s+"); + String param = sp[2]; + if (param.equalsIgnoreCase("swap-repl-rordb-sync") && fakeRedisServer.isSupportRordb()) { + return "*2\r\n$20\r\nswap-repl-rordb-sync\r\n$3\r\nyes\r\n".getBytes(); + } + return super.handleConfigGet(line); + } + @Override protected boolean isKeeper() { return fakeRedisServer.isKeeper(); diff --git a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/store/ReplicationStoreMetaTest.java b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/store/ReplicationStoreMetaTest.java index 2b498f68b..993a09b7b 100644 --- a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/store/ReplicationStoreMetaTest.java +++ b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/store/ReplicationStoreMetaTest.java @@ -18,31 +18,6 @@ */ public class ReplicationStoreMetaTest extends AbstractRedisTest{ - @Test - public void testPsync1Version(){ - - Long keeperBegin = 4089698428721L; - Long rdbLastKeeperOffset = 4089698428720L; - Long beginOffset = 1L; - - String realData = "{\"beginOffset\":" + beginOffset + ",\"cmdFilePrefix\":\"cmd_aaf0bac6-2323-4fd9-9ff1-3de907b2a59f_\"," - + "\"keeperBeginOffset\": " + keeperBegin + ",\"keeperRunid\":\"defda76dafa715ea7dc3ccbc9c6406892c203469\",\"keeperState\":\"BACKUP\"," - + "\"masterAddress\":{\"rawUrl\":\"redis://10.2.24.216:6379\",\"socketAddress\":{\"address\":\"10.2.24.216\",\"port\":6379}}," - + "\"masterRunid\":\"aa27eb88752a94c82e66d109c3279b9e3bcd97b3\",\"rdbEofMark\":\"19c9a31ab9aeb916429198e51e7abada9d9ecb62\"," - + "\"rdbFile\":\"rdb_1487043213489_e0d7641a-da1b-450d-9a28-9d0f5cbd0888\",\"rdbFileSize\":18,\"rdbLastKeeperOffset\":" + rdbLastKeeperOffset + "}"; - ReplicationStoreMeta meta = fromString(realData); - - Assert.assertEquals((Long)(beginOffset + (rdbLastKeeperOffset - keeperBegin)), meta.getRdbLastOffset()); - Assert.assertEquals("aa27eb88752a94c82e66d109c3279b9e3bcd97b3", meta.getReplId()); - Assert.assertEquals(null, meta.getReplId2()); - - String dese = metaString(meta); - logger.info("{}", dese); - ReplicationStoreMeta metaDese = fromString(dese); - - Assert.assertEquals(meta, metaDese); - } - @Test public void testEofmark(){ diff --git a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/utils/SimplePsyncObserver.java b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/utils/SimplePsyncObserver.java index 97243af86..1032371c1 100644 --- a/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/utils/SimplePsyncObserver.java +++ b/redis/redis-core/src/test/java/com/ctrip/xpipe/redis/core/utils/SimplePsyncObserver.java @@ -6,6 +6,7 @@ import com.google.common.util.concurrent.SettableFuture; import java.io.IOException; +import java.util.Map; /** * @author wenchao.meng @@ -31,12 +32,7 @@ public void beginWriteRdb(EofType eofType, String repelId, long masterRdbOffset) } @Override - public void readRdbGtidSet(RdbStore rdbStore, String gtidSet) { - - } - - @Override - public void readAuxEnd(RdbStore rdbStore) { + public void readAuxEnd(RdbStore rdbStore, Map auxMap) { } diff --git a/redis/redis-integration-test/src/test/java/com/ctrip/xpipe/redis/integratedtest/keeper/KeeperFastStateChangeTest.java b/redis/redis-integration-test/src/test/java/com/ctrip/xpipe/redis/integratedtest/keeper/KeeperFastStateChangeTest.java index 83ec0389b..37ec8bf66 100644 --- a/redis/redis-integration-test/src/test/java/com/ctrip/xpipe/redis/integratedtest/keeper/KeeperFastStateChangeTest.java +++ b/redis/redis-integration-test/src/test/java/com/ctrip/xpipe/redis/integratedtest/keeper/KeeperFastStateChangeTest.java @@ -30,6 +30,10 @@ /** * @author lishanglin * date 2021/12/14 + * [MAC] update fd limit to 8192 before test + * sudo sysctl -w kern.maxfiles=1048600 + * sudo sysctl -w kern.maxfilesperproc=1048600 + * ulimit -n 8124 */ public class KeeperFastStateChangeTest extends AbstractKeeperIntegratedSingleDc { diff --git a/redis/redis-integration-test/src/test/java/com/ctrip/xpipe/redis/integratedtest/keeper/TwoKeepers.java b/redis/redis-integration-test/src/test/java/com/ctrip/xpipe/redis/integratedtest/keeper/TwoKeepers.java index 8459c7371..cc48763cb 100644 --- a/redis/redis-integration-test/src/test/java/com/ctrip/xpipe/redis/integratedtest/keeper/TwoKeepers.java +++ b/redis/redis-integration-test/src/test/java/com/ctrip/xpipe/redis/integratedtest/keeper/TwoKeepers.java @@ -32,6 +32,7 @@ public void beforeAbstractKeeperIntegratedSingleDc() throws Exception { setKeeperActive(); startKeepers(); + startRedis(getRedisMaster()); sleep(3000); } diff --git a/redis/redis-integration-test/src/test/java/com/ctrip/xpipe/redis/integratedtest/keeper/manul/GtidKeeperTest.java b/redis/redis-integration-test/src/test/java/com/ctrip/xpipe/redis/integratedtest/keeper/manul/GtidKeeperTest.java index 98d9f6bf5..d78cadb7f 100644 --- a/redis/redis-integration-test/src/test/java/com/ctrip/xpipe/redis/integratedtest/keeper/manul/GtidKeeperTest.java +++ b/redis/redis-integration-test/src/test/java/com/ctrip/xpipe/redis/integratedtest/keeper/manul/GtidKeeperTest.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; +import java.util.Map; /** * @author lishanglin @@ -122,8 +123,9 @@ public void onFinish(RdbParser parser) { logger.info("[onFinish] {}", parser); } + @Override - public void onAuxFinish() { + public void onAuxFinish(Map auxMap) { logger.info("[onAuxFinish]"); } } diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RdbDumper.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RdbDumper.java index 23e425d25..3d5b59bcc 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RdbDumper.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RdbDumper.java @@ -2,6 +2,7 @@ import com.ctrip.xpipe.api.command.Command; import com.ctrip.xpipe.redis.core.store.DumpedRdbStore; +import com.ctrip.xpipe.redis.core.store.RdbStore; import java.io.IOException; @@ -14,12 +15,14 @@ public interface RdbDumper extends Command{ void tryFullSync(RedisSlave redisSlave) throws IOException; + boolean tryRordb(); + DumpedRdbStore prepareRdbStore() throws IOException; void beginReceiveRdbData(String replId, long masterOffset); - void rdbGtidSetParsed(); - + void auxParseFinished(RdbStore.Type rdbType); + void dumpFinished(); void dumpFail(Throwable th); diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RedisMaster.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RedisMaster.java index a04f99cc5..5e6e28965 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RedisMaster.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RedisMaster.java @@ -3,6 +3,7 @@ +import com.ctrip.xpipe.api.command.CommandFuture; import com.ctrip.xpipe.api.endpoint.Endpoint; import com.ctrip.xpipe.api.lifecycle.Lifecycle; import com.ctrip.xpipe.api.lifecycle.LifecycleStateAware; @@ -28,7 +29,7 @@ public interface RedisMaster extends RedisRole, Lifecycle, LifecycleStateAware, void reconnect(); - RdbDumper createRdbDumper() throws CreateRdbDumperException; + RdbDumper createRdbDumper(boolean tryRrodb) throws CreateRdbDumperException; MASTER_STATE getMasterState(); @@ -38,4 +39,6 @@ public interface RedisMaster extends RedisRole, Lifecycle, LifecycleStateAware, boolean usingProxy(); + CommandFuture checkMasterSupportRordb(); + } diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RedisMasterReplication.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RedisMasterReplication.java index 7acb4187b..de738fcc1 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RedisMasterReplication.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RedisMasterReplication.java @@ -14,6 +14,8 @@ */ public interface RedisMasterReplication extends PsyncChecker, Lifecycle{ + boolean tryRordb(); + void handleResponse(Channel channel, ByteBuf msg) throws XpipeException; void masterDisconnected(Channel channel); diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RedisSlave.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RedisSlave.java index 346f546b4..e6d592bda 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RedisSlave.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/RedisSlave.java @@ -4,6 +4,7 @@ import com.ctrip.xpipe.netty.filechannel.ReferenceFileRegion; import com.ctrip.xpipe.redis.core.protocal.protocal.EofType; import com.ctrip.xpipe.redis.core.store.CommandsListener; +import com.ctrip.xpipe.redis.core.store.RdbStore; import com.ctrip.xpipe.redis.core.store.ReplicationProgress; import io.netty.channel.ChannelFuture; @@ -17,8 +18,6 @@ public interface RedisSlave extends RedisClient, PartialAware void waitForRdbDumping(); - void waitForGtidParse(); - void waitForSeqFsync(); SLAVE_STATE getSlaveState(); @@ -57,4 +56,6 @@ public interface RedisSlave extends RedisClient, PartialAware boolean supportProgress(Class> clazz); + boolean supportRdb(RdbStore.Type rdbType); + } diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/SLAVE_STATE.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/SLAVE_STATE.java index 4bdadeb06..3438e0351 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/SLAVE_STATE.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/SLAVE_STATE.java @@ -8,7 +8,6 @@ public enum SLAVE_STATE { REDIS_REPL_WAIT_RDB_DUMPING("wait_rdb_dumping"), - REDIS_REPL_WAIT_RDB_GTIDSET("wait_rdb_gtidset"), REDIS_REPL_WAIT_SEQ_FSYNC("wait_seq_fsync"), REDIS_REPL_SEND_BULK("send_bulk"), REDIS_REPL_ONLINE("online"); diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/applier/xsync/DefaultCommandDispatcher.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/applier/xsync/DefaultCommandDispatcher.java index 3e488395c..be12a3cbe 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/applier/xsync/DefaultCommandDispatcher.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/applier/xsync/DefaultCommandDispatcher.java @@ -9,7 +9,6 @@ import com.ctrip.xpipe.redis.core.redis.operation.RedisOp; import com.ctrip.xpipe.redis.core.redis.operation.RedisOpParser; import com.ctrip.xpipe.redis.core.redis.operation.RedisOpType; -import com.ctrip.xpipe.redis.core.redis.operation.op.RedisOpLwm; import com.ctrip.xpipe.redis.core.redis.operation.op.RedisOpMergeEnd; import com.ctrip.xpipe.redis.core.redis.operation.op.RedisOpMergeStart; import com.ctrip.xpipe.redis.core.redis.rdb.RdbParser; @@ -24,10 +23,7 @@ import io.netty.buffer.ByteBuf; import org.apache.zookeeper.common.StringUtils; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicLong; @@ -392,7 +388,7 @@ public void onFinish(RdbParser parser) { } @Override - public void onAuxFinish() { + public void onAuxFinish(Map auxMap) { } } diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/config/TestKeeperConfig.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/config/TestKeeperConfig.java index ca919ea29..8ef15f50f 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/config/TestKeeperConfig.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/config/TestKeeperConfig.java @@ -16,7 +16,7 @@ public class TestKeeperConfig extends AbstractCoreConfig implements KeeperConfig private long replicationStoreMaxCommandsToTransferBeforeCreateRdb = 1024; private long replicationStoreMaxLWMDistanceToTransferBeforeCreateRdb = 10000; private int minTimeMilliToGcAfterCreate = 2000; - private int rdbDumpMinIntervalMilli = 1000; + public int rdbDumpMinIntervalMilli = 1000; private int maxPartialSyncKeepTokenRounds = 3; private int partialSyncTrafficMonitorIntervalTimes = 10; private long commandReaderFlyingThreshold = DefaultCommandStore.DEFAULT_COMMAND_READER_FLYING_THRESHOLD; diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/handler/CommandHandlerManager.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/handler/CommandHandlerManager.java index 7dcaee98c..59fbf4f3b 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/handler/CommandHandlerManager.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/handler/CommandHandlerManager.java @@ -41,6 +41,7 @@ protected void initCommands() { putHandler(new ClientCommandHandler()); putHandler(new RoleCommandHandler()); putHandler(new ProxyCommandHandler()); + putHandler(new ConfigHandler()); } protected void putHandler(CommandHandler handler) { @@ -81,9 +82,9 @@ public void run() { return; } innerDoHandle(args, redisClient, handler); - } catch (Exception e) { - logger.error("Error process command {} for client {}", Arrays.asList(args), redisClient, e); - redisClient.sendMessage(new RedisErrorParser(e.getMessage()).format()); + } catch (Throwable th) { + logger.error("Error process command {} for client {}", Arrays.asList(args), redisClient, th); + redisClient.sendMessage(new RedisErrorParser(th.getMessage()).format()); } } diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/handler/keeper/ConfigHandler.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/handler/keeper/ConfigHandler.java new file mode 100644 index 000000000..e4904829c --- /dev/null +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/handler/keeper/ConfigHandler.java @@ -0,0 +1,47 @@ +package com.ctrip.xpipe.redis.keeper.handler.keeper; + +import com.ctrip.xpipe.redis.core.protocal.cmd.AbstractConfigCommand; +import com.ctrip.xpipe.redis.core.protocal.protocal.ArrayParser; +import com.ctrip.xpipe.redis.keeper.RedisClient; +import com.ctrip.xpipe.redis.keeper.RedisKeeperServer; +import com.ctrip.xpipe.redis.keeper.handler.AbstractCommandHandler; + +/** + * @author lishanglin + * date 2024/3/5 + */ +public class ConfigHandler extends AbstractCommandHandler { + + @Override + protected void doHandle(String[] args, RedisClient redisClient) throws Exception { + + if (args.length > 1) { + if (args[0].equalsIgnoreCase("get")) { + String param = args[1]; + if (param.equalsIgnoreCase(AbstractConfigCommand.REDIS_CONFIG_TYPE.RORDB_SYNC.getConfigName())) { + final RedisKeeperServer redisKeeperServer = (RedisKeeperServer) redisClient.getRedisServer(); + if (null != redisKeeperServer.getRedisMaster()) { + redisKeeperServer.getRedisMaster().checkMasterSupportRordb().addListener(commandFuture -> { + redisClient.sendMessage(new ArrayParser(new Object[] { + AbstractConfigCommand.REDIS_CONFIG_TYPE.RORDB_SYNC.getConfigName(), + (commandFuture.isSuccess() && commandFuture.get()) ? "yes" : "no" + }).format()); + }); + } else { + redisClient.sendMessage("*0\r\n".getBytes()); + } + } else { + redisClient.sendMessage("*0\r\n".getBytes()); + } + } else { + throw new IllegalStateException("unknown command:" + args[0]); + } + } + + } + + @Override + public String[] getCommands() { + return new String[]{"config"}; + } +} diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/AbstractRdbDumper.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/AbstractRdbDumper.java index f5ced8981..c53e14856 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/AbstractRdbDumper.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/AbstractRdbDumper.java @@ -10,9 +10,10 @@ import com.ctrip.xpipe.utils.VisibleForTesting; import java.io.IOException; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.ReentrantReadWriteLock; -import static com.ctrip.xpipe.redis.core.store.RdbDumpState.WAIT_DUMPPING; +import static com.ctrip.xpipe.redis.core.store.RdbDumpState.*; /** * @author wenchao.meng @@ -27,6 +28,8 @@ public abstract class AbstractRdbDumper extends AbstractCommand implements private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + private AtomicReference rdbType = new AtomicReference<>(); + public AbstractRdbDumper(RedisKeeperServer redisKeeperServer) { this.redisKeeperServer = redisKeeperServer; } @@ -42,7 +45,9 @@ public void setRdbDumpState(RdbDumpState rdbDumpState) { this.rdbDumpState = rdbDumpState; switch (rdbDumpState) { case DUMPING: - doWhenDumping(); + break; + case AUX_PARSED: + doWhenAuxParsed(); break; case FAIL: doWhenDumpFailed(); @@ -51,7 +56,6 @@ public void setRdbDumpState(RdbDumpState rdbDumpState) { case NORMAL: // clear dumper redisKeeperServer.clearRdbDumper(this); - ; break; case WAIT_DUMPPING: break; @@ -65,7 +69,7 @@ private void doWhenDumpFailed() { for (final RedisSlave redisSlave : redisKeeperServer.slaves()) { if (redisSlave.getSlaveState() == SLAVE_STATE.REDIS_REPL_WAIT_RDB_DUMPING) { - getLogger().info("[doWhenDumping][slave waiting for rdb, close]{}", redisSlave); + getLogger().info("[doWhenDumpFailed][slave waiting for rdb, close]{}", redisSlave); try { redisSlave.close(); } catch (IOException e) { @@ -75,21 +79,11 @@ private void doWhenDumpFailed() { } } - private void doWhenDumping() { + private void doWhenAuxParsed() { for (final RedisSlave redisSlave : redisKeeperServer.slaves()) { if (redisSlave.getSlaveState() == SLAVE_STATE.REDIS_REPL_WAIT_RDB_DUMPING) { - getLogger().info("[doWhenDumping][slave waiting for rdb, resume]{}", redisSlave); - continueSlaveFsync(redisSlave); - } - } - } - - @Override - public void rdbGtidSetParsed() { - for (final RedisSlave redisSlave : redisKeeperServer.slaves()) { - if (redisSlave.getSlaveState() == SLAVE_STATE.REDIS_REPL_WAIT_RDB_GTIDSET) { - getLogger().info("[doWhenDumping][slave waiting for rdb, resume]{}", redisSlave); + getLogger().info("[doWhenAuxParsed][slave waiting for rdb, resume]{}", redisSlave); continueSlaveFsync(redisSlave); } } @@ -125,8 +119,12 @@ public void tryFullSync(RedisSlave redisSlave) throws IOException { lock.readLock().lock(); try { state = rdbDumpState; - if (state == WAIT_DUMPPING) { - getLogger().info("[tryFullSync][make slave waiting]{}", redisSlave); + if (state == WAIT_DUMPPING || state == DUMPING) { + getLogger().info("[tryFullSync][make slave waiting][status {}]{}", state, redisSlave); + redisSlave.waitForRdbDumping(); + return; + } else if (state == AUX_PARSED && !redisSlave.supportRdb(rdbType.get())) { + getLogger().info("[tryFullSync][make slave waiting][rdbType not support {}]{}", rdbType.get().name(), redisSlave); redisSlave.waitForRdbDumping(); return; } @@ -134,7 +132,7 @@ public void tryFullSync(RedisSlave redisSlave) throws IOException { lock.readLock().unlock(); } switch (state) { - case DUMPING: + case AUX_PARSED: doFullSyncOrGiveUp(redisSlave); break; case FAIL: @@ -155,11 +153,17 @@ public void tryFullSync(RedisSlave redisSlave) throws IOException { } } + @Override + public void auxParseFinished(RdbStore.Type type) { + getLogger().info("[auxParseFinished][{}]{}", type.name(), this); + this.rdbType.set(type); + setRdbDumpState(RdbDumpState.AUX_PARSED); + } + @Override public void beginReceiveRdbData(String replId, long masterOffset) { getLogger().info("[beginReceiveRdbData]{}", this); setRdbDumpState(RdbDumpState.DUMPING); - } @Override diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/AbstractRedisMasterReplication.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/AbstractRedisMasterReplication.java index 0c7ddeb46..36b6da50c 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/AbstractRedisMasterReplication.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/AbstractRedisMasterReplication.java @@ -22,7 +22,7 @@ import com.ctrip.xpipe.redis.core.protocal.cmd.Replconf; import com.ctrip.xpipe.redis.core.protocal.cmd.Replconf.ReplConfType; import com.ctrip.xpipe.redis.core.protocal.protocal.EofType; -import com.ctrip.xpipe.redis.core.proxy.endpoint.ProxyEndpointSelector; +import com.ctrip.xpipe.redis.core.redis.rdb.RdbConstant; import com.ctrip.xpipe.redis.core.store.RdbStore; import com.ctrip.xpipe.redis.keeper.RdbDumper; import com.ctrip.xpipe.redis.keeper.RedisKeeperServer; @@ -47,6 +47,7 @@ import io.netty.handler.logging.LoggingHandler; import java.io.IOException; +import java.util.Map; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -81,8 +82,6 @@ public abstract class AbstractRedisMasterReplication extends AbstractLifecycle i public static final int REPLCONF_INTERVAL_MILLI = 1000; - public static final int PSYNC_RETRY_INTERVAL_MILLI = 2000; - protected RedisMaster redisMaster; protected long connectedTime; @@ -95,8 +94,6 @@ public abstract class AbstractRedisMasterReplication extends AbstractLifecycle i protected AtomicReference> currentCommand = new AtomicReference>(null); - private ProxyEndpointSelector selector; - private int commandTimeoutMilli; protected RedisMasterReplicationObserver replicationObserver; @@ -242,8 +239,14 @@ public void masterConnected(Channel channel) { chain.add(listeningPortCommand()); // for proxy connect init time - Replconf capa = new Replconf(clientPool, ReplConfType.CAPA, scheduled, commandTimeoutMilli, - CAPA.EOF.toString(), CAPA.PSYNC2.toString()); + Replconf capa; + if (tryRordb()) { + capa = new Replconf(clientPool, ReplConfType.CAPA, scheduled, commandTimeoutMilli, + CAPA.EOF.toString(), CAPA.PSYNC2.toString(), CAPA.RORDB.toString()); + } else { + capa = new Replconf(clientPool, ReplConfType.CAPA, scheduled, commandTimeoutMilli, + CAPA.EOF.toString(), CAPA.PSYNC2.toString()); + } chain.add(new FailSafeCommandWrapper<>(capa)); try { @@ -432,24 +435,27 @@ public void reFullSync() { } @Override - public void readRdbGtidSet(RdbStore rdbStore, String gtidSet) { - // maybe this part should be in AbstractReplicationStorePsync - try { - logger.info("[readRdbGtidSet] {}", gtidSet); - //use rdbStore kept in RdbOnlyReplication if possible - redisMaster.getCurrentReplicationStore().checkAndUpdateRdbGtidSet(rdbStore, gtidSet); - } catch (IOException e) { - logger.error("[readRdbGtidSet][fail]", e); + public void readAuxEnd(RdbStore rdbStore, Map auxMap) { + String gtidSet = auxMap.getOrDefault(RdbConstant.REDIS_RDB_AUX_KEY_GTID, GtidSet.EMPTY_GTIDSET); + logger.info("[readAuxEnd][gtid] {}", gtidSet); + rdbStore.updateRdbGtidSet(gtidSet); + + RdbStore.Type rdbType = auxMap.containsKey(RdbConstant.REDIS_RDB_AUX_KEY_RORDB) ? RdbStore.Type.RORDB : RdbStore.Type.NORMAL; + logger.info("[readAuxEnd][rdb] {}", rdbType); + rdbStore.updateRdbType(rdbType); + doRdbTypeConfirm(rdbStore); + + if (null != rdbDumper.get()) { + // rdbDumper may be reset by dumpFail + rdbDumper.get().auxParseFinished(rdbType); } - - getRdbDumper().rdbGtidSetParsed(); } - @Override - public void readAuxEnd(RdbStore rdbStore) { - // no gtidset read when read aux end, may need refactor by capa gtid ? - if (!rdbStore.isGtidSetInit()) { - this.readRdbGtidSet(rdbStore, GtidSet.EMPTY_GTIDSET); + protected void doRdbTypeConfirm(RdbStore rdbStore) { + try { + redisMaster.getCurrentReplicationStore().confirmRdb(rdbStore); + } catch (Throwable th) { + dumpFail(th); } } diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisKeeperServer.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisKeeperServer.java index 27e864162..4644626af 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisKeeperServer.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisKeeperServer.java @@ -17,6 +17,7 @@ import com.ctrip.xpipe.concurrent.LongTimeAlertTask; import com.ctrip.xpipe.endpoint.DefaultEndPoint; import com.ctrip.xpipe.exception.XpipeRuntimeException; +import com.ctrip.xpipe.gtid.GtidSet; import com.ctrip.xpipe.lifecycle.LifecycleHelper; import com.ctrip.xpipe.netty.NettySimpleMessageHandler; import com.ctrip.xpipe.observer.NodeAdded; @@ -25,10 +26,12 @@ import com.ctrip.xpipe.redis.core.entity.KeeperMeta; import com.ctrip.xpipe.redis.core.meta.KeeperState; import com.ctrip.xpipe.redis.core.meta.MetaZkConfig; +import com.ctrip.xpipe.redis.core.protocal.CAPA; import com.ctrip.xpipe.redis.core.protocal.PsyncObserver; import com.ctrip.xpipe.redis.core.protocal.RedisProtocol; import com.ctrip.xpipe.redis.core.protocal.protocal.EofType; import com.ctrip.xpipe.redis.core.redis.operation.RedisOpParser; +import com.ctrip.xpipe.redis.core.redis.rdb.RdbConstant; import com.ctrip.xpipe.redis.core.store.*; import com.ctrip.xpipe.redis.keeper.*; import com.ctrip.xpipe.redis.keeper.config.KeeperConfig; @@ -55,19 +58,16 @@ import java.io.File; import java.io.IOException; -import java.sql.Time; -import java.util.Date; -import java.util.HashSet; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Set; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; -import static com.ctrip.xpipe.redis.core.store.FULLSYNC_FAIL_CAUSE.RDB_GTIDSET_NOT_READY; +import static com.ctrip.xpipe.redis.core.store.FULLSYNC_FAIL_CAUSE.FULLSYNC_PROGRESS_NOT_SUPPORTED; import static com.ctrip.xpipe.redis.keeper.SLAVE_STATE.*; /** @@ -83,6 +83,7 @@ public class DefaultRedisKeeperServer extends AbstractRedisServer implements Red // otherwise we hardly finish all old replication work before new replication start on master address changing private static final int DEFAULT_MASTER_EVENT_LOOP_SIZE = 1; private static final int DEFAULT_RDB_EVENT_LOOP_SIZE = 1; + private static final int DEFAULT_MASTER_CONFIG_EVENT_LOOP_SIZE = 1; public static String KEY_DEFAULT_KEEPER_WORKER_GROUP_THREAD_COUNT = "DEFAULT_KEEPER_WORKER_GROUP_THREAD_COUNT"; public static int DEFAULT_KEEPER_WORKER_GROUP_THREAD_COUNT = Integer.parseInt(System.getProperty(KEY_DEFAULT_KEEPER_WORKER_GROUP_THREAD_COUNT, "5")); @@ -108,6 +109,7 @@ public class DefaultRedisKeeperServer extends AbstractRedisServer implements Red private EventLoopGroup workerGroup; private NioEventLoopGroup masterEventLoopGroup; private NioEventLoopGroup rdbOnlyEventLoopGroup; + private NioEventLoopGroup masterConfigEventLoopGroup; private final Map> redisClients = new ConcurrentHashMap<>(); @@ -143,6 +145,10 @@ public class DefaultRedisKeeperServer extends AbstractRedisServer implements Red private volatile AtomicReference rdbDumper = new AtomicReference(null); private long lastDumpTime = -1; + + private AtomicLong lastRdbDumpTime = new AtomicLong(-1); + private AtomicLong lastRordbDumpTime = new AtomicLong(-1); + //for test private AtomicInteger rdbDumpTryCount = new AtomicInteger(); @@ -231,6 +237,7 @@ protected void doInitialize() throws Exception { workerGroup = new NioEventLoopGroup(DEFAULT_KEEPER_WORKER_GROUP_THREAD_COUNT, KeeperReplIdAwareThreadFactory.create(replId, "work-"+ threadPoolName)); masterEventLoopGroup = new NioEventLoopGroup(DEFAULT_MASTER_EVENT_LOOP_SIZE, KeeperReplIdAwareThreadFactory.create(replId, "master-" + threadPoolName)); rdbOnlyEventLoopGroup = new NioEventLoopGroup(DEFAULT_RDB_EVENT_LOOP_SIZE, KeeperReplIdAwareThreadFactory.create(replId, "rdbOnly-" + threadPoolName)); + masterConfigEventLoopGroup = new NioEventLoopGroup(DEFAULT_MASTER_CONFIG_EVENT_LOOP_SIZE, KeeperReplIdAwareThreadFactory.create(replId, "masterConfig-" + threadPoolName)); this.resetReplAfterLongTimeDown(); @@ -448,7 +455,7 @@ private boolean isMasterSame(Endpoint current, Endpoint target) { private void initAndStartMaster(Endpoint target) { try { this.keeperRedisMaster = new DefaultRedisMaster(this, (DefaultEndPoint)target, masterEventLoopGroup, - rdbOnlyEventLoopGroup, replicationStoreManager, scheduled, resourceManager); + rdbOnlyEventLoopGroup, masterConfigEventLoopGroup, replicationStoreManager, scheduled, resourceManager); if(getLifecycleState().isStopping() || getLifecycleState().isStopped()){ logger.info("[initAndStartMaster][stopped, exit]{}, {}", target, this); @@ -635,7 +642,8 @@ public void onFullSync(long masterRdbOffset) { } @Override - public void readRdbGtidSet(RdbStore rdbStore, String gtidSet) { + public void readAuxEnd(RdbStore rdbStore, Map auxMap) { + String gtidSet = auxMap.getOrDefault(RdbConstant.REDIS_RDB_AUX_KEY_GTID, GtidSet.EMPTY_GTIDSET); try { if (isStartIndexing) { EventMonitor.DEFAULT.logEvent("INDEX.START", replId + " - " + gtidSet); @@ -646,11 +654,6 @@ public void readRdbGtidSet(RdbStore rdbStore, String gtidSet) { } } - @Override - public void readAuxEnd(RdbStore rdbStore) { - /*NOOP*/ - } - @Override public void closeSlaves(String reason) { @@ -759,19 +762,31 @@ public void fullSyncToSlave(final RedisSlave redisSlave) throws IOException { return; } + boolean tryRordb = false; // slave and master all support rordb or not + if (redisSlave.capaOf(CAPA.RORDB) ) { + try { + logger.info("[fullSyncToSlave][rordb]{}", redisSlave); + tryRordb = keeperRedisMaster.checkMasterSupportRordb().get(); + logger.info("[fullSyncToSlave][rordb] masterSupport:{}", tryRordb); + } catch (Throwable th) { + logger.info("[fullSyncToSlave][rordb]{}", redisSlave, th); + } + } + if(rdbDumper.get() == null){ logger.info("[fullSyncToSlave][dumper null]{}", redisSlave); FullSyncListener fullSyncListener = new DefaultFullSyncListener(redisSlave); - FULLSYNC_FAIL_CAUSE failCause = getCurrentReplicationStore().fullSyncIfPossible(fullSyncListener); + FULLSYNC_FAIL_CAUSE failCause = getCurrentReplicationStore().fullSyncIfPossible(fullSyncListener, tryRordb); if(null != failCause){ - //go dump rdb + if (FULLSYNC_PROGRESS_NOT_SUPPORTED.equals(failCause)) { + logger.info("[fullSyncToSlave][progress not support][cancel slave]"); + redisSlave.close(); + return; + } + try{ - if (RDB_GTIDSET_NOT_READY.equals(failCause)) { - redisSlave.waitForGtidParse(); - } else { - dumpNewRdb(); - redisSlave.waitForRdbDumping(); - } + dumpNewRdb(tryRordb); + redisSlave.waitForRdbDumping(); }catch(AbstractRdbDumperException e){ logger.error("[fullSyncToSlave]", e); if(e.isCancelSlave()){ @@ -829,7 +844,7 @@ public synchronized void startIndexing() throws IOException { if (failCause != null) { try { - dumpNewRdb(); + dumpNewRdb(false); } catch (Throwable t) { logger.error("[startIndexing][dumpNewRdb] fail {}, {}", this, rdbDumper.get()); logger.error("[startIndexing][dumpNewRdb] fail", t); @@ -843,9 +858,9 @@ public boolean isStartIndexing() { return isStartIndexing; } - private RdbDumper dumpNewRdb() throws CreateRdbDumperException, SetRdbDumperException { + private RdbDumper dumpNewRdb(boolean tryRordb) throws CreateRdbDumperException, SetRdbDumperException { - RdbDumper rdbDumper = keeperRedisMaster.createRdbDumper(); + RdbDumper rdbDumper = keeperRedisMaster.createRdbDumper(tryRordb); setRdbDumper(rdbDumper); rdbDumper.execute(); return rdbDumper; @@ -881,14 +896,15 @@ public void setRdbDumper(RdbDumper newDumper, boolean force) throws SetRdbDumper logger.info("[setRdbDumper]{},{}", newDumper, force); rdbDumpTryCount.incrementAndGet(); + AtomicLong lastDumpTime = newDumper.tryRordb() ? lastRordbDumpTime : lastRdbDumpTime; - if(lastDumpTime > 0 && !force && (System.currentTimeMillis() - lastDumpTime < keeperConfig.getRdbDumpMinIntervalMilli())){ - logger.info("[setRdbDumper][too quick]{}", new Date(lastDumpTime)); - throw new SetRdbDumperException(lastDumpTime, keeperConfig.getRdbDumpMinIntervalMilli()); + if(lastDumpTime.get() > 0 && !force && (System.currentTimeMillis() - lastDumpTime.get() < keeperConfig.getRdbDumpMinIntervalMilli())){ + logger.info("[setRdbDumper][too quick]{}", new Date(lastDumpTime.get())); + throw new SetRdbDumperException(lastDumpTime.get(), keeperConfig.getRdbDumpMinIntervalMilli()); } if(rdbDumper.compareAndSet(null, newDumper)){ - lastDumpTime = System.currentTimeMillis(); + lastDumpTime.set(System.currentTimeMillis()); dumpListener(newDumper); return; } @@ -902,7 +918,7 @@ public void setRdbDumper(RdbDumper newDumper, boolean force) throws SetRdbDumper logger.error("[setRdbDumper][error cancel]" + olRdbDumper, e); } rdbDumper.set(newDumper); - lastDumpTime = System.currentTimeMillis(); + lastDumpTime.set(System.currentTimeMillis()); dumpListener(newDumper); }else{ throw new SetRdbDumperException(olRdbDumper); @@ -921,7 +937,8 @@ public void operationComplete(CommandFuture commandFuture) throws Exceptio if(!commandFuture.isSuccess()){ logger.info("[operationComplete][dump fail, clear dump time]", commandFuture.cause()); - lastDumpTime = 0; + AtomicLong lastDumpTime = newDumper.tryRordb() ? lastRordbDumpTime : lastRdbDumpTime; + lastDumpTime.set(0); } } }); @@ -933,6 +950,33 @@ public void clearRdbDumper(RdbDumper oldDumper) { logger.info("[clearRdbDumper]{}", oldDumper); if(!rdbDumper.compareAndSet(oldDumper, null)){ logger.warn("[clearRdbDumper][current is not request]{}, {}", oldDumper, rdbDumper.get()); + } else { + logger.debug("[clearRdbDumper] redump for waiting slaves if needed"); + List waitingSlaves = new ArrayList<>(); + int needRordbSlaves = 0; + for (final RedisSlave redisSlave : slaves()) { + if (redisSlave.getSlaveState() == SLAVE_STATE.REDIS_REPL_WAIT_RDB_DUMPING) { + waitingSlaves.add(redisSlave); + if (redisSlave.capaOf(CAPA.RORDB)) needRordbSlaves++; + } + } + + if (!waitingSlaves.isEmpty()) { + try { + logger.info("[clearRdbDumper][redump][rdb] waiting:{}, needRordb:{}", waitingSlaves.size(), needRordbSlaves); + dumpNewRdb(false); + } catch (Throwable th) { + logger.info("[clearRdbDumper][redump] fail", th); + waitingSlaves.forEach(redisSlave -> { + try { + logger.info("[redumpFailed][close]{}", redisSlave); + redisSlave.close(); + } catch (Throwable t) { + logger.error("[redumpFailed][close slave]", t); + } + }); + } + } } } @@ -1024,13 +1068,8 @@ public void beginWriteRdb(EofType eofType, String replId, long masterRdbOffset) } @Override - public void readRdbGtidSet(RdbStore rdbStore, String gtidSet) { - redisKeeperServer.readRdbGtidSet(rdbStore, gtidSet); - } - - @Override - public void readAuxEnd(RdbStore rdbStore) { - + public void readAuxEnd(RdbStore rdbStore, Map auxMap) { + redisKeeperServer.readAuxEnd(rdbStore, auxMap); } @Override diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisMaster.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisMaster.java index 5e9d442ec..8cde95501 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisMaster.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisMaster.java @@ -1,16 +1,22 @@ package com.ctrip.xpipe.redis.keeper.impl; +import com.ctrip.xpipe.api.command.CommandFuture; import com.ctrip.xpipe.api.endpoint.Endpoint; import com.ctrip.xpipe.api.server.PARTIAL_STATE; +import com.ctrip.xpipe.cache.TimeBoundCache; +import com.ctrip.xpipe.command.DefaultCommandFuture; import com.ctrip.xpipe.endpoint.DefaultEndPoint; import com.ctrip.xpipe.lifecycle.AbstractLifecycle; +import com.ctrip.xpipe.pool.XpipeNettyClientPool; import com.ctrip.xpipe.redis.core.protocal.MASTER_STATE; +import com.ctrip.xpipe.redis.core.protocal.cmd.ConfigGetCommand; import com.ctrip.xpipe.redis.core.store.ReplicationStore; import com.ctrip.xpipe.redis.core.store.ReplicationStoreManager; import com.ctrip.xpipe.redis.keeper.*; import com.ctrip.xpipe.redis.keeper.config.KeeperResourceManager; import io.netty.channel.nio.NioEventLoopGroup; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicBoolean; @@ -40,16 +46,24 @@ public class DefaultRedisMaster extends AbstractLifecycle implements RedisMaster private NioEventLoopGroup rdbOnlyEventLoopGroup; + private NioEventLoopGroup masterConfigEventLoopGroup; + + private XpipeNettyClientPool masterConfigClientPool; + private KeeperResourceManager keeperResourceManager; + private TimeBoundCache> rordbConfigFutureCache; + public DefaultRedisMaster(RedisKeeperServer redisKeeperServer, DefaultEndPoint endpoint, NioEventLoopGroup masterEventLoopGroup, - NioEventLoopGroup rdbOnlyEventLoopGroup, ReplicationStoreManager replicationStoreManager, ScheduledExecutorService scheduled, + NioEventLoopGroup rdbOnlyEventLoopGroup, NioEventLoopGroup masterConfigEventLoopGroup, + ReplicationStoreManager replicationStoreManager, ScheduledExecutorService scheduled, KeeperResourceManager resourceManager) { this.redisKeeperServer = redisKeeperServer; this.replicationStoreManager = replicationStoreManager; this.masterEventLoopGroup = masterEventLoopGroup; this.rdbOnlyEventLoopGroup = rdbOnlyEventLoopGroup; + this.masterConfigEventLoopGroup = masterConfigEventLoopGroup; this.endpoint = endpoint; this.scheduled = scheduled; this.keeperResourceManager = resourceManager; @@ -64,23 +78,33 @@ protected void doInitialize() throws Exception { //init we treat is as redis redisKeeperServer.getKeeperMonitor().getMasterStats().setMasterRole(endpoint, SERVER_TYPE.REDIS); + GenericObjectPoolConfig config = new GenericObjectPoolConfig(); + config.setMaxTotal(1); + config.setJmxEnabled(false); + masterConfigClientPool = new XpipeNettyClientPool(endpoint, config); + masterConfigClientPool.initialize(); + + rordbConfigFutureCache = new TimeBoundCache<>(() -> 60000, this::refreshMasterConfigRordb); } @Override protected void doStart() throws Exception { super.doStart(); redisMasterReplication.start(); + masterConfigClientPool.start(); } @Override protected void doStop() throws Exception { redisMasterReplication.stop(); + masterConfigClientPool.stop(); super.doStop(); } @Override protected void doDispose() throws Exception { redisMasterReplication.dispose(); + masterConfigClientPool.dispose(); super.doDispose(); } @@ -112,13 +136,13 @@ public PARTIAL_STATE partialState() { @Override - public RdbDumper createRdbDumper() throws CreateRdbDumperException { + public RdbDumper createRdbDumper(boolean tryRrodb) throws CreateRdbDumperException { if(masterState != MASTER_STATE.REDIS_REPL_CONNECTED){ logger.info("[createRdbDumper][master state not connected, dumper not allowed]{}", redisMasterReplication); throw new CreateRdbDumperException(this, "master state not connected, dumper not allowed:" + masterState); } - return new RedisMasterNewRdbDumper(this, redisKeeperServer, rdbOnlyEventLoopGroup, scheduled, keeperResourceManager); + return new RedisMasterNewRdbDumper(this, redisKeeperServer, tryRrodb, rdbOnlyEventLoopGroup, scheduled, keeperResourceManager); } public MASTER_STATE getMasterState() { @@ -162,4 +186,24 @@ public void setKeeper() { public boolean usingProxy() { return null != endpoint.getProxyProtocol(); } + + @Override + public CommandFuture checkMasterSupportRordb() { + return rordbConfigFutureCache.getData(); + } + + private CommandFuture refreshMasterConfigRordb() { + CommandFuture future = new DefaultCommandFuture<>(); + int timeoutMill = isKeeper() ? 3000 : 660; + ConfigGetCommand configGet = new ConfigGetCommand.ConfigGetRordbSync(masterConfigClientPool, scheduled, timeoutMill); + configGet.execute().addListener(commandFuture -> { + if (commandFuture.isSuccess()) { + future.setSuccess(commandFuture.get()); + } else { + future.setSuccess(false); + } + }); + return future; + } + } diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisMasterReplication.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisMasterReplication.java index cddf26921..6cdc1b46c 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisMasterReplication.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisMasterReplication.java @@ -46,6 +46,13 @@ public DefaultRedisMasterReplication(RedisMaster redisMaster, RedisKeeperServer super(redisKeeperServer, redisMaster, nioEventLoopGroup, scheduled, resourceManager); } + @Override + public boolean tryRordb() { + // capa rordb as default + // if the master support rordb, the slaves will most likely support it too + return true; + } + @Override protected void doConnect(Bootstrap b) { diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisSlave.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisSlave.java index f6112dc7b..5f1e4e486 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisSlave.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/DefaultRedisSlave.java @@ -28,6 +28,8 @@ import java.io.IOException; import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; import java.util.Set; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; @@ -130,23 +132,6 @@ public void waitForRdbDumping() { } } - @Override - public void waitForGtidParse() { - - if(this.slaveState == SLAVE_STATE.REDIS_REPL_WAIT_RDB_GTIDSET){ - getLogger().info("[waitForGtidParse][already waiting]{}", this); - return; - } - - this.slaveState = SLAVE_STATE.REDIS_REPL_WAIT_RDB_GTIDSET; - - if (null == pingFuture || pingFuture.isDone()) { - waitForRdb(); - } else { - getLogger().info("[waitForGtidParse][already start wait]{}", this); - } - } - @Override public void waitForSeqFsync() { if(this.slaveState == SLAVE_STATE.REDIS_REPL_WAIT_SEQ_FSYNC) { @@ -435,6 +420,11 @@ public boolean supportProgress(Class> clazz) { return clazz.equals(OffsetReplicationProgress.class); } + @Override + public boolean supportRdb(RdbStore.Type rdbType) { + return (RdbStore.Type.RORDB.equals(rdbType) && capaOf(CAPA.RORDB)) || RdbStore.Type.NORMAL.equals(rdbType); + } + private int remotePort() { Channel channel = channel(); return channel == null? 0: ((InetSocketAddress)channel.remoteAddress()).getPort(); diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/RdbonlyRedisMasterReplication.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/RdbonlyRedisMasterReplication.java index 7e5b175c1..e29dd033c 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/RdbonlyRedisMasterReplication.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/RdbonlyRedisMasterReplication.java @@ -5,12 +5,15 @@ import com.ctrip.xpipe.redis.core.protocal.cmd.RdbOnlyPsync; import com.ctrip.xpipe.redis.core.protocal.protocal.EofType; import com.ctrip.xpipe.redis.core.store.DumpedRdbStore; +import com.ctrip.xpipe.redis.core.store.RdbStore; import com.ctrip.xpipe.redis.keeper.RdbDumper; import com.ctrip.xpipe.redis.keeper.RedisKeeperServer; import com.ctrip.xpipe.redis.keeper.RedisMaster; import com.ctrip.xpipe.redis.keeper.config.KeeperResourceManager; import com.ctrip.xpipe.redis.keeper.exception.psync.PsyncConnectMasterFailException; import com.ctrip.xpipe.redis.keeper.exception.psync.PsyncMasterRdbOffsetNotContinuousRuntimeException; +import com.ctrip.xpipe.redis.keeper.exception.psync.RdbOnlyPsyncReplIdNotSameException; +import com.ctrip.xpipe.redis.keeper.exception.replication.UnexpectedReplIdException; import com.ctrip.xpipe.redis.keeper.store.RdbOnlyReplicationStore; import com.ctrip.xpipe.utils.VisibleForTesting; import io.netty.bootstrap.Bootstrap; @@ -32,11 +35,19 @@ public class RdbonlyRedisMasterReplication extends AbstractRedisMasterReplicatio @VisibleForTesting DumpedRdbStore dumpedRdbStore; - public RdbonlyRedisMasterReplication(RedisKeeperServer redisKeeperServer, RedisMaster redisMaster, + private final boolean tryRordb; + + public RdbonlyRedisMasterReplication(RedisKeeperServer redisKeeperServer, RedisMaster redisMaster, boolean tryRordb, NioEventLoopGroup nioEventLoopGroup, ScheduledExecutorService scheduled, RdbDumper rdbDumper, KeeperResourceManager resourceManager) { super(redisKeeperServer, redisMaster, nioEventLoopGroup, scheduled, resourceManager); setRdbDumper(rdbDumper); + this.tryRordb = tryRordb; + } + + @Override + public boolean tryRordb() { + return tryRordb; } @Override @@ -93,6 +104,17 @@ public PARTIAL_STATE partialState() { return PARTIAL_STATE.FULL; } + @Override + protected void doRdbTypeConfirm(RdbStore rdbStore) { + try { + redisMaster.getCurrentReplicationStore().checkReplIdAndUpdateRdb(rdbStore); + } catch (UnexpectedReplIdException|IllegalStateException e) { + dumpFail(e); + } catch (Throwable th) { + logger.info("[doRdbTypeConfirm][checkReplIdAndUpdateRdb] fail", th); + } + } + @Override protected void doReFullSync() { throw new IllegalStateException("impossible to be here"); diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/RedisMasterNewRdbDumper.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/RedisMasterNewRdbDumper.java index dbc7d2dbd..27a433856 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/RedisMasterNewRdbDumper.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/RedisMasterNewRdbDumper.java @@ -39,16 +39,24 @@ public class RedisMasterNewRdbDumper extends AbstractRdbDumper { private final KeeperResourceManager resourceManager; - public RedisMasterNewRdbDumper(RedisMaster redisMaster, RedisKeeperServer redisKeeperServer, + private final boolean tryRordb; + + public RedisMasterNewRdbDumper(RedisMaster redisMaster, RedisKeeperServer redisKeeperServer, boolean tryRordb, NioEventLoopGroup nioEventLoopGroup, ScheduledExecutorService scheduled, KeeperResourceManager resourceManager) { super(redisKeeperServer); this.redisMaster = redisMaster; + this.tryRordb = tryRordb; this.nioEventLoopGroup = nioEventLoopGroup; this.scheduled = scheduled; this.resourceManager = resourceManager; } + @Override + public boolean tryRordb() { + return tryRordb; + } + @Override protected void doExecute() throws Exception { startRdbOnlyReplication(); @@ -79,7 +87,7 @@ protected void releaseResource() { } protected void startRdbOnlyReplication() throws Exception { - rdbonlyRedisMasterReplication = new RdbonlyRedisMasterReplication(redisKeeperServer, redisMaster, nioEventLoopGroup, scheduled, this, resourceManager); + rdbonlyRedisMasterReplication = new RdbonlyRedisMasterReplication(redisKeeperServer, redisMaster, tryRordb, nioEventLoopGroup, scheduled, this, resourceManager); rdbonlyRedisMasterReplication.initialize(); rdbonlyRedisMasterReplication.start(); @@ -106,18 +114,18 @@ public void beginReceiveRdbData(String replId, long masterOffset) { try { logger.info("[beginReceiveRdbData][update rdb]{}", dumpedRdbStore); - redisMaster.getCurrentReplicationStore().checkReplIdAndUpdateRdb(dumpedRdbStore, replId); + redisMaster.getCurrentReplicationStore().checkReplId(replId); super.beginReceiveRdbData(replId, masterOffset); } catch (UnexpectedReplIdException e) { dumpFail(new RdbOnlyPsyncReplIdNotSameException("[beginReceiveRdbData]", e)); - } catch (IOException e) { - logger.error("[beginReceiveRdbData]", e); + } catch (Throwable th) { + logger.error("[beginReceiveRdbData]", th); } } @Override public String toString() { - return String.format("%s(%s)", getClass().getSimpleName(), rdbonlyRedisMasterReplication); + return String.format("%s(%s)[%s]", getClass().getSimpleName(), rdbonlyRedisMasterReplication, tryRordb); } @Override diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/RedisMasterReplicationRdbDumper.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/RedisMasterReplicationRdbDumper.java index 4b099bf8f..c7dde7e52 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/RedisMasterReplicationRdbDumper.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/impl/RedisMasterReplicationRdbDumper.java @@ -21,6 +21,11 @@ public RedisMasterReplicationRdbDumper(RedisMasterReplication redisMasterReplica this.redisMasterReplication = redisMasterReplication; } + @Override + public boolean tryRordb() { + return redisMasterReplication.tryRordb(); + } + @Override protected void doExecute() throws Exception { //nothing to do diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/ratelimit/LeakyBucketBasedMasterReplicationListener.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/ratelimit/LeakyBucketBasedMasterReplicationListener.java index d1c68595c..4e79c21c2 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/ratelimit/LeakyBucketBasedMasterReplicationListener.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/ratelimit/LeakyBucketBasedMasterReplicationListener.java @@ -19,6 +19,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.Map; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -144,12 +145,7 @@ public void onFullSync(long masterRdbOffset) { } @Override - public void readRdbGtidSet(RdbStore rdbStore, String gtidSet) { - - } - - @Override - public void readAuxEnd(RdbStore rdbStore) { + public void readAuxEnd(RdbStore rdbStore, Map auxMap) { } diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultDumpedRdbStore.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultDumpedRdbStore.java index 3ad8595cc..638bb349b 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultDumpedRdbStore.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultDumpedRdbStore.java @@ -15,12 +15,12 @@ public class DefaultDumpedRdbStore extends DefaultRdbStore implements DumpedRdbStore{ public DefaultDumpedRdbStore(File file) throws IOException { - super(file, -1, null); + super(file, null, -1, null); } @Override - public EofType getEofType() { - return this.eofType; + public void setReplId(String replId) { + this.replId = replId; } @@ -29,11 +29,6 @@ public void setEofType(EofType eofType) { this.eofType = eofType; } - @Override - public File getRdbFile() { - return file; - } - @Override public void setRdbOffset(long rdbOffset){ this.rdbOffset = rdbOffset; diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultFullSyncListener.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultFullSyncListener.java index 0f8af27cf..a9d40c4e4 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultFullSyncListener.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultFullSyncListener.java @@ -4,6 +4,7 @@ import com.ctrip.xpipe.redis.core.protocal.protocal.EofType; import com.ctrip.xpipe.redis.core.store.CommandFile; import com.ctrip.xpipe.redis.core.store.FullSyncListener; +import com.ctrip.xpipe.redis.core.store.RdbStore; import com.ctrip.xpipe.redis.core.store.ReplicationProgress; import com.ctrip.xpipe.redis.keeper.RedisSlave; import io.netty.channel.ChannelFuture; @@ -11,6 +12,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.List; import java.util.concurrent.atomic.AtomicLong; /** @@ -30,6 +32,11 @@ public DefaultFullSyncListener(RedisSlave redisSlave) { this.redisSlave = redisSlave; } + @Override + public boolean supportRdb(RdbStore.Type rdbType) { + return redisSlave.supportRdb(rdbType); + } + @Override public void onFileData(ReferenceFileRegion referenceFileRegion) { diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultRdbStore.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultRdbStore.java index 5c45393f0..6a4e1e2e0 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultRdbStore.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultRdbStore.java @@ -44,6 +44,8 @@ public class DefaultRdbStore extends AbstractStore implements RdbStore { private AtomicReference status = new AtomicReference<>(Status.Writing); + protected String replId; + protected long rdbOffset; private AtomicInteger refCount = new AtomicInteger(0); @@ -51,12 +53,16 @@ public class DefaultRdbStore extends AbstractStore implements RdbStore { protected List rdbStoreListeners = new LinkedList<>(); private Object truncateLock = new Object(); + + private AtomicReference typeRef; - public DefaultRdbStore(File file, long rdbOffset, EofType eofType) throws IOException { + public DefaultRdbStore(File file, String replId, long rdbOffset, EofType eofType) throws IOException { + this.replId = replId; this.file = file; this.eofType = eofType; this.rdbOffset = rdbOffset; + this.typeRef = new AtomicReference<>(Type.UNKNOWN); if(file.length() > 0){ checkAndSetRdbState(); @@ -65,7 +71,37 @@ public DefaultRdbStore(File file, long rdbOffset, EofType eofType) throws IOExce channel = writeFile.getChannel(); } } - + + @Override + public String getReplId() { + return replId; + } + + @Override + public long getRdbOffset() { + return rdbOffset; + } + + @Override + public EofType getEofType() { + return this.eofType; + } + + @Override + public File getRdbFile() { + return file; + } + + @Override + public void updateRdbType(Type type) { + this.typeRef.compareAndSet(Type.UNKNOWN, type); + } + + @Override + public Type getRdbType() { + return typeRef.get(); + } + @Override public int writeRdb(ByteBuf byteBuf) throws IOException { makeSureOpen(); @@ -337,7 +373,8 @@ public long getSize(LongSupplier realSizeProvider) { @Override public String toString() { - return String.format("eofType:%s, rdbOffset:%d,file:%s, exists:%b, status:%s", eofType, rdbOffset, file, file.exists(), status.get()); + return String.format("type:%s, eofType:%s, rdbOffset:%d,file:%s, exists:%b, status:%s", + typeRef.get().name(), eofType, rdbOffset, file, file.exists(), status.get()); } @Override diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultReplicationStore.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultReplicationStore.java index 2c15df6c1..3aad6c423 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultReplicationStore.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DefaultReplicationStore.java @@ -6,6 +6,7 @@ import com.ctrip.xpipe.redis.core.protocal.protocal.LenEofType; import com.ctrip.xpipe.redis.core.store.*; import com.ctrip.xpipe.redis.keeper.config.KeeperConfig; +import com.ctrip.xpipe.redis.keeper.exception.replication.UnexpectedReplIdException; import com.ctrip.xpipe.redis.keeper.monitor.KeeperMonitor; import com.ctrip.xpipe.redis.keeper.store.cmd.OffsetCommandReaderWriterFactory; import com.ctrip.xpipe.redis.core.store.OffsetReplicationProgress; @@ -18,6 +19,7 @@ import java.io.File; import java.io.FileFilter; import java.io.IOException; +import java.util.Objects; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -42,6 +44,8 @@ public boolean accept(File path) { private AtomicReference rdbStoreRef = new AtomicReference<>(); + private AtomicReference rordbStoreRef = new AtomicReference<>(); + private ConcurrentMap previousRdbStores = new ConcurrentHashMap<>(); protected CommandStore cmdStore; @@ -85,60 +89,125 @@ public DefaultReplicationStore(File baseDir, KeeperConfig config, String keeperR if (meta != null && meta.getRdbFile() != null) { File rdb = new File(baseDir, meta.getRdbFile()); if (rdb.isFile()) { - rdbStoreRef.set(createRdbStore(rdb, meta.getRdbLastOffset(), initEofType(meta))); + rdbStoreRef.set(createRdbStore(rdb, meta.getReplId(), meta.getRdbLastOffset(), initRdbEofType(meta))); + rdbStoreRef.get().updateRdbType(RdbStore.Type.NORMAL); + rdbStoreRef.get().updateRdbGtidSet(null != meta.getRdbGtidSet() ? meta.getRdbGtidSet() : GtidSet.EMPTY_GTIDSET); + } + } + if (meta != null && meta.getRordbFile() != null) { + File rordb = new File(baseDir, meta.getRordbFile()); + if (rordb.isFile()) { + rordbStoreRef.set(createRdbStore(rordb, meta.getReplId(), meta.getRordbLastOffset(), initRordbEofType(meta))); + rordbStoreRef.get().updateRdbType(RdbStore.Type.RORDB); + rordbStoreRef.get().updateRdbGtidSet(null != meta.getRordbGtidSet() ? meta.getRordbGtidSet() : GtidSet.EMPTY_GTIDSET); } } if (null != meta && null != meta.getCmdFilePrefix()) { - cmdStore = createCommandStore(baseDir, meta, cmdFileSize, config, cmdReaderWriterFactory, keeperMonitor, rdbStoreRef.get()); + cmdStore = createCommandStore(baseDir, meta, cmdFileSize, config, cmdReaderWriterFactory, keeperMonitor); if (meta.getRdbLastOffset() != null) { cmdStore.setBaseIndex(meta.getRdbGtidSet(), meta.getRdbLastOffset() - (meta.getBeginOffset() - 1)); + } else if (meta.getRordbLastOffset() != null) { + cmdStore.setBaseIndex(meta.getRordbGtidSet(), meta.getRordbLastOffset() - (meta.getBeginOffset() - 1)); } } removeUnusedRdbFiles(); } - protected EofType initEofType(ReplicationStoreMeta meta) { + protected EofType initRdbEofType(ReplicationStoreMeta meta) { // must has length field - getLogger().info("[initEofType][leneof]{}", meta); + getLogger().info("[initRdbEofType][leneof]{}", meta); return new LenEofType(meta.getRdbFileSize()); } + protected EofType initRordbEofType(ReplicationStoreMeta meta) { + + // must has length field + getLogger().info("[initRordbEofType][leneof]{}", meta); + return new LenEofType(meta.getRordbFileSize()); + } + private void removeUnusedRdbFiles() { @SuppressWarnings("resource") - RdbStore rdbStore = rdbStoreRef.get() == null ? null : rdbStoreRef.get(); + RdbStore rdbStore = rdbStoreRef.get(); + RdbStore rordbStore = rordbStoreRef.get(); for (File rdbFile : rdbFilesOnFS()) { - if (rdbStore == null || !rdbStore.sameRdbFile(rdbFile)) { - getLogger().info("[removeUnusedRdbFile] {}", rdbFile); - rdbFile.delete(); - } + if (rdbStore != null && rdbStore.sameRdbFile(rdbFile)) continue; + if (rordbStore != null && rordbStore.sameRdbFile(rdbFile)) continue; + + getLogger().info("[removeUnusedRdbFile] {}", rdbFile); + rdbFile.delete(); } } @Override - public RdbStore beginRdb(String replId, long rdbOffset, EofType eofType) throws IOException { - + public RdbStore prepareRdb(String replId, long rdbOffset, EofType eofType) throws IOException { makeSureOpen(); - - getLogger().info("Begin RDB replId:{}, rdbOffset:{}, eof:{}", replId, rdbOffset, eofType); baseDir.mkdirs(); + getLogger().info("[makeRdb] replId:{}, rdbOffset:{}, eof:{}", replId, rdbOffset, eofType); String rdbFile = newRdbFileName(); + return createRdbStore(new File(baseDir, rdbFile), replId, rdbOffset, eofType); + } + + @Override + public void checkReplId(String expectReplId) { + String currentReplId = metaStore.getReplId(); + if (!Objects.equals(expectReplId, currentReplId)) { + throw new UnexpectedReplIdException(expectReplId, currentReplId); + } + } + + public void confirmRdb(RdbStore rdbStore) throws IOException { + makeSureOpen(); + + getLogger().info("[confirmRdb] type:{}, replId:{}, rdbOffset:{}, eof:{}", + rdbStore.getRdbType(), rdbStore.getReplId(), rdbStore.getRdbOffset(), rdbStore.getEofType()); + AtomicReference storeRef = RdbStore.Type.NORMAL.equals(rdbStore.getRdbType()) ? rdbStoreRef : rordbStoreRef; + String cmdFilePrefix = "cmd_" + UUID.randomUUID().toString() + "_"; - ReplicationStoreMeta newMeta = metaStore.rdbBegun(replId, rdbOffset + 1, rdbFile, eofType, - cmdFilePrefix); + ReplicationStoreMeta newMeta = metaStore.rdbConfirm(rdbStore.getReplId(), rdbStore.getRdbOffset() + 1, + rdbStore.getGtidSet(), rdbStore.getRdbFile().getName(), rdbStore.getRdbType(), rdbStore.getEofType(), cmdFilePrefix); - // beginOffset - 1 == masteroffset - RdbStore rdbStore = createRdbStore(new File(baseDir, newMeta.getRdbFile()), - newMeta.getBeginOffset() - 1, eofType); rdbStore.addListener(createRdbStoreListener(rdbStore)); - rdbStoreRef.set(rdbStore); - cmdStore = createCommandStore(baseDir, newMeta, cmdFileSize, config, cmdReaderWriterFactory, keeperMonitor, rdbStore); + storeRef.set(rdbStore); + cmdStore = createCommandStore(baseDir, newMeta, cmdFileSize, config, cmdReaderWriterFactory, keeperMonitor); + cmdStore.setBaseIndex(rdbStore.getGtidSet(), rdbStore.rdbOffset() - (newMeta.getBeginOffset() - 1)); + } - return rdbStoreRef.get(); + @Override + public void checkReplIdAndUpdateRdb(RdbStore rdbStore) throws IOException { + makeSureOpen(); + + synchronized (lock) { + rdbUpdateCount.incrementAndGet(); + + File dumpedRdbFile = rdbStore.getRdbFile(); + if (!baseDir.equals(dumpedRdbFile.getParentFile())) { + throw new IllegalStateException("update rdb error, filePath:" + dumpedRdbFile.getAbsolutePath() + + ", baseDir:" + baseDir.getAbsolutePath()); + } + EofType eofType = rdbStore.getEofType(); + long rdbOffset = rdbStore.rdbOffset(); + RdbStore.Type rdbType = rdbStore.getRdbType(); + String gtidSet = rdbStore.getGtidSet(); + AtomicReference storeRef = RdbStore.Type.NORMAL.equals(rdbType) ? rdbStoreRef : rordbStoreRef; + + @SuppressWarnings("unused") + ReplicationStoreMeta metaDup = metaStore.checkReplIdAndUpdateRdbInfo(dumpedRdbFile.getName(), + rdbType, eofType, rdbOffset, gtidSet, rdbStore.getReplId()); + + rdbStore.addListener(createRdbStoreListener(rdbStore)); + + getLogger().info("[checkReplIdAndUpdateRdb] new file:{}, type:{} eofType:{}, rdbOffset:{}", dumpedRdbFile, rdbType, eofType, rdbOffset); + RdbStore oldRdbStore = storeRef.get(); + storeRef.set(rdbStore); + if (null!= oldRdbStore) previousRdbStores.put(oldRdbStore, Boolean.TRUE); + cmdStore.setBaseIndex(rdbStore.getGtidSet(), rdbStore.rdbOffset() - (metaDup.getBeginOffset() - 1)); + } } @Override @@ -151,12 +220,12 @@ public void continueFromOffset(String replId, long continueOffset) throws IOExce String cmdFilePrefix = "cmd_" + UUID.randomUUID().toString() + "_"; ReplicationStoreMeta newMeta = metaStore.continueFromOffset(replId, continueOffset, cmdFilePrefix); - cmdStore = createCommandStore(baseDir, newMeta, cmdFileSize, config, cmdReaderWriterFactory, keeperMonitor, null); + cmdStore = createCommandStore(baseDir, newMeta, cmdFileSize, config, cmdReaderWriterFactory, keeperMonitor); } protected CommandStore createCommandStore(File baseDir, ReplicationStoreMeta replMeta, int cmdFileSize, KeeperConfig config, CommandReaderWriterFactory cmdReaderWriterFactory, - KeeperMonitor keeperMonitor, RdbStore rdbStore) throws IOException { + KeeperMonitor keeperMonitor) throws IOException { DefaultCommandStore cmdStore = new DefaultCommandStore(new File(baseDir, replMeta.getCmdFilePrefix()), cmdFileSize, config::getReplicationStoreCommandFileKeepTimeSeconds, config.getReplicationStoreMinTimeMilliToGcAfterCreate(), @@ -173,8 +242,8 @@ protected CommandStore createCommandStore(File baseDir, ReplicationStoreMeta rep return cmdStore; } - protected RdbStore createRdbStore(File rdb, long rdbOffset, EofType eofType) throws IOException { - return new DefaultRdbStore(rdb, rdbOffset, eofType); + protected RdbStore createRdbStore(File rdb, String replId, long rdbOffset, EofType eofType) throws IOException { + return new DefaultRdbStore(rdb, replId, rdbOffset, eofType); } protected RdbStoreListener createRdbStoreListener(RdbStore rdbStore) { @@ -189,52 +258,6 @@ public DumpedRdbStore prepareNewRdb() throws IOException { return rdbStore; } - @Override - public void checkReplIdAndUpdateRdb(DumpedRdbStore dumpedRdbStore, String expectedReplId) throws IOException { - - makeSureOpen(); - - synchronized (lock) { - rdbUpdateCount.incrementAndGet(); - - File dumpedRdbFile = dumpedRdbStore.getRdbFile(); - if (!baseDir.equals(dumpedRdbFile.getParentFile())) { - throw new IllegalStateException("update rdb error, filePath:" + dumpedRdbFile.getAbsolutePath() - + ", baseDir:" + baseDir.getAbsolutePath()); - } - EofType eofType = dumpedRdbStore.getEofType(); - long rdbOffset = dumpedRdbStore.rdbOffset(); - - @SuppressWarnings("unused") - ReplicationStoreMeta metaDup = metaStore.checkReplIdAndUpdateRdbInfo(dumpedRdbFile.getName(), eofType, rdbOffset, expectedReplId); - - dumpedRdbStore.addListener(createRdbStoreListener(dumpedRdbStore)); - - getLogger().info("[rdbUpdated] new file {}, eofType {}, rdbOffset {}", dumpedRdbFile, eofType, rdbOffset); - RdbStore oldRdbStore = rdbStoreRef.get(); - rdbStoreRef.set(dumpedRdbStore); - if (null!= oldRdbStore) previousRdbStores.put(oldRdbStore, Boolean.TRUE); - } - } - - @Override - public void checkAndUpdateRdbGtidSet(RdbStore rdbStore, String rdbGtidSet) throws IOException { - - makeSureOpen(); - - if (rdbGtidSet == null) { - return; - } - - synchronized (lock) { - // when switching to GtidReplicationStore via rdb only repl, rdbStore is of GtidRdbStore and this is of DefaultReplicationStore - // which maybe it is not a elegant way - rdbStore.updateRdbGtidSet(rdbGtidSet); - //probably redundant - getMetaStore().attachRdbGtidSet(rdbStore.getRdbFileName(), rdbGtidSet); - } - } - public RdbStore getRdbStore() { return rdbStoreRef.get(); } @@ -301,6 +324,11 @@ public long lastReplDataUpdatedAt() { return rdbStore.getRdbFileLastModified(); } + RdbStore rordbStore = rordbStoreRef.get(); + if (null != rordbStore) { + return rordbStore.getRdbFileLastModified(); + } + return 0L; } @@ -309,44 +337,54 @@ private File[] rdbFilesOnFS() { return rdbFiles != null ? rdbFiles : new File[0]; } - protected FullSyncContext lockAndCheckIfFullSyncPossible() { + protected FullSyncContext lockAndCheckIfRordbFullSyncPossible() { + synchronized (lock) { + getLogger().info("[lockAndCheckIfRordbFullSyncPossible]"); + return lockAndCheckIfFullSyncPossible(rordbStoreRef.get()); + } + } + protected FullSyncContext lockAndCheckIfRdbFullSyncPossible() { synchronized (lock) { - RdbStore rdbStore = rdbStoreRef.get(); - if (rdbStore == null || !rdbStore.checkOk()) { - getLogger().info("[lockAndCheckIfFullSyncPossible][false]{}", rdbStore); - return new FullSyncContext(false, FULLSYNC_FAIL_CAUSE.RDB_NOT_OK); - } + getLogger().info("[lockAndCheckIfRdbFullSyncPossible]"); + return lockAndCheckIfFullSyncPossible(rdbStoreRef.get()); + } + } - rdbStore.incrementRefCount(); - long rdbOffset = rdbStore.rdbOffset(); - long minOffset = firstAvailableOffset(); - long maxOffset = getEndOffset(); - - /** - * rdb and cmd is continuous AND not so much cmd after rdb - */ - long cmdAfterRdbThreshold = config.getReplicationStoreMaxCommandsToTransferBeforeCreateRdb(); - FullSyncContext context; - if (minOffset > rdbOffset + 1) { - getLogger().info("minOffset > rdbOffset + 1"); - getLogger().info("[isFullSyncPossible][false][miss cmd after rdb] {} <= {} + 1", minOffset, rdbOffset); - context = new FullSyncContext(false, FULLSYNC_FAIL_CAUSE.MISS_CMD_AFTER_RDB); - } else if (maxOffset - rdbOffset > cmdAfterRdbThreshold) { - getLogger().info("maxOffset - rdbOffset > cmdAfterRdbThreshold"); - getLogger().info("[isFullSyncPossible][false][too much cmd after rdb] {} - {} <= {}", - maxOffset, rdbOffset, cmdAfterRdbThreshold); - context = new FullSyncContext(false, FULLSYNC_FAIL_CAUSE.TOO_MUCH_CMD_AFTER_RDB); - } else { - getLogger().info("minOffset <= rdbOffset + 1 && maxOffset - rdbOffset <= cmdAfterRdbThreshold"); - getLogger().info("[isFullSyncPossible][true] {} <= {} + 1 && {} - {} <= {}", - minOffset, rdbOffset, maxOffset, rdbOffset, cmdAfterRdbThreshold); - context = new FullSyncContext(true, rdbStore); - } + protected FullSyncContext lockAndCheckIfFullSyncPossible(RdbStore rdbStore) { + if (rdbStore == null || !rdbStore.checkOk()) { + getLogger().info("[lockAndCheckIfFullSyncPossible][false]{}", rdbStore); + return new FullSyncContext(false, FULLSYNC_FAIL_CAUSE.RDB_NOT_OK); + } - if (!context.isFullSyncPossible()) rdbStore.decrementRefCount(); - return context; + rdbStore.incrementRefCount(); + long rdbOffset = rdbStore.rdbOffset(); + long minOffset = firstAvailableOffset(); + long maxOffset = getEndOffset(); + + /** + * rdb and cmd is continuous AND not so much cmd after rdb + */ + long cmdAfterRdbThreshold = config.getReplicationStoreMaxCommandsToTransferBeforeCreateRdb(); + FullSyncContext context; + if (minOffset > rdbOffset + 1) { + getLogger().info("minOffset > rdbOffset + 1"); + getLogger().info("[isFullSyncPossible][false][miss cmd after rdb] {} <= {} + 1", minOffset, rdbOffset); + context = new FullSyncContext(false, FULLSYNC_FAIL_CAUSE.MISS_CMD_AFTER_RDB); + } else if (maxOffset - rdbOffset > cmdAfterRdbThreshold) { + getLogger().info("maxOffset - rdbOffset > cmdAfterRdbThreshold"); + getLogger().info("[isFullSyncPossible][false][too much cmd after rdb] {} - {} <= {}", + maxOffset, rdbOffset, cmdAfterRdbThreshold); + context = new FullSyncContext(false, FULLSYNC_FAIL_CAUSE.TOO_MUCH_CMD_AFTER_RDB); + } else { + getLogger().info("minOffset <= rdbOffset + 1 && maxOffset - rdbOffset <= cmdAfterRdbThreshold"); + getLogger().info("[isFullSyncPossible][true] {} <= {} + 1 && {} - {} <= {}", + minOffset, rdbOffset, maxOffset, rdbOffset, cmdAfterRdbThreshold); + context = new FullSyncContext(true, rdbStore); } + + if (!context.isFullSyncPossible()) rdbStore.decrementRefCount(); + return context; } protected String newRdbFileName() { @@ -355,13 +393,28 @@ protected String newRdbFileName() { @Override public FULLSYNC_FAIL_CAUSE fullSyncIfPossible(FullSyncListener fullSyncListener) throws IOException { + return fullSyncIfPossible(fullSyncListener, false); + } + + @Override + public FULLSYNC_FAIL_CAUSE fullSyncIfPossible(FullSyncListener fullSyncListener, boolean tryRordb) throws IOException { makeSureOpen(); if (!fullSyncListener.supportProgress(OffsetReplicationProgress.class)) { - return FULLSYNC_FAIL_CAUSE.FULLSYNC_TYPE_NOT_SUPPORTED; + return FULLSYNC_FAIL_CAUSE.FULLSYNC_PROGRESS_NOT_SUPPORTED; } - final FullSyncContext ctx = lockAndCheckIfFullSyncPossible(); + return doFullSyncIfPossible(fullSyncListener, tryRordb); + } + + protected FULLSYNC_FAIL_CAUSE doFullSyncIfPossible(FullSyncListener fullSyncListener, boolean tryRordb) throws IOException { + if (fullSyncListener.supportRdb(RdbStore.Type.RORDB)) { + final FullSyncContext ctx = lockAndCheckIfRordbFullSyncPossible(); + if (ctx.isFullSyncPossible()) return tryDoFullSync(ctx, fullSyncListener); + else if (tryRordb) return ctx.getCause(); + } + + final FullSyncContext ctx = lockAndCheckIfRdbFullSyncPossible(); if (ctx.isFullSyncPossible()) { return tryDoFullSync(ctx, fullSyncListener); } else { @@ -373,13 +426,13 @@ protected FULLSYNC_FAIL_CAUSE tryDoFullSync(FullSyncContext ctx, FullSyncListene RdbStore rdbStore = ctx.getRdbStore(); if (null != cmdStore && !cmdStore.retainCommands( new DefaultCommandsGuarantee(fullSyncListener, beginOffset(), rdbStore.rdbOffset() + 1, commandsRetainTimeoutMilli))) { - getLogger().info("[fullSyncToSlave][cmd file deleted and terminate]{}", fullSyncListener); + getLogger().info("[fullSyncToSlave][{}][cmd file deleted and terminate]{}", rdbStore.getRdbType().name(), fullSyncListener); rdbStore.decrementRefCount(); return FULLSYNC_FAIL_CAUSE.MISS_CMD_AFTER_RDB; } try { - getLogger().info("[fullSyncToSlave][reuse current rdb to full sync]{}", fullSyncListener); + getLogger().info("[fullSyncToSlave][{}][reuse current rdb to full sync]{}", rdbStore.getRdbType().name(), fullSyncListener); // after rdb send over, command will be sent automatically rdbStore.readRdbFile(fullSyncListener); } finally { @@ -463,11 +516,6 @@ public ReplicationStoreRdbFileListener(RdbStore rdbStore) { this.rdbStore = rdbStore; } - @Override - public void onRdbGtidSet(String gtidSet) { - - } - @Override public void onEndRdb() { try { @@ -504,17 +552,22 @@ public void destroy() throws Exception { FileUtils.recursiveDelete(baseDir); } + private void gcRdbIfNeeded(AtomicReference rdbStoreRef) throws IOException { + RdbStore originRdbStore = rdbStoreRef.get(); + if (null != originRdbStore && !originRdbStore.isWriting() + && originRdbStore.rdbOffset() + 1 < firstAvailableOffset() + && rdbStoreRef.compareAndSet(originRdbStore, null)) { + getLogger().info("[gc][release rdb for cmd not continue] {}", originRdbStore); + previousRdbStores.put(originRdbStore, Boolean.TRUE); + metaStore.releaseRdbFile(originRdbStore.getRdbFileName()); + } + } + @Override public boolean gc() throws IOException { synchronized (lock) { - RdbStore originRdbStore = rdbStoreRef.get(); - if (null != originRdbStore && !originRdbStore.isWriting() - && originRdbStore.rdbOffset() + 1 < firstAvailableOffset() - && rdbStoreRef.compareAndSet(originRdbStore, null)) { - getLogger().info("[gc][release rdb for cmd not continue] {}", originRdbStore); - previousRdbStores.put(originRdbStore, Boolean.TRUE); - metaStore.releaseRdbFile(originRdbStore.getRdbFileName()); - } + gcRdbIfNeeded(rdbStoreRef); + gcRdbIfNeeded(rordbStoreRef); } // delete old rdb files diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DumpedGtidRdbStore.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DumpedGtidRdbStore.java index ba72022df..aec1bd577 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DumpedGtidRdbStore.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/DumpedGtidRdbStore.java @@ -13,7 +13,7 @@ public class DumpedGtidRdbStore extends GtidRdbStore implements DumpedRdbStore { public DumpedGtidRdbStore(File file) throws IOException { - super(file, -1, null, null); + super(file, null, -1, null, null); } @Override @@ -21,15 +21,15 @@ public EofType getEofType() { return this.eofType; } - @Override - public void setEofType(EofType eofType) { - this.eofType = eofType; + public void setReplId(String replId) { + this.replId = replId; } + @Override - public File getRdbFile() { - return file; + public void setEofType(EofType eofType) { + this.eofType = eofType; } @Override diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/FullSyncContext.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/FullSyncContext.java index 0ed8c8329..d7ffe5d85 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/FullSyncContext.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/FullSyncContext.java @@ -16,6 +16,8 @@ public class FullSyncContext { private FULLSYNC_FAIL_CAUSE cause; + private boolean tryRordb = false; + public FullSyncContext(boolean fullSyncPossible, FULLSYNC_FAIL_CAUSE cause) { this.fullSyncPossible = fullSyncPossible; this.cause = cause; @@ -26,6 +28,14 @@ public FullSyncContext(boolean fullSyncPossible, RdbStore rdbStore) { this.rdbStore = rdbStore; } + public boolean isTryRordb() { + return tryRordb; + } + + public void setTryRordb(boolean tryRordb) { + this.tryRordb = tryRordb; + } + public boolean isFullSyncPossible() { return fullSyncPossible; } diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/GtidCommandStore.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/GtidCommandStore.java index 7366c0c48..35166216d 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/GtidCommandStore.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/GtidCommandStore.java @@ -102,6 +102,7 @@ public void setBaseIndex(String baseGtidSet, long localOffset) { //when fullSync or when keeperSync, rdbGtidSet come up later; //but when keeperRestart, rdbGtidSet come up immediately from meta.json + logger.info("[setBaseIndex]{}-{}",localOffset, baseGtidSet); this.baseGtidSet = new GtidSet(baseGtidSet); this.baseStartOffset = localOffset; } diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/GtidRdbStore.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/GtidRdbStore.java index 99c607268..fe190c62f 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/GtidRdbStore.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/GtidRdbStore.java @@ -6,15 +6,12 @@ import com.ctrip.xpipe.redis.core.store.GtidSetReplicationProgress; import com.ctrip.xpipe.redis.core.store.RdbFileListener; import com.ctrip.xpipe.redis.core.store.RdbStore; -import com.ctrip.xpipe.redis.core.store.RdbStoreListener; import io.netty.buffer.ByteBuf; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.atomic.AtomicReference; /** @@ -27,12 +24,9 @@ public class GtidRdbStore extends DefaultRdbStore implements RdbStore { private AtomicReference gtidSet = new AtomicReference<>(); - private final List waitAuxListener; - - public GtidRdbStore(File file, long rdbOffset, EofType eofType, String gtidSet) throws IOException { - super(file, rdbOffset, eofType); + public GtidRdbStore(File file, String replId, long rdbOffset, EofType eofType, String gtidSet) throws IOException { + super(file, replId, rdbOffset, eofType); this.gtidSet.set(gtidSet); - this.waitAuxListener = new ArrayList<>(); } @Override @@ -60,12 +54,7 @@ public int writeRdb(ByteBuf byteBuf) throws IOException { @Override public boolean updateRdbGtidSet(String gtidSet) { - if (this.gtidSet.compareAndSet(null, gtidSet)) { - notifyListenersRdbGtidSet(gtidSet); - return true; - } - - return false; + return this.gtidSet.compareAndSet(null, gtidSet); } @Override @@ -81,17 +70,6 @@ protected void doReadRdbFileInfo(RdbFileListener rdbFileListener) { rdbFileListener.setRdbFileInfo(eofType, new GtidSetReplicationProgress(new GtidSet(gtidSet.get()), rdbOffset)); } - protected void notifyListenersRdbGtidSet(String rdbGtidSet) { - - for(RdbStoreListener listener : rdbStoreListeners){ - try{ - listener.onRdbGtidSet(rdbGtidSet); - }catch(Throwable th){ - getLogger().error("[notifyListenersEndRdb]" + this, th); - } - } - } - @Override protected Logger getLogger() { return logger; diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/GtidReplicationStore.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/GtidReplicationStore.java index e679991e7..57a174384 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/GtidReplicationStore.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/GtidReplicationStore.java @@ -42,7 +42,7 @@ public GtidReplicationStore(File baseDir, KeeperConfig config, String keeperRuni @Override protected CommandStore createCommandStore(File baseDir, ReplicationStoreMeta replMeta, int cmdFileSize, KeeperConfig config, CommandReaderWriterFactory cmdReaderWriterFactory, - KeeperMonitor keeperMonitor, RdbStore rdbStore) throws IOException { + KeeperMonitor keeperMonitor) throws IOException { String replRdbGtidSet = replMeta.getRdbGtidSet(); logger.info("[createCommandStore], replRdbGtidSet={}", replRdbGtidSet); @@ -62,18 +62,8 @@ protected CommandStore createCommandStore(File baseDir, ReplicationStoreMeta rep } @Override - protected RdbStore createRdbStore(File rdb, long rdbOffset, EofType eofType) throws IOException { - ReplicationStoreMeta meta = getMetaStore().dupReplicationStoreMeta(); - if (meta.getRdbFile().equals(rdb.getName())) { - return new GtidRdbStore(rdb, rdbOffset, eofType, meta.getRdbGtidSet()); - } else { - return new GtidRdbStore(rdb, rdbOffset, eofType, null); - } - } - - @Override - protected RdbStoreListener createRdbStoreListener(RdbStore rdbStore) { - return new GtidReplicationStoreRdbFileListener(rdbStore); + protected RdbStore createRdbStore(File rdb, String replId, long rdbOffset, EofType eofType) throws IOException { + return new GtidRdbStore(rdb, replId, rdbOffset, eofType, null); } @Override @@ -92,24 +82,24 @@ public DumpedRdbStore prepareNewRdb() throws IOException { } @Override - public FULLSYNC_FAIL_CAUSE fullSyncIfPossible(FullSyncListener fullSyncListener) throws IOException { + public FULLSYNC_FAIL_CAUSE fullSyncIfPossible(FullSyncListener fullSyncListener, boolean tryRordb) throws IOException { makeSureOpen(); if (!fullSyncListener.supportProgress(GtidSetReplicationProgress.class)) { - return super.fullSyncIfPossible(fullSyncListener); + return super.fullSyncIfPossible(fullSyncListener, tryRordb); } - FullSyncContext ctx = lockAndCheckIfFullSyncPossible(); - if (ctx.isFullSyncPossible() && !ctx.getRdbStore().isGtidSetInit()) { + return doFullSyncIfPossible(fullSyncListener, tryRordb); + } + + @Override + protected FULLSYNC_FAIL_CAUSE tryDoFullSync(FullSyncContext ctx, FullSyncListener fullSyncListener) throws IOException { + if (!ctx.getRdbStore().isGtidSetInit()) { ctx.getRdbStore().decrementRefCount(); - return FULLSYNC_FAIL_CAUSE.RDB_GTIDSET_NOT_READY; + throw new IllegalStateException("unexpected rdb with gtid not init: " + ctx.getRdbStore()); } - if (ctx.isFullSyncPossible()) { - return tryDoFullSync(ctx, fullSyncListener); - } else { - return ctx.getCause(); - } + return super.tryDoFullSync(ctx, fullSyncListener); } @Override @@ -117,28 +107,6 @@ protected Logger getLogger() { return logger; } - public class GtidReplicationStoreRdbFileListener extends ReplicationStoreRdbFileListener implements RdbStoreListener { - - public GtidReplicationStoreRdbFileListener(RdbStore rdbStore) { - super(rdbStore); - } - - @Override - public void onRdbGtidSet(String gtidSet) { - try { - getLogger().info("[onRdbGtidSet][update metastore] {} {}", rdbStore.getRdbFileName(), gtidSet); - getMetaStore().attachRdbGtidSet(rdbStore.getRdbFileName(), gtidSet); - - getLogger().info("[onRdbGtidSet][update metastore] info to init first index {} - ({} - 1) = {} : {}", - rdbStore.rdbOffset(), getMetaStore().beginOffset(), rdbStore.rdbOffset() - (getMetaStore().beginOffset() - 1), gtidSet); - cmdStore.setBaseIndex(gtidSet, rdbStore.rdbOffset() - (getMetaStore().beginOffset() - 1)); - } catch (IOException e) { - getLogger().error("[onRdbGtidSet][update metastore]", e); - } - } - - } - @Override public FULLSYNC_FAIL_CAUSE createIndexIfPossible(ExecutorService indexingExecutors) { @@ -148,10 +116,10 @@ public FULLSYNC_FAIL_CAUSE createIndexIfPossible(ExecutorService indexingExecuto return null; } - FullSyncContext ctx = lockAndCheckIfFullSyncPossible(); + FullSyncContext ctx = lockAndCheckIfRdbFullSyncPossible(); if (ctx.isFullSyncPossible() && !ctx.getRdbStore().isGtidSetInit()) { ctx.getRdbStore().decrementRefCount(); - return FULLSYNC_FAIL_CAUSE.RDB_GTIDSET_NOT_READY; + throw new IllegalStateException("unexpected rdb with gtid not init: " + ctx.getRdbStore()); } if (ctx.isFullSyncPossible()) { diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/RdbOnlyReplicationStore.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/RdbOnlyReplicationStore.java index 3cfa86487..51ef24600 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/RdbOnlyReplicationStore.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/RdbOnlyReplicationStore.java @@ -25,6 +25,18 @@ public RdbOnlyReplicationStore(DumpedRdbStore dumpedRdbStore) { this.dumpedRdbStore = dumpedRdbStore; metaStore = new MetaStore() { + @Override + public ReplicationStoreMeta rdbConfirm(String replId, long beginOffset, String gtidSet, String rdbFile, + RdbStore.Type type, EofType eofType, String cmdFilePrefix) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public ReplicationStoreMeta checkReplIdAndUpdateRdbInfo(String rdbFile, RdbStore.Type type, EofType eofType, + long rdbOffset, String gtidSet, String expectedReplId) throws IOException { + throw new UnsupportedOperationException(); + } + @Override public void setMasterAddress(DefaultEndPoint endpoint) { throw new UnsupportedOperationException(); @@ -130,6 +142,26 @@ public void releaseRdbFile(String rdbFile) throws IOException { }; } + @Override + public void checkReplId(String expectReplId) { + throw new UnsupportedOperationException(); + } + + @Override + public void confirmRdb(RdbStore rdbStore) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void checkReplIdAndUpdateRdb(RdbStore rdbStore) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public FULLSYNC_FAIL_CAUSE fullSyncIfPossible(FullSyncListener fullSyncListener, boolean masterSupportRordb) throws IOException { + throw new UnsupportedOperationException(); + } + @Override public void close() throws IOException { dumpedRdbStore.close(); @@ -141,9 +173,10 @@ public void destroy() throws Exception { } @Override - public RdbStore beginRdb(String replId, long rdbOffset, EofType eofType) throws IOException { + public RdbStore prepareRdb(String replId, long rdbOffset, EofType eofType) throws IOException { this.replId = replId; this.rdbOffset = rdbOffset; + dumpedRdbStore.setReplId(replId); dumpedRdbStore.setRdbOffset(this.rdbOffset); dumpedRdbStore.setEofType(eofType); return dumpedRdbStore; @@ -209,16 +242,6 @@ public DumpedRdbStore prepareNewRdb() throws IOException { throw new UnsupportedOperationException(); } - @Override - public void checkReplIdAndUpdateRdb(DumpedRdbStore dumpedRdbStore, String expectedReplId) throws IOException { - throw new UnsupportedOperationException(); - } - - @Override - public void checkAndUpdateRdbGtidSet(RdbStore rdbStore, String rdbGtidSet) throws IOException { - throw new UnsupportedOperationException(); - } - @Override public void addCommandsListener(ReplicationProgress progress, CommandsListener commandsListener) throws IOException { throw new UnsupportedOperationException(); diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/meta/AbstractMetaStore.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/meta/AbstractMetaStore.java index 22bec5b4e..4ff4bebb9 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/meta/AbstractMetaStore.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/meta/AbstractMetaStore.java @@ -6,6 +6,7 @@ import com.ctrip.xpipe.redis.core.protocal.RedisClientProtocol; import com.ctrip.xpipe.redis.core.protocal.protocal.EofType; import com.ctrip.xpipe.redis.core.store.MetaStore; +import com.ctrip.xpipe.redis.core.store.RdbStore; import com.ctrip.xpipe.redis.core.store.ReplicationStoreMeta; import com.ctrip.xpipe.redis.core.store.exception.BadMetaStoreException; import com.ctrip.xpipe.redis.keeper.exception.RedisKeeperRuntimeException; @@ -155,6 +156,39 @@ private void setKeeperState(KeeperState keeperState) throws IOException { } } + @Override + public ReplicationStoreMeta checkReplIdAndUpdateRdbInfo(String rdbFile, RdbStore.Type type, EofType eofType, + long rdbOffset, String gtidSet, String expectedReplId) throws IOException { + synchronized (metaRef) { + + ReplicationStoreMeta metaDup = dupReplicationStoreMeta(); + + if (!Objects.equals(expectedReplId, metaDup.getReplId())) { + throw new UnexpectedReplIdException(expectedReplId, metaDup.getReplId()); + } + + if (RdbStore.Type.NORMAL.equals(type)) { + logger.info("[rdbUpdated] update rdbLastOffset to {}", rdbOffset); + metaDup.setRdbFile(rdbFile); + setRdbFileInfo(metaDup, eofType); + metaDup.setRdbLastOffset(rdbOffset); + metaDup.setRdbGtidSet(gtidSet); + } else if (RdbStore.Type.RORDB.equals(type)) { + logger.info("[rordbUpdated] update rordbLastOffset to {}", rdbOffset); + metaDup.setRordbFile(rdbFile); + setRordbFileInfo(metaDup, eofType); + metaDup.setRordbLastOffset(rdbOffset); + metaDup.setRordbGtidSet(gtidSet); + } else { + throw new IllegalStateException("unknown type " + (type == null?"null":type.name())); + } + + saveMeta(metaDup); + + return metaDup; + } + } + @Override public ReplicationStoreMeta checkReplIdAndUpdateRdbInfo(String rdbFile, EofType eofType, long rdbOffset, String expectedReplId) throws IOException { @@ -190,6 +224,19 @@ protected void setRdbFileInfo(ReplicationStoreMeta metaDup, EofType eofType) { } } + protected void setRordbFileInfo(ReplicationStoreMeta metaDup, EofType eofType) { + + String tag = eofType.getTag(); + + if(tag.length() == RedisClientProtocol.RUN_ID_LENGTH){ + metaDup.setRordbEofMark(tag); + metaDup.setRordbFileSize(-1); + }else{ + metaDup.setRordbFileSize(Long.valueOf(tag)); + metaDup.setRordbEofMark(null); + } + } + protected ReplicationStoreMeta getMeta() { return metaRef.get(); } diff --git a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/meta/DefaultMetaStore.java b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/meta/DefaultMetaStore.java index 8783c187f..d022741f7 100644 --- a/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/meta/DefaultMetaStore.java +++ b/redis/redis-keeper/src/main/java/com/ctrip/xpipe/redis/keeper/store/meta/DefaultMetaStore.java @@ -2,6 +2,7 @@ import com.ctrip.xpipe.endpoint.DefaultEndPoint; import com.ctrip.xpipe.redis.core.protocal.protocal.EofType; +import com.ctrip.xpipe.redis.core.store.RdbStore; import com.ctrip.xpipe.redis.core.store.ReplicationStoreMeta; import com.ctrip.xpipe.utils.ObjectUtils; @@ -49,6 +50,39 @@ public DefaultEndPoint getMasterAddress() { return getMeta().getMasterAddress(); } + @Override + public ReplicationStoreMeta rdbConfirm(String replId, long beginOffset, String gtidSet, String rdbFile, RdbStore.Type type, + EofType eofType, String cmdFilePrefix) throws IOException { + synchronized (metaRef) { + ReplicationStoreMeta metaDup = dupReplicationStoreMeta(); + + if (RdbStore.Type.NORMAL.equals(type)) { + metaDup.setRdbFile(rdbFile); + metaDup.setRdbGtidSet(null); + setRdbFileInfo(metaDup, eofType); + metaDup.setRdbLastOffset(beginOffset - 1); + metaDup.setRdbGtidSet(gtidSet); + } else if (RdbStore.Type.RORDB.equals(type)) { + metaDup.setRordbFile(rdbFile); + metaDup.setRordbGtidSet(null); + setRordbFileInfo(metaDup, eofType); + metaDup.setRordbLastOffset(beginOffset - 1); + metaDup.setRordbGtidSet(gtidSet); + } else { + throw new IllegalStateException("unknown type " + (type == null?"null":type.name())); + } + + metaDup.setReplId(replId); + metaDup.setBeginOffset(beginOffset); + metaDup.setCmdFilePrefix(cmdFilePrefix); + clearReplicationId2(metaDup); + + saveMeta(metaDup); + return metaDup; + } + + } + @Override public ReplicationStoreMeta rdbBegun(String replId, long beginOffset, String rdbFile, EofType eofType, String cmdFilePrefix) throws IOException { @@ -138,15 +172,18 @@ public void releaseRdbFile(String rdbFile) throws IOException { synchronized (metaRef) { ReplicationStoreMeta currentMeta = metaRef.get(); String currentRdbFile = currentMeta.getRdbFile(); + String currentRordbFile = currentMeta.getRordbFile(); - if (null == currentRdbFile) { - logger.info("[releaseRdbFile][{}][already no rdb]", rdbFile); - } else if (!currentRdbFile.equals(rdbFile)) { - logger.warn("[releaseRdbFile][{}] current {}, skip", rdbFile, currentRdbFile); - } else { + if (currentRdbFile != null && currentRdbFile.equals(rdbFile)) { ReplicationStoreMeta metaDup = dupReplicationStoreMeta(); clearRdb(metaDup); saveMeta(metaDup); + } else if (currentRordbFile != null && currentRordbFile.equals(rdbFile)) { + ReplicationStoreMeta metaDup = dupReplicationStoreMeta(); + clearRordb(metaDup); + saveMeta(metaDup); + } else { + logger.info("[releaseRdbFile][{}] currentRdb:{} currentRordb:{}, skip", rdbFile, currentRdbFile, currentRordbFile); } } } @@ -159,4 +196,12 @@ private void clearRdb(ReplicationStoreMeta metaDup) { metaDup.setRdbGtidSet(null); } + private void clearRordb(ReplicationStoreMeta metaDup) { + metaDup.setRordbFile(null); + metaDup.setRordbEofMark(null); + metaDup.setRordbFileSize(0); + metaDup.setRordbLastOffset(null); + metaDup.setRordbGtidSet(null); + } + } diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/AbstractFakeRedisTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/AbstractFakeRedisTest.java index bdab1f340..123ef1fc1 100644 --- a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/AbstractFakeRedisTest.java +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/AbstractFakeRedisTest.java @@ -18,10 +18,13 @@ import com.ctrip.xpipe.redis.keeper.RedisKeeperServer; import com.ctrip.xpipe.redis.keeper.config.KeeperConfig; import com.ctrip.xpipe.redis.keeper.config.TestKeeperConfig; +import com.ctrip.xpipe.utils.ObjectUtils; import org.junit.Assert; import org.junit.Before; import java.io.IOException; +import java.util.Arrays; +import java.util.Map; /** * @author wenchao.meng @@ -58,7 +61,7 @@ protected RedisKeeperServer startRedisKeeperServerAndConnectToFakeRedis(int repl protected RedisKeeperServer startRedisKeeperServerAndConnectToFakeRedis(int replicationStoreCommandFileNumToKeep, int replicationStoreMaxCommandsToTransferBeforeCreateRdb, int minTimeMilliToGcAfterCreate) throws Exception { - RedisKeeperServer redisKeeperServer = startRedisKeeperServer(replicationStoreCommandFileNumToKeep, replicationStoreMaxCommandsToTransferBeforeCreateRdb, 1000); + RedisKeeperServer redisKeeperServer = startRedisKeeperServer(replicationStoreCommandFileNumToKeep, replicationStoreMaxCommandsToTransferBeforeCreateRdb, minTimeMilliToGcAfterCreate); connectToFakeRedis(redisKeeperServer); return redisKeeperServer; } @@ -143,20 +146,20 @@ protected void connectToFakeRedis(RedisKeeperServer redisKeeperServer) { } protected void waitForPsyncResultEquals(InMemoryPsync psync) throws Exception { - waitConditionUntilTimeOut(() -> new String(psync.getRdb()).equals(fakeRedisServer.getRdbContent()) + waitConditionUntilTimeOut(() -> Arrays.equals(psync.getRdb(), fakeRedisServer.getRdbContent()) && new String(psync.getCommands()).equals(fakeRedisServer.currentCommands())); } protected void assertPsyncResultEquals(InMemoryPsync psync) { try{ - Assert.assertEquals(fakeRedisServer.getRdbContent(), new String(psync.getRdb())); + Assert.assertArrayEquals(fakeRedisServer.getRdbContent(), psync.getRdb()); Assert.assertEquals(fakeRedisServer.currentCommands(), new String(psync.getCommands())); }catch(Exception e){ logger.error("[assertPsyncResultEquals]", e); } - Assert.assertEquals(fakeRedisServer.getRdbContent(), new String(psync.getRdb())); + Assert.assertArrayEquals(fakeRedisServer.getRdbContent(), psync.getRdb()); Assert.assertEquals(fakeRedisServer.currentCommands(), new String(psync.getCommands())); } @@ -222,12 +225,7 @@ public void onKeeperContinue(String replId, long beginOffset) { } @Override - public void readRdbGtidSet(RdbStore rdbStore, String gtidSet) { - - } - - @Override - public void readAuxEnd(RdbStore rdbStore) { + public void readAuxEnd(RdbStore rdbStore, Map auxMap) { } diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/AbstractRedisKeeperTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/AbstractRedisKeeperTest.java index 1003e091d..4fb965053 100644 --- a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/AbstractRedisKeeperTest.java +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/AbstractRedisKeeperTest.java @@ -146,14 +146,14 @@ protected File getReplicationStoreManagerBaseDir(KeeperMeta keeper) { } - protected String readRdbFileTilEnd(ReplicationStore replicationStore) throws IOException, InterruptedException { + protected byte[] readRdbFileTilEnd(ReplicationStore replicationStore) throws IOException, InterruptedException { RdbStore rdbStore = ((DefaultReplicationStore)replicationStore).getRdbStore(); return readRdbFileTilEnd(rdbStore); } - protected String readRdbFileTilEnd(RdbStore rdbStore) throws IOException, InterruptedException { + protected byte[] readRdbFileTilEnd(RdbStore rdbStore) throws IOException, InterruptedException { final ByteArrayWritableByteChannel bachannel = new ByteArrayWritableByteChannel(); final CountDownLatch latch = new CountDownLatch(1); @@ -195,7 +195,7 @@ public void beforeFileData() { } }); latch.await(5, TimeUnit.SECONDS); - return new String(bachannel.getResult()); + return bachannel.getResult(); } public String readCommandFileTilEnd(final ReplicationStore replicationStore, int expectedLen) throws IOException { diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/AllTests.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/AllTests.java index 6e01984a2..e976e5841 100644 --- a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/AllTests.java +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/AllTests.java @@ -63,6 +63,7 @@ SlaveOfCommandHandlerTest.class, KeeperCommandHandlerTest.class, InfoHandlerTest.class, + ConfigHandlerTest.class, ApplierCommandHandlerTest.class, DefaultKeeperStatsTest.class, @@ -83,6 +84,8 @@ DiskHealthCheckerTest.class, + RordbReplicationSupportTest.class, + AllApplierTests.class, }) public class AllTests { diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/handler/keeper/ConfigHandlerTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/handler/keeper/ConfigHandlerTest.java new file mode 100644 index 000000000..e8ed54c36 --- /dev/null +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/handler/keeper/ConfigHandlerTest.java @@ -0,0 +1,67 @@ +package com.ctrip.xpipe.redis.keeper.handler.keeper; + +import com.ctrip.xpipe.api.pool.SimpleObjectPool; +import com.ctrip.xpipe.endpoint.DefaultEndPoint; +import com.ctrip.xpipe.netty.commands.NettyClient; +import com.ctrip.xpipe.redis.core.protocal.cmd.ConfigGetCommand; +import com.ctrip.xpipe.redis.keeper.AbstractFakeRedisTest; +import com.ctrip.xpipe.redis.keeper.RedisKeeperServer; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.TimeUnit; + +/** + * @author lishanglin + * date 2024/3/5 + */ +public class ConfigHandlerTest extends AbstractFakeRedisTest { + + private RedisKeeperServer keeperServer; + + @Before + public void beforeConfigHandlerTest() throws Exception { + keeperServer = startRedisKeeperServerAndConnectToFakeRedis(); + } + + @Test + public void testConfigGetRordbSyncMasterSupport() throws Exception { + SimpleObjectPool clientPool = getXpipeNettyClientKeyedObjectPool() + .getKeyPool(new DefaultEndPoint("127.0.0.1", keeperServer.getListeningPort())); + ConfigGetCommand cfgGet = new ConfigGetCommand.ConfigGetRordbSync(clientPool, scheduled); + fakeRedisServer.setSupportRordb(true); + + Assert.assertTrue(cfgGet.execute().get(1, TimeUnit.SECONDS)); + } + + @Test + public void testConfigGetRordbSyncMasterNotSupport() throws Exception { + SimpleObjectPool clientPool = getXpipeNettyClientKeyedObjectPool() + .getKeyPool(new DefaultEndPoint("127.0.0.1", keeperServer.getListeningPort())); + ConfigGetCommand cfgGet = new ConfigGetCommand.ConfigGetRordbSync(clientPool, scheduled); + fakeRedisServer.setSupportRordb(false); + + Assert.assertFalse(cfgGet.execute().get(1, TimeUnit.SECONDS)); + } + + @Test + public void testConfigGetUnknown() throws Exception { + SimpleObjectPool clientPool = getXpipeNettyClientKeyedObjectPool() + .getKeyPool(new DefaultEndPoint("127.0.0.1", keeperServer.getListeningPort())); + ConfigGetCommand cfgGet = new ConfigGetCommand.ConfigGetBool(clientPool, scheduled) { + @Override + protected String getConfigName() { + return "mockconfig"; + } + + @Override + protected Boolean defaultValue() { + return false; + } + }; + + Assert.assertFalse(cfgGet.execute().get(1, TimeUnit.SECONDS)); + } + +} diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/AbstractRdbDumperTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/AbstractRdbDumperTest.java index c9ce9bbaa..c40679c3e 100644 --- a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/AbstractRdbDumperTest.java +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/AbstractRdbDumperTest.java @@ -2,6 +2,7 @@ import com.ctrip.xpipe.redis.core.store.DumpedRdbStore; import com.ctrip.xpipe.redis.core.store.RdbDumpState; +import com.ctrip.xpipe.redis.core.store.RdbStore; import com.ctrip.xpipe.redis.keeper.AbstractFakeRedisTest; import com.ctrip.xpipe.redis.keeper.RedisKeeperServer; import com.ctrip.xpipe.redis.keeper.RedisSlave; @@ -50,7 +51,7 @@ public void fixWaitDumpingConcurrencyProblem() throws Exception { CountDownLatch latch = new CountDownLatch(2); runTogether(() -> { redisSlave1.waitForRdbDumping(); - dumper.setRdbDumpState(RdbDumpState.DUMPING); + dumper.auxParseFinished(RdbStore.Type.NORMAL); }, latch); runTogether(() -> { try { @@ -81,7 +82,7 @@ void doFullSyncOrGiveUp(RedisSlave redisSlave) throws IOException { sleep(1000); } }); - dumper.setRdbDumpState(RdbDumpState.DUMPING); + dumper.auxParseFinished(RdbStore.Type.NORMAL); executor.execute(()->{ try { @@ -116,6 +117,11 @@ public TestDumper(RedisKeeperServer redisKeeperServer) { super(redisKeeperServer); } + @Override + public boolean tryRordb() { + return false; + } + @Override protected void doExecute() throws Throwable { diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/RdbonlyRedisMasterReplicationTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/RdbonlyRedisMasterReplicationTest.java index fedb93ceb..e8c68d84c 100644 --- a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/RdbonlyRedisMasterReplicationTest.java +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/RdbonlyRedisMasterReplicationTest.java @@ -36,6 +36,8 @@ public class RdbonlyRedisMasterReplicationTest extends AbstractRedisKeeperTest { private NioEventLoopGroup rdbEventLoopGroup = new NioEventLoopGroup(1); + private NioEventLoopGroup masterConfigEventLoopGroup = new NioEventLoopGroup(1); + private ReplicationStoreManager replicationStoreManager = createReplicationStoreManager(); private DefaultEndPoint target; @@ -52,11 +54,12 @@ public void beforeRdbonlyRedisMasterReplicationTest() throws IOException { @Test public void testTimeoutMilli() throws CreateRdbDumperException { target = new DefaultEndPoint("localhost", randomPort()); - this.keeperRedisMaster = new DefaultRedisMaster(keeperServer, target, masterEventLoopGroup, rdbEventLoopGroup, replicationStoreManager, scheduled, getRegistry().getComponent(KeeperResourceManager.class)); + this.keeperRedisMaster = new DefaultRedisMaster(keeperServer, target, masterEventLoopGroup, rdbEventLoopGroup, masterConfigEventLoopGroup, + replicationStoreManager, scheduled, getRegistry().getComponent(KeeperResourceManager.class)); keeperRedisMaster.setMasterState(MASTER_STATE.REDIS_REPL_CONNECTED); - RedisMasterNewRdbDumper dumper = (RedisMasterNewRdbDumper)keeperRedisMaster.createRdbDumper(); + RedisMasterNewRdbDumper dumper = (RedisMasterNewRdbDumper)keeperRedisMaster.createRdbDumper(false); RdbonlyRedisMasterReplication rdbonlyRedisMasterReplication = new RdbonlyRedisMasterReplication(keeperServer, - keeperRedisMaster, masterEventLoopGroup, scheduled, dumper, getRegistry().getComponent(KeeperResourceManager.class)); + keeperRedisMaster, false, masterEventLoopGroup, scheduled, dumper, getRegistry().getComponent(KeeperResourceManager.class)); int time = rdbonlyRedisMasterReplication.commandTimeoutMilli(); Assert.assertEquals(AbstractRedisCommand.DEFAULT_REDIS_COMMAND_TIME_OUT_MILLI, time); @@ -69,6 +72,7 @@ public void releaseRdbFileWhenCannotPsync() throws Exception { RdbonlyRedisMasterReplication replication = spy(new RdbonlyRedisMasterReplication( mock(DefaultRedisKeeperServer.class), mock(RedisMaster.class), + false, mock(NioEventLoopGroup.class), mock(ScheduledExecutorService.class), mock(RedisMasterNewRdbDumper.class), diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/RedisMasterNewRdbDumperTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/RedisMasterNewRdbDumperTest.java index 4a1c93d9d..5849af815 100644 --- a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/RedisMasterNewRdbDumperTest.java +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/RedisMasterNewRdbDumperTest.java @@ -1,7 +1,5 @@ package com.ctrip.xpipe.redis.keeper.impl; -import com.ctrip.xpipe.redis.core.store.ReplicationStore; -import com.ctrip.xpipe.redis.core.store.ReplicationStoreManager; import com.ctrip.xpipe.redis.keeper.RedisKeeperServer; import com.ctrip.xpipe.redis.keeper.RedisMaster; import com.ctrip.xpipe.redis.keeper.config.KeeperResourceManager; @@ -27,7 +25,7 @@ public void whenRdbOffsetNotContinuous() throws Exception { RedisKeeperServer redisKeeperServer = mock(RedisKeeperServer.class); doNothing().when(redisKeeperServer).resetDefaultReplication(); - RedisMasterNewRdbDumper dumper = spy(new RedisMasterNewRdbDumper(redisMaster, redisKeeperServer, mock(NioEventLoopGroup.class), + RedisMasterNewRdbDumper dumper = spy(new RedisMasterNewRdbDumper(redisMaster, redisKeeperServer, false, mock(NioEventLoopGroup.class), mock(ScheduledExecutorService.class), mock(KeeperResourceManager.class))); doNothing().when(dumper).startRdbOnlyReplication(); @@ -39,7 +37,7 @@ public void whenRdbOffsetNotContinuous() throws Exception { @Test public void cancel() throws Exception { - RedisMasterNewRdbDumper dumper = spy(new RedisMasterNewRdbDumper(mock(RedisMaster.class), mock(RedisKeeperServer.class), mock(NioEventLoopGroup.class), + RedisMasterNewRdbDumper dumper = spy(new RedisMasterNewRdbDumper(mock(RedisMaster.class), mock(RedisKeeperServer.class), false, mock(NioEventLoopGroup.class), mock(ScheduledExecutorService.class), mock(KeeperResourceManager.class))); doNothing().when(dumper).doExecute(); diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/RordbReplicationSupportTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/RordbReplicationSupportTest.java new file mode 100644 index 000000000..6d72e3ac3 --- /dev/null +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/RordbReplicationSupportTest.java @@ -0,0 +1,274 @@ +package com.ctrip.xpipe.redis.keeper.impl; + +import com.ctrip.xpipe.api.command.CommandFuture; +import com.ctrip.xpipe.command.DefaultCommandFuture; +import com.ctrip.xpipe.endpoint.DefaultEndPoint; +import com.ctrip.xpipe.pool.XpipeNettyClientPool; +import com.ctrip.xpipe.redis.core.protocal.CAPA; +import com.ctrip.xpipe.redis.core.protocal.MASTER_STATE; +import com.ctrip.xpipe.redis.core.protocal.PsyncObserver; +import com.ctrip.xpipe.redis.core.protocal.cmd.ConfigGetCommand; +import com.ctrip.xpipe.redis.core.protocal.cmd.InMemoryPsync; +import com.ctrip.xpipe.redis.core.protocal.cmd.Replconf; +import com.ctrip.xpipe.redis.core.protocal.protocal.EofType; +import com.ctrip.xpipe.redis.core.redis.rdb.RdbConstant; +import com.ctrip.xpipe.redis.core.server.FakeRedisServer; +import com.ctrip.xpipe.redis.core.store.RdbStore; +import com.ctrip.xpipe.redis.keeper.AbstractRedisKeeperContextTest; +import com.ctrip.xpipe.redis.keeper.RedisKeeperServer; +import com.ctrip.xpipe.redis.keeper.config.KeeperConfig; +import com.ctrip.xpipe.redis.keeper.config.TestKeeperConfig; +import com.ctrip.xpipe.tuple.Pair; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * @author lishanglin + * date 2024/3/4 + */ +public class RordbReplicationSupportTest extends AbstractRedisKeeperContextTest { + + private FakeRedisServer redisServer; + + @Before + public void setupRordbReplicationSupportTest() throws Exception{ + this.redisServer = startFakeRedisServer(); + } + + @Test + @Ignore + public void testFakeRedisServerSupport() throws Exception { + ConfigGetCommand cmd = new ConfigGetCommand.ConfigGetRordbSync( + getXpipeNettyClientKeyedObjectPool().getKeyPool(new DefaultEndPoint("127.0.0.1", redisServer.getPort())), + scheduled); + Assert.assertFalse(cmd.execute().get()); + redisServer.setSupportRordb(true); + cmd.reset(); + Assert.assertTrue(cmd.execute().get()); + } + + @Test + @Ignore + public void testPsyncRordbFromMaster() throws Exception { + redisServer.setSupportRordb(true); + InMemoryPsync psync = sendPsyncAndWaitRdbDone("127.0.0.1", redisServer.getPort(), true); + Assert.assertArrayEquals(redisServer.getRdbContent(), psync.getRdb()); + Assert.assertEquals(RdbStore.Type.RORDB, checkRdbType(psync.getRdb())); + } + + @Test + public void testSlaveCapaRordbMasterSupport() throws Exception { + redisServer.setSupportRordb(true); + RedisKeeperServer redisKeeperServer = initKeeperAndConnectToMaster(); + InMemoryPsync psync = sendPsyncAndWaitRdbDone("127.0.0.1", redisKeeperServer.getListeningPort(), true); + Assert.assertArrayEquals(redisServer.getRdbContent(), psync.getRdb()); + Assert.assertEquals(RdbStore.Type.RORDB, checkRdbType(psync.getRdb())); + } + + @Test + public void testSlaveCapaRordbMasterNotSupport() throws Exception { + redisServer.setSupportRordb(false); + RedisKeeperServer redisKeeperServer = initKeeperAndConnectToMaster(); + InMemoryPsync psync = sendPsyncAndWaitRdbDone("127.0.0.1", redisKeeperServer.getListeningPort(), true); + Assert.assertArrayEquals(redisServer.getRdbContent(), psync.getRdb()); + Assert.assertEquals(RdbStore.Type.NORMAL, checkRdbType(psync.getRdb())); + } + + @Test + public void testSlaveRordbThenRdb() throws Exception { + redisServer.setSupportRordb(true); + RedisKeeperServer redisKeeperServer = initKeeperAndConnectToMaster(); + InMemoryPsync psync = sendPsyncAndWaitRdbDone("127.0.0.1", redisKeeperServer.getListeningPort(), true); + Assert.assertArrayEquals(redisServer.getRdbContent(), psync.getRdb()); + Assert.assertEquals(RdbStore.Type.RORDB, checkRdbType(psync.getRdb())); + psync = sendPsyncAndWaitRdbDone("127.0.0.1", redisKeeperServer.getListeningPort(), false); + Assert.assertArrayEquals(redisServer.getRdbContent(), psync.getRdb()); + Assert.assertEquals(RdbStore.Type.NORMAL, checkRdbType(psync.getRdb())); + } + + @Test + public void testSlaveRdbThenRordb() throws Exception { + redisServer.setSupportRordb(true); + RedisKeeperServer redisKeeperServer = initKeeperAndConnectToMaster(); + InMemoryPsync psync = sendPsyncAndWaitRdbDone("127.0.0.1", redisKeeperServer.getListeningPort(), false); + Assert.assertArrayEquals(redisServer.getRdbContent(), psync.getRdb()); + Assert.assertEquals(RdbStore.Type.NORMAL, checkRdbType(psync.getRdb())); + psync = sendPsyncAndWaitRdbDone("127.0.0.1", redisKeeperServer.getListeningPort(), true); + Assert.assertArrayEquals(redisServer.getRdbContent(), psync.getRdb()); + Assert.assertEquals(RdbStore.Type.RORDB, checkRdbType(psync.getRdb())); + } + + @Test + public void testSlaveRordbOnRdbDumping() throws Exception { + redisServer.setSupportRordb(true); + RedisKeeperServer redisKeeperServer = initKeeperAndConnectToMaster(); + + redisServer.setSleepBeforeSendRdb(3000); + Pair psyncs = sendPsyncOnDumpingAndWaitRdbDone("127.0.0.1", + redisKeeperServer.getListeningPort(), false, true); + Assert.assertEquals(RdbStore.Type.NORMAL, checkRdbType(psyncs.getKey().getRdb())); + Assert.assertEquals(RdbStore.Type.NORMAL, checkRdbType(psyncs.getValue().getRdb())); + } + + @Test + public void testSlaveRdbOnRordbDumping() throws Exception { + redisServer.setSupportRordb(true); + RedisKeeperServer redisKeeperServer = initKeeperAndConnectToMaster(); + + redisServer.setSleepBeforeSendRdb(3000); + Pair psyncs = sendPsyncOnDumpingAndWaitRdbDone("127.0.0.1", + redisKeeperServer.getListeningPort(), true, false); + Assert.assertEquals(RdbStore.Type.RORDB, checkRdbType(psyncs.getKey().getRdb())); + Assert.assertEquals(RdbStore.Type.NORMAL, checkRdbType(psyncs.getValue().getRdb())); + } + + private RdbStore.Type checkRdbType(byte[] rdb) { + Map auxMap = parseRdbAux(rdb); + if (auxMap.containsKey(RdbConstant.REDIS_RDB_AUX_KEY_RORDB)) { + return RdbStore.Type.RORDB; + } else { + return RdbStore.Type.NORMAL; + } + } + + private RedisKeeperServer initKeeperAndConnectToMaster() throws Exception { + RedisKeeperServer redisKeeperServer = createRedisKeeperServer(); + redisKeeperServer.initialize(); + redisKeeperServer.start(); + + redisKeeperServer.setRedisKeeperServerState( + new RedisKeeperServerStateActive(redisKeeperServer, new DefaultEndPoint("127.0.0.1", redisServer.getPort()))); + redisKeeperServer.reconnectMaster(); + + waitConditionUntilTimeOut(() -> redisKeeperServer.getRedisMaster().getMasterState() == MASTER_STATE.REDIS_REPL_CONNECTED); + + return redisKeeperServer; + } + + private Pair sendPsyncOnDumpingAndWaitRdbDone(String redisIp, int redisPort, boolean tryRordb1, boolean tryRordb2) throws Exception { + XpipeNettyClientPool masterPool1 = singleConnectPool(redisIp, redisPort); + XpipeNettyClientPool masterPool2 = singleConnectPool(redisIp, redisPort); + replConfCapa(masterPool1, tryRordb1); + replConfCapa(masterPool2, tryRordb2); + + InMemoryPsync psync1 = new InMemoryPsync(masterPool1, "?", -1, scheduled); + InMemoryPsync psync2 = new InMemoryPsync(masterPool2, "?", -1, scheduled); + + CountDownLatch latch = new CountDownLatch(2); + psync1.addPsyncObserver(new TestPsyncObserver() { + @Override + public void endWriteRdb() { + latch.countDown(); + } + }); + psync2.addPsyncObserver(new TestPsyncObserver() { + @Override + public void endWriteRdb() { + latch.countDown(); + } + }); + + psync1.execute(); + sleep(1000); + psync2.execute(); + latch.await(); + + return Pair.from(psync1, psync2); + } + + private InMemoryPsync sendPsyncAndWaitRdbDone(String redisIp, int redisPort, boolean tryRordb) throws Exception { + XpipeNettyClientPool masterPool = singleConnectPool(redisIp, redisPort); + replConfCapa(masterPool, tryRordb); + + InMemoryPsync psync = new InMemoryPsync(masterPool, "?", -1, scheduled); + CommandFuture future = new DefaultCommandFuture(); + psync.addPsyncObserver(new TestPsyncObserver() { + @Override + public void endWriteRdb() { + future.setSuccess(); + } + }); + psync.execute(); + future.get(5, TimeUnit.SECONDS); + + return psync; + } + + private XpipeNettyClientPool singleConnectPool(String redisIp, int redisPort) throws Exception { + GenericObjectPoolConfig config = new GenericObjectPoolConfig(); + config.setMaxTotal(1); + config.setJmxEnabled(false); + XpipeNettyClientPool pool = new XpipeNettyClientPool(new DefaultEndPoint(redisIp, redisPort), config); + pool.initialize(); + return pool; + } + + private void replConfCapa(XpipeNettyClientPool pool, boolean tryRordb) throws Exception { + Replconf repl; + if (tryRordb) { + repl = new Replconf(pool, Replconf.ReplConfType.CAPA, scheduled, + CAPA.EOF.toString(), CAPA.PSYNC2.toString(), CAPA.RORDB.toString()); + } else { + repl = new Replconf(pool, Replconf.ReplConfType.CAPA, scheduled, + CAPA.EOF.toString(), CAPA.PSYNC2.toString()); + } + repl.execute().get(); + } + + protected KeeperConfig getKeeperConfig() { + TestKeeperConfig config = new TestKeeperConfig(); + config.rdbDumpMinIntervalMilli = 0; + return config; + } + + @Override + protected String getXpipeMetaConfigFile() { + return "keeper-test.xml"; + } + + class TestPsyncObserver implements PsyncObserver { + @Override + public void onFullSync(long masterRdbOffset) { + + } + + @Override + public void reFullSync() { + + } + + @Override + public void beginWriteRdb(EofType eofType, String replId, long masterRdbOffset) throws IOException { + + } + + @Override + public void readAuxEnd(RdbStore rdbStore, Map auxMap) { + + } + + @Override + public void endWriteRdb() { + + } + + @Override + public void onContinue(String requestReplId, String responseReplId) { + + } + + @Override + public void onKeeperContinue(String replId, long beginOffset) { + + } + } + +} diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/fakeredis/DefaultRedisKeeperServerConnectToFakeRedisTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/fakeredis/DefaultRedisKeeperServerConnectToFakeRedisTest.java index 5dbd45c0d..13cd69984 100644 --- a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/fakeredis/DefaultRedisKeeperServerConnectToFakeRedisTest.java +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/fakeredis/DefaultRedisKeeperServerConnectToFakeRedisTest.java @@ -25,8 +25,8 @@ public void testReplicationData() throws Exception{ logger.info(remarkableMessage("[testReplicationData][read replication store]")); ReplicationStore replicationStore = redisKeeperServer.getReplicationStore(); - String rdbContent = readRdbFileTilEnd(replicationStore); - Assert.assertEquals(fakeRedisServer.getRdbContent(), rdbContent); + byte[] rdbContent = readRdbFileTilEnd(replicationStore); + Assert.assertArrayEquals(fakeRedisServer.getRdbContent(), rdbContent); String commands = readCommandFileTilEnd(replicationStore, fakeRedisServer.currentCommands().length()); Assert.assertEquals(fakeRedisServer.currentCommands(), commands); @@ -48,7 +48,7 @@ private void startKeeperServerAndTestReFullSync(int fileToKeep, int maxTransferC RedisKeeperServer redisKeeperServer = startRedisKeeperServerAndConnectToFakeRedis(fileToKeep, maxTransferCommnadsSize, 1000); int keeperPort = redisKeeperServer.getListeningPort(); - sleep(2000); + sleep(3000); logger.info(remarkableMessage("send psync to redump rdb")); int rdbDumpCount1 = ((DefaultReplicationStore)redisKeeperServer.getReplicationStore()).getRdbUpdateCount(); diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/fakeredis/FakeRedisExceptionTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/fakeredis/FakeRedisExceptionTest.java index f1c8fda1a..eb3215a64 100644 --- a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/fakeredis/FakeRedisExceptionTest.java +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/impl/fakeredis/FakeRedisExceptionTest.java @@ -2,7 +2,6 @@ import com.ctrip.xpipe.api.cluster.LeaderElectorManager; import com.ctrip.xpipe.redis.core.entity.KeeperMeta; -import com.ctrip.xpipe.redis.core.protocal.protocal.EofType; import com.ctrip.xpipe.redis.core.store.RdbStore; import com.ctrip.xpipe.redis.core.store.ReplicationStore; import com.ctrip.xpipe.redis.keeper.AbstractFakeRedisTest; @@ -19,10 +18,10 @@ import java.io.File; import java.io.IOException; +import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import static org.mockito.Mockito.mock; /** * @author wenchao.meng @@ -58,9 +57,8 @@ protected RedisKeeperServer createRedisKeeperServer(Long replId, KeeperMeta kee createkeepersMonitorManager(), getRegistry().getComponent(KeeperResourceManager.class)){ @Override - public void beginWriteRdb(EofType eofType, String replId, long offset) { - - super.beginWriteRdb(eofType, replId, offset); + public void readAuxEnd(RdbStore rdbStore, Map auxMap) { + super.readAuxEnd(rdbStore, auxMap); try { writeToRdb(getCurrentReplicationStore()); } catch (IOException e) { diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/protocal/cmd/PsyncTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/protocal/cmd/PsyncTest.java index 3a3f46244..2be136dd2 100644 --- a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/protocal/cmd/PsyncTest.java +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/protocal/cmd/PsyncTest.java @@ -5,12 +5,16 @@ import com.ctrip.xpipe.api.pool.SimpleObjectPool; import com.ctrip.xpipe.endpoint.DefaultEndPoint; import com.ctrip.xpipe.exception.XpipeException; +import com.ctrip.xpipe.gtid.GtidSet; import com.ctrip.xpipe.lifecycle.LifecycleHelper; import com.ctrip.xpipe.netty.NettyPoolUtil; import com.ctrip.xpipe.netty.commands.NettyClient; +import com.ctrip.xpipe.redis.core.protocal.PsyncObserver; import com.ctrip.xpipe.redis.core.protocal.cmd.DefaultPsync; +import com.ctrip.xpipe.redis.core.protocal.protocal.EofType; import com.ctrip.xpipe.redis.core.protocal.protocal.LenEofType; import com.ctrip.xpipe.redis.core.redis.RunidGenerator; +import com.ctrip.xpipe.redis.core.store.RdbStore; import com.ctrip.xpipe.redis.core.store.ReplicationStoreManager; import com.ctrip.xpipe.redis.keeper.AbstractRedisKeeperTest; import com.ctrip.xpipe.redis.keeper.store.DefaultReplicationStore; @@ -19,7 +23,9 @@ import org.junit.Before; import org.junit.Test; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.Map; /** * @author wenchao.meng @@ -35,7 +41,10 @@ public class PsyncTest extends AbstractRedisKeeperTest{ private String masterId = randomString(40); private Long masterOffset; - private String rdbContent = "REDIS0009" + '\0' + randomString(); + // MAGIC + AUX + SELECT DB + private byte[] rdbHeader = new byte[] {0x52, 0x45, 0x44, 0x49, 0x53, 0x30, 0x30, 0x30, 0x39, (byte) 0xfa, 0x09, 0x72, + 0x65, 0x64, 0x69, 0x73, 0x2d, 0x76, 0x65, 0x72, 0x05, 0x36, 0x2e, 0x32, 0x2e, 0x36, (byte) 0xfe, 0x00}; + private String rdbContent = randomString(); private String commandContent = randomString(); private boolean isPartial = false; @@ -59,19 +68,61 @@ public void operationComplete(CommandFuture commandFuture) throws Except } } }); + psync.addPsyncObserver(new PsyncObserver() { + @Override + public void onFullSync(long masterRdbOffset) { + } + + @Override + public void reFullSync() { + } + + @Override + public void beginWriteRdb(EofType eofType, String replId, long masterRdbOffset) throws IOException { + } + + @Override + public void readAuxEnd(RdbStore rdbStore, Map auxMap) { + try { + rdbStore.updateRdbGtidSet(GtidSet.EMPTY_GTIDSET); + rdbStore.updateRdbType(RdbStore.Type.NORMAL); + replicationStore.confirmRdb(rdbStore); + } catch (Throwable th) { + logger.info("[readAuxEnd][confirmRdb] fail", th); + } + } + + @Override + public void endWriteRdb() { + } + + @Override + public void onContinue(String requestReplId, String responseReplId) { + } + + @Override + public void onKeeperContinue(String replId, long beginOffset) { + } + }); + } + + private void initRdbStore() throws IOException { + RdbStore rdbStore = replicationStore.prepareRdb(masterId, masterOffset, new LenEofType(0)); + rdbStore.updateRdbGtidSet(GtidSet.EMPTY_GTIDSET); + rdbStore.updateRdbType(RdbStore.Type.NORMAL); + replicationStore.confirmRdb(rdbStore); + replicationStore.getRdbStore().endRdb(); } @Test public void testPsyncPartialeRight() throws XpipeException, IOException, InterruptedException{ isPartial = true; - String []data = new String[]{ - "+" + DefaultPsync.PARTIAL_SYNC + "\r\n", - commandContent + byte [][]data = new byte[][]{ + ("+" + DefaultPsync.PARTIAL_SYNC + "\r\n").getBytes(), + commandContent.getBytes() }; - //create store - replicationStore.beginRdb(masterId, masterOffset, new LenEofType(0)); - replicationStore.getRdbStore().endRdb(); + initRdbStore(); runData(data); } @@ -82,13 +133,11 @@ public void testPsync2() throws XpipeException, IOException, InterruptedExceptio isPartial = true; String newReplId = RunidGenerator.DEFAULT.generateRunid(); - String []data = new String[]{ - "+" + DefaultPsync.PARTIAL_SYNC + " " + newReplId + "\r\n", - commandContent + byte [][]data = new byte[][]{ + ("+" + DefaultPsync.PARTIAL_SYNC + " " + newReplId + "\r\n").getBytes(), + commandContent.getBytes() }; - //create store - replicationStore.beginRdb(masterId, masterOffset, new LenEofType(0)); - replicationStore.getRdbStore().endRdb(); + initRdbStore(); Long secondReplIdOffset = replicationStore.getEndOffset() + 1; @@ -105,13 +154,11 @@ public void testPsync2Spaces() throws XpipeException, IOException, InterruptedEx isPartial = true; String newReplId = RunidGenerator.DEFAULT.generateRunid(); - String []data = new String[]{ - "+" + DefaultPsync.PARTIAL_SYNC + " " + newReplId + " \r\n", - commandContent + byte [][]data = new byte[][]{ + ("+" + DefaultPsync.PARTIAL_SYNC + " " + newReplId + " \r\n").getBytes(), + commandContent.getBytes() }; - //create store - replicationStore.beginRdb(masterId, masterOffset, new LenEofType(0)); - replicationStore.getRdbStore().endRdb(); + initRdbStore(); Long secondReplIdOffset = replicationStore.getEndOffset() + 1; @@ -128,14 +175,12 @@ public void testPsync2SplitTcp() throws XpipeException, IOException, Interrupted isPartial = true; String newReplId = RunidGenerator.DEFAULT.generateRunid(); - String []data = new String[]{ - "+" + DefaultPsync.PARTIAL_SYNC , - " " + newReplId + " \r\n", - commandContent + byte [][]data = new byte[][]{ + ("+" + DefaultPsync.PARTIAL_SYNC).getBytes(), + (" " + newReplId + " \r\n").getBytes(), + commandContent.getBytes() }; - //create store - replicationStore.beginRdb(masterId, masterOffset, new LenEofType(0)); - replicationStore.getRdbStore().endRdb(); + initRdbStore(); Long secondReplIdOffset = replicationStore.getEndOffset() + 1; @@ -151,12 +196,13 @@ public void testPsync2SplitTcp() throws XpipeException, IOException, Interrupted public void testPsyncEofMark() throws XpipeException, IOException, InterruptedException{ String eof = RunidGenerator.DEFAULT.generateRunid(); - String []data = new String[]{ - "+" + DefaultPsync.FULL_SYNC + " " + masterId + " " + masterOffset + "\r\n", - "$EOF:" + eof + "\r\n", - rdbContent, - eof, - commandContent + byte [][]data = new byte[][]{ + ("+" + DefaultPsync.FULL_SYNC + " " + masterId + " " + masterOffset + "\r\n").getBytes(), + ("$EOF:" + eof + "\r\n").getBytes(), + rdbHeader, + rdbContent.getBytes(), + eof.getBytes(), + commandContent.getBytes() }; runData(data); @@ -165,12 +211,14 @@ public void testPsyncEofMark() throws XpipeException, IOException, InterruptedEx @Test public void testPsyncFullRight() throws XpipeException, IOException, InterruptedException{ - - String []data = new String[]{ - "+" + DefaultPsync.FULL_SYNC + " " + masterId + " " + masterOffset + "\r\n", - "$" + rdbContent.length() + "\r\n", - rdbContent, - commandContent + + int rdbLen = rdbContent.length() + rdbHeader.length; + byte [][]data = new byte[][]{ + ("+" + DefaultPsync.FULL_SYNC + " " + masterId + " " + masterOffset + "\r\n").getBytes(), + ("$" + rdbLen + "\r\n").getBytes(), + rdbHeader, + rdbContent.getBytes(), + commandContent.getBytes() }; runData(data); @@ -178,12 +226,14 @@ public void testPsyncFullRight() throws XpipeException, IOException, Interrupted @Test public void testPsyncFullWithRdbCrlf() throws XpipeException, IOException, InterruptedException{ - - String []data = new String[]{ - "+" + DefaultPsync.FULL_SYNC + " " + masterId + " " + masterOffset + "\r\n", - "$" + rdbContent.length() + "\r\n", - rdbContent + "\r\n", - commandContent + + int rdbLen = rdbContent.length() + rdbHeader.length; + byte [][]data = new byte[][]{ + ("+" + DefaultPsync.FULL_SYNC + " " + masterId + " " + masterOffset + "\r\n").getBytes(), + ("$" + rdbLen + "\r\n").getBytes(), + rdbHeader, + (rdbContent + "\r\n").getBytes(), + commandContent.getBytes() }; runData(data); @@ -191,29 +241,33 @@ public void testPsyncFullWithRdbCrlf() throws XpipeException, IOException, Inter @Test public void testPsyncFullWithSplit() throws XpipeException, IOException, InterruptedException{ - - String []data = new String[]{ - "+" + DefaultPsync.FULL_SYNC + " " + masterId + " " + masterOffset + "\r\n", - "$" + rdbContent.length() , - "\r\n", - rdbContent.substring(0, rdbContent.length()/2), - rdbContent.substring(rdbContent.length()/2) + "\r\n", - commandContent.substring(0, rdbContent.length()/2), - commandContent.substring(rdbContent.length()/2) + + int rdbLen = rdbContent.length() + rdbHeader.length; + byte [][]data = new byte[][]{ + ("+" + DefaultPsync.FULL_SYNC + " " + masterId + " " + masterOffset + "\r\n").getBytes(), + ("$" + rdbLen).getBytes() , + "\r\n".getBytes(), + rdbHeader, + rdbContent.substring(0, rdbContent.length()/2).getBytes(), + (rdbContent.substring(rdbContent.length()/2) + "\r\n").getBytes(), + commandContent.substring(0, rdbContent.length()/2).getBytes(), + commandContent.substring(rdbContent.length()/2).getBytes() }; runData(data); } @Test - public void testPsyncFailHalfRdb() throws XpipeException, IOException, InterruptedException{ + public void testPsyncFailHalfRdb() throws Exception{ psync.addFutureListener(); - + + int rdbLen = rdbContent.length() + rdbHeader.length; int midIndex = rdbContent.length()/2; - String []data = new String[]{ - "+" + DefaultPsync.FULL_SYNC + " " + masterId + " " + masterOffset + "\r\n", - "$" + rdbContent.length() + "\r\n", - rdbContent.substring(0, midIndex) + "\r\n", + byte [][]data = new byte[][]{ + ("+" + DefaultPsync.FULL_SYNC + " " + masterId + " " + masterOffset + "\r\n").getBytes(), + ("$" + rdbLen + "\r\n").getBytes(), + rdbHeader, + (rdbContent.substring(0, midIndex) + "\r\n").getBytes(), }; runData(data, false); @@ -222,17 +276,17 @@ public void testPsyncFailHalfRdb() throws XpipeException, IOException, Interrupt Assert.assertFalse(replicationStore.getRdbStore().checkOk()); } - private void runData(String []data) throws XpipeException, IOException, InterruptedException { + private void runData(byte [][]data) throws XpipeException, IOException, InterruptedException { runData(data, true); } - private void runData(String []data, boolean assertResult) throws XpipeException, IOException, InterruptedException { + private void runData(byte [][]data, boolean assertResult) throws XpipeException, IOException, InterruptedException { ByteBuf []byteBufs = new ByteBuf[data.length]; for(int i=0;i redisKeeperServer1.getKeeperRepl().getEndOffset() == redisKeeperServer2.getKeeperRepl().getEndOffset()); logger.info(remarkableMessage("stop keeper2 {}"), redisKeeperServer2.getListeningPort()); redisKeeperServer2.stop(); sleep((int) (redisKeeperServer1.getKeeperConfig().getReplDownSafeIntervalMilli() * 3 / 2)); diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultRdbStoreEofMarkTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultRdbStoreEofMarkTest.java index 15862799d..095b290da 100644 --- a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultRdbStoreEofMarkTest.java +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultRdbStoreEofMarkTest.java @@ -28,7 +28,7 @@ public class DefaultRdbStoreEofMarkTest extends AbstractRedisKeeperTest { public void beforeDefaultRdbStoreEofMarkTest() throws IOException{ rdbFile = new File(String.format("%s/%s.rdb", getTestFileDir(), getTestName())); - rdbStore = new DefaultRdbStore(rdbFile, 0, new EofMarkType(eofMark)); + rdbStore = new DefaultRdbStore(rdbFile, "replid", 0, new EofMarkType(eofMark)); } @@ -50,7 +50,7 @@ protected void doRun() throws Exception { } }); - String rdbFileData = readRdbFileTilEnd(rdbStore); + String rdbFileData = new String(readRdbFileTilEnd(rdbStore)); Assert.assertEquals(data, rdbFileData); } diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultRdbStoreTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultRdbStoreTest.java index 25729ec31..cf1d211b9 100644 --- a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultRdbStoreTest.java +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultRdbStoreTest.java @@ -37,7 +37,7 @@ public void beforeDefaultRdbStoreTest() throws IOException{ String fileName = String.format("%s/%s.rdb", getTestFileDir(), getTestName()); rdbFile = new File(fileName); - rdbStore = new DefaultRdbStore(rdbFile, 1L, new LenEofType(rdbFileSize)); + rdbStore = new DefaultRdbStore(rdbFile, "replId",1L, new LenEofType(rdbFileSize)); } @Test diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultReplicationStoreManagerTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultReplicationStoreManagerTest.java index 2e3213ebc..f902484fc 100644 --- a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultReplicationStoreManagerTest.java +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultReplicationStoreManagerTest.java @@ -1,6 +1,7 @@ package com.ctrip.xpipe.redis.keeper.store; import com.ctrip.xpipe.endpoint.DefaultEndPoint; +import com.ctrip.xpipe.gtid.GtidSet; import com.ctrip.xpipe.lifecycle.LifecycleHelper; import com.ctrip.xpipe.redis.core.protocal.protocal.LenEofType; import com.ctrip.xpipe.redis.core.redis.RunidGenerator; @@ -256,7 +257,10 @@ public void test() throws Exception { MetaStore metaStore = newCurrentStore.getMetaStore(); metaStore.setMasterAddress(new DefaultEndPoint("redis://127.0.0.1:6379")); - newCurrentStore.beginRdb("masterRunid", 0, new LenEofType(100)); + RdbStore rdbStore = newCurrentStore.prepareRdb("masterRunid", 0, new LenEofType(100)); + rdbStore.updateRdbGtidSet(GtidSet.EMPTY_GTIDSET); + rdbStore.updateRdbType(RdbStore.Type.NORMAL); + newCurrentStore.confirmRdb(rdbStore); ByteBuf cmdBuf = Unpooled.buffer(); cmdBuf.writeByte(9); diff --git a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultReplicationStoreTest.java b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultReplicationStoreTest.java index f1555fd76..b506bbdca 100644 --- a/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultReplicationStoreTest.java +++ b/redis/redis-keeper/src/test/java/com/ctrip/xpipe/redis/keeper/store/DefaultReplicationStoreTest.java @@ -1,13 +1,11 @@ package com.ctrip.xpipe.redis.keeper.store; import com.ctrip.xpipe.concurrent.AbstractExceptionLogTask; +import com.ctrip.xpipe.gtid.GtidSet; import com.ctrip.xpipe.netty.filechannel.ReferenceFileRegion; import com.ctrip.xpipe.redis.core.protocal.protocal.EofType; import com.ctrip.xpipe.redis.core.protocal.protocal.LenEofType; -import com.ctrip.xpipe.redis.core.store.CommandFile; -import com.ctrip.xpipe.redis.core.store.FullSyncListener; -import com.ctrip.xpipe.redis.core.store.RdbStore; -import com.ctrip.xpipe.redis.core.store.ReplicationProgress; +import com.ctrip.xpipe.redis.core.store.*; import com.ctrip.xpipe.redis.keeper.AbstractRedisKeeperTest; import com.ctrip.xpipe.redis.keeper.config.DefaultKeeperConfig; import com.ctrip.xpipe.redis.keeper.config.TestKeeperConfig; @@ -39,13 +37,21 @@ public void beforeDefaultReplicationStoreTest() throws IOException{ baseDir = new File(getTestFileDir()); } + private RdbStore beginRdb(ReplicationStore replicationStore, int dataLen) throws IOException { + RdbStore rdbStore = replicationStore.prepareRdb(randomKeeperRunid(), -1, new LenEofType(dataLen)); + rdbStore.updateRdbGtidSet(GtidSet.EMPTY_GTIDSET); + rdbStore.updateRdbType(RdbStore.Type.NORMAL); + replicationStore.confirmRdb(rdbStore); + return rdbStore; + } + @Test public void testInterruptedException() throws IOException { String keeperRunid = randomKeeperRunid(); int dataLen = 100; store = new DefaultReplicationStore(baseDir, new DefaultKeeperConfig(), keeperRunid, createkeeperMonitor()); - RdbStore rdbStore = store.beginRdb(randomKeeperRunid(), -1, new LenEofType(dataLen)); + RdbStore rdbStore = beginRdb(store, dataLen); rdbStore.writeRdb(Unpooled.wrappedBuffer(randomString(dataLen).getBytes())); rdbStore.endRdb(); @@ -69,7 +75,7 @@ public void testReadWhileDestroy() throws Exception{ store.getMetaStore().becomeActive(); int dataLen = 1000; - RdbStore rdbStore = store.beginRdb(randomKeeperRunid(), -1, new LenEofType(dataLen)); + RdbStore rdbStore = beginRdb(store, dataLen); rdbStore.writeRdb(Unpooled.wrappedBuffer(randomString(dataLen).getBytes())); rdbStore.endRdb(); @@ -100,7 +106,12 @@ protected void doRun() throws Exception { try{ store.fullSyncIfPossible(new FullSyncListener() { - + + @Override + public boolean supportRdb(RdbStore.Type rdbType) { + return true; + } + @Override public ChannelFuture onCommand(CommandFile currentFile, long filePosition, Object cmd) { @@ -175,7 +186,7 @@ public void testReadWrite() throws Exception { int cmdCount = 4; int cmdLen = 10; - store.beginRdb("master", -1, new LenEofType(-1)); + beginRdb(store, -1); for (int j = 0; j < cmdCount; j++) { ByteBuf buf = Unpooled.buffer(); @@ -196,7 +207,7 @@ public void testGcNotContinueRdb() throws Exception { store.getMetaStore().becomeActive(); int dataLen = 100; - RdbStore rdbStore = store.beginRdb(randomKeeperRunid(), -1, new LenEofType(dataLen)); + RdbStore rdbStore = beginRdb(store, dataLen); rdbStore.writeRdb(Unpooled.wrappedBuffer(randomString(dataLen).getBytes())); rdbStore.endRdb(); diff --git a/services/ctrip-integration-test/src/test/java/com/ctrip/xpipe/redis/ctrip/integratedtest/console/replication/manual/GtidReplicationManualTest.java b/services/ctrip-integration-test/src/test/java/com/ctrip/xpipe/redis/ctrip/integratedtest/console/replication/manual/GtidReplicationManualTest.java index c64e9af17..6b7ca0cc5 100644 --- a/services/ctrip-integration-test/src/test/java/com/ctrip/xpipe/redis/ctrip/integratedtest/console/replication/manual/GtidReplicationManualTest.java +++ b/services/ctrip-integration-test/src/test/java/com/ctrip/xpipe/redis/ctrip/integratedtest/console/replication/manual/GtidReplicationManualTest.java @@ -28,6 +28,7 @@ import java.util.Collections; import java.util.List; +import java.util.Map; /** * @author lishanglin @@ -142,7 +143,7 @@ public void onFinish(RdbParser parser) { } @Override - public void onAuxFinish() { + public void onAuxFinish(Map auxMap) { logger.info("[onAuxFinish]"); } }