Search in sources :

Example 11 with MasterClient

use of org.neo4j.kernel.ha.com.slave.MasterClient in project neo4j by neo4j.

the class SwitchToSlaveBranchThenCopyTest method newSwitchToSlaveSpy.

@SuppressWarnings("unchecked")
private SwitchToSlaveBranchThenCopy newSwitchToSlaveSpy(PageCache pageCacheMock, StoreCopyClient storeCopyClient) throws IOException {
    ClusterMembers clusterMembers = mock(ClusterMembers.class);
    ClusterMember master = mock(ClusterMember.class);
    when(master.getStoreId()).thenReturn(storeId);
    when(master.getHARole()).thenReturn(HighAvailabilityModeSwitcher.MASTER);
    when(master.hasRole(eq(HighAvailabilityModeSwitcher.MASTER))).thenReturn(true);
    when(master.getInstanceId()).thenReturn(new InstanceId(1));
    when(clusterMembers.getMembers()).thenReturn(singletonList(master));
    Dependencies resolver = new Dependencies();
    resolver.satisfyDependencies(requestContextFactory, clusterMembers, mock(TransactionObligationFulfiller.class), mock(OnlineBackupKernelExtension.class), mock(IndexConfigStore.class), mock(TransactionCommittingResponseUnpacker.class), mock(DataSourceManager.class), mock(StoreLockerLifecycleAdapter.class), mock(FileSystemWatcherService.class));
    NeoStoreDataSource dataSource = mock(NeoStoreDataSource.class);
    when(dataSource.getStoreId()).thenReturn(storeId);
    TransactionStats transactionCounters = mock(TransactionStats.class);
    when(transactionCounters.getNumberOfActiveTransactions()).thenReturn(0L);
    Response<HandshakeResult> response = mock(Response.class);
    when(response.response()).thenReturn(new HandshakeResult(42, 2));
    when(masterClient.handshake(anyLong(), any(StoreId.class))).thenReturn(response);
    when(masterClient.getProtocolVersion()).thenReturn(MasterClient320.PROTOCOL_VERSION);
    TransactionIdStore transactionIdStoreMock = mock(TransactionIdStore.class);
    // note that the checksum (the second member of the array) is the same as the one in the handshake mock above
    when(transactionIdStoreMock.getLastCommittedTransaction()).thenReturn(new TransactionId(42, 42, 42));
    MasterClientResolver masterClientResolver = mock(MasterClientResolver.class);
    when(masterClientResolver.instantiate(anyString(), anyInt(), anyString(), any(Monitors.class), any(StoreId.class), any(LifeSupport.class))).thenReturn(masterClient);
    return spy(new SwitchToSlaveBranchThenCopy(new File(""), NullLogService.getInstance(), configMock(), resolver, mock(HaIdGeneratorFactory.class), mock(DelegateInvocationHandler.class), mock(ClusterMemberAvailability.class), requestContextFactory, pullerFactory, masterClientResolver, mock(SwitchToSlave.Monitor.class), storeCopyClient, Suppliers.singleton(dataSource), Suppliers.singleton(transactionIdStoreMock), slave -> {
        SlaveServer server = mock(SlaveServer.class);
        InetSocketAddress inetSocketAddress = InetSocketAddress.createUnresolved("localhost", 42);
        when(server.getSocketAddress()).thenReturn(inetSocketAddress);
        return server;
    }, updatePuller, pageCacheMock, mock(Monitors.class), transactionCounters));
}
Also used : InstanceId(org.neo4j.cluster.InstanceId) StoreId(org.neo4j.kernel.impl.store.StoreId) NeoStoreDataSource(org.neo4j.kernel.NeoStoreDataSource) MasterClientResolver(org.neo4j.kernel.ha.com.slave.MasterClientResolver) Suppliers(org.neo4j.function.Suppliers) URISyntaxException(java.net.URISyntaxException) OnlineBackupKernelExtension(org.neo4j.backup.OnlineBackupKernelExtension) DelegateInvocationHandler(org.neo4j.kernel.ha.DelegateInvocationHandler) Dependencies(org.neo4j.kernel.impl.util.Dependencies) LifeSupport(org.neo4j.kernel.lifecycle.LifeSupport) NullLogProvider(org.neo4j.logging.NullLogProvider) MasterClient(org.neo4j.kernel.ha.com.slave.MasterClient) Collections.singletonList(java.util.Collections.singletonList) StoreIdTestFactory.newStoreIdForCurrentVersion(org.neo4j.com.StoreIdTestFactory.newStoreIdForCurrentVersion) HighAvailabilityModeSwitcher(org.neo4j.kernel.ha.cluster.modeswitch.HighAvailabilityModeSwitcher) Mockito.doThrow(org.mockito.Mockito.doThrow) TransactionObligationFulfiller(org.neo4j.com.storecopy.TransactionObligationFulfiller) Matchers.eq(org.mockito.Matchers.eq) Mockito.doAnswer(org.mockito.Mockito.doAnswer) Matchers.anyInt(org.mockito.Matchers.anyInt) Assert.fail(org.junit.Assert.fail) URI(java.net.URI) MismatchingStoreIdException(org.neo4j.kernel.impl.store.MismatchingStoreIdException) Response(org.neo4j.com.Response) PageCache(org.neo4j.io.pagecache.PageCache) InetSocketAddress(java.net.InetSocketAddress) TransactionCommittingResponseUnpacker(org.neo4j.com.storecopy.TransactionCommittingResponseUnpacker) UpdatePuller(org.neo4j.kernel.ha.UpdatePuller) UpdatePullerScheduler(org.neo4j.kernel.ha.UpdatePullerScheduler) Matchers.any(org.mockito.Matchers.any) Stream(java.util.stream.Stream) ClusterMemberAvailability(org.neo4j.cluster.member.ClusterMemberAvailability) Mockito.withSettings(org.mockito.Mockito.withSettings) RequestContextFactory(org.neo4j.kernel.ha.com.RequestContextFactory) SlaveUpdatePuller(org.neo4j.kernel.ha.SlaveUpdatePuller) Mockito.mock(org.mockito.Mockito.mock) BranchedDataException(org.neo4j.kernel.ha.BranchedDataException) BranchedDataPolicy(org.neo4j.kernel.ha.BranchedDataPolicy) MoveAfterCopy(org.neo4j.com.storecopy.MoveAfterCopy) TransactionIdStore(org.neo4j.kernel.impl.transaction.log.TransactionIdStore) PagedFile(org.neo4j.io.pagecache.PagedFile) Monitors(org.neo4j.kernel.monitoring.Monitors) HandshakeResult(org.neo4j.kernel.ha.com.master.HandshakeResult) JobScheduler(org.neo4j.kernel.impl.util.JobScheduler) Mockito.spy(org.mockito.Mockito.spy) PullerFactory(org.neo4j.kernel.ha.PullerFactory) Matchers.anyString(org.mockito.Matchers.anyString) TransactionId(org.neo4j.kernel.impl.store.TransactionId) ClusterMembers(org.neo4j.kernel.ha.cluster.member.ClusterMembers) StoreLockerLifecycleAdapter(org.neo4j.kernel.internal.StoreLockerLifecycleAdapter) SlaveServer(org.neo4j.kernel.ha.com.slave.SlaveServer) HaIdGeneratorFactory(org.neo4j.kernel.ha.id.HaIdGeneratorFactory) CancellationRequest(org.neo4j.helpers.CancellationRequest) Matchers.anyLong(org.mockito.Matchers.anyLong) MapUtil.stringMap(org.neo4j.helpers.collection.MapUtil.stringMap) Lifecycle(org.neo4j.kernel.lifecycle.Lifecycle) Config(org.neo4j.kernel.configuration.Config) Test(org.junit.Test) IOException(java.io.IOException) Mockito.when(org.mockito.Mockito.when) DataSourceManager(org.neo4j.kernel.impl.transaction.state.DataSourceManager) File(java.io.File) Mockito.verify(org.mockito.Mockito.verify) TimeUnit(java.util.concurrent.TimeUnit) NullLogService(org.neo4j.kernel.impl.logging.NullLogService) Mockito.never(org.mockito.Mockito.never) IndexConfigStore(org.neo4j.kernel.impl.index.IndexConfigStore) Assert.assertNull(org.junit.Assert.assertNull) ClusterSettings(org.neo4j.cluster.ClusterSettings) StoreCopyClient(org.neo4j.com.storecopy.StoreCopyClient) TransactionStats(org.neo4j.kernel.impl.transaction.TransactionStats) ClusterMember(org.neo4j.kernel.ha.cluster.member.ClusterMember) FileSystemWatcherService(org.neo4j.kernel.impl.util.watcher.FileSystemWatcherService) MasterClient320(org.neo4j.kernel.ha.MasterClient320) FileSystemAbstraction(org.neo4j.io.fs.FileSystemAbstraction) HandshakeResult(org.neo4j.kernel.ha.com.master.HandshakeResult) TransactionObligationFulfiller(org.neo4j.com.storecopy.TransactionObligationFulfiller) InetSocketAddress(java.net.InetSocketAddress) OnlineBackupKernelExtension(org.neo4j.backup.OnlineBackupKernelExtension) ClusterMembers(org.neo4j.kernel.ha.cluster.member.ClusterMembers) DataSourceManager(org.neo4j.kernel.impl.transaction.state.DataSourceManager) SlaveServer(org.neo4j.kernel.ha.com.slave.SlaveServer) ClusterMember(org.neo4j.kernel.ha.cluster.member.ClusterMember) StoreId(org.neo4j.kernel.impl.store.StoreId) LifeSupport(org.neo4j.kernel.lifecycle.LifeSupport) Dependencies(org.neo4j.kernel.impl.util.Dependencies) TransactionIdStore(org.neo4j.kernel.impl.transaction.log.TransactionIdStore) InstanceId(org.neo4j.cluster.InstanceId) NeoStoreDataSource(org.neo4j.kernel.NeoStoreDataSource) IndexConfigStore(org.neo4j.kernel.impl.index.IndexConfigStore) TransactionCommittingResponseUnpacker(org.neo4j.com.storecopy.TransactionCommittingResponseUnpacker) TransactionId(org.neo4j.kernel.impl.store.TransactionId) MasterClientResolver(org.neo4j.kernel.ha.com.slave.MasterClientResolver) TransactionStats(org.neo4j.kernel.impl.transaction.TransactionStats) FileSystemWatcherService(org.neo4j.kernel.impl.util.watcher.FileSystemWatcherService) Monitors(org.neo4j.kernel.monitoring.Monitors) StoreLockerLifecycleAdapter(org.neo4j.kernel.internal.StoreLockerLifecycleAdapter) PagedFile(org.neo4j.io.pagecache.PagedFile) File(java.io.File)

Example 12 with MasterClient

use of org.neo4j.kernel.ha.com.slave.MasterClient in project neo4j by neo4j.

the class SwitchToSlave method executeConsistencyChecks.

private boolean executeConsistencyChecks(TransactionIdStore txIdStore, URI masterUri, URI me, StoreId storeId, CancellationRequest cancellationRequest) throws Throwable {
    LifeSupport consistencyCheckLife = new LifeSupport();
    try {
        MasterClient masterClient = newMasterClient(masterUri, me, storeId, consistencyCheckLife);
        consistencyCheckLife.start();
        if (cancellationRequest.cancellationRequested()) {
            return false;
        }
        checkDataConsistency(masterClient, txIdStore, storeId, masterUri, me, cancellationRequest);
    } finally {
        consistencyCheckLife.shutdown();
    }
    return true;
}
Also used : MasterClient(org.neo4j.kernel.ha.com.slave.MasterClient) LifeSupport(org.neo4j.kernel.lifecycle.LifeSupport)

Example 13 with MasterClient

use of org.neo4j.kernel.ha.com.slave.MasterClient in project neo4j by neo4j.

the class SwitchToSlave method copyStoreFromMaster.

void copyStoreFromMaster(MasterClient masterClient, CancellationRequest cancellationRequest, MoveAfterCopy moveAfterCopy) throws Throwable {
    try {
        userLog.info("Copying store from master");
        StoreCopyClient.StoreCopyRequester requester = new StoreCopyClient.StoreCopyRequester() {

            @Override
            public Response<?> copyStore(StoreWriter writer) {
                return masterClient.copyStore(new RequestContext(0, config.get(ClusterSettings.server_id).toIntegerIndex(), 0, BASE_TX_ID, 0), writer);
            }

            @Override
            public void done() {
            // Nothing to clean up here
            }
        };
        MoveAfterCopy moveAfterCopyWithLogging = (moves, fromDirectory, toDirectory) -> {
            userLog.info("Copied store from master to " + fromDirectory);
            msgLog.info("Starting post copy operation to move store from " + fromDirectory + " to " + storeDir);
            moveAfterCopy.move(moves, fromDirectory, toDirectory);
        };
        storeCopyClient.copyStore(requester, cancellationRequest, moveAfterCopyWithLogging);
        startServicesAgain();
        userLog.info("Finished copying store from master");
    } catch (Throwable t) {
        // Delete store so that we can copy from master without conflicts next time
        cleanStoreDir();
        throw t;
    }
}
Also used : InstanceId(org.neo4j.cluster.InstanceId) StoreId(org.neo4j.kernel.impl.store.StoreId) NeoStoreDataSource(org.neo4j.kernel.NeoStoreDataSource) MasterClientResolver(org.neo4j.kernel.ha.com.slave.MasterClientResolver) Log(org.neo4j.logging.Log) OnlineBackupKernelExtension(org.neo4j.backup.OnlineBackupKernelExtension) DelegateInvocationHandler(org.neo4j.kernel.ha.DelegateInvocationHandler) LifeSupport(org.neo4j.kernel.lifecycle.LifeSupport) RequestContext(org.neo4j.com.RequestContext) MasterClient(org.neo4j.kernel.ha.com.slave.MasterClient) HighAvailabilityModeSwitcher(org.neo4j.kernel.ha.cluster.modeswitch.HighAvailabilityModeSwitcher) TransactionObligationFulfiller(org.neo4j.com.storecopy.TransactionObligationFulfiller) URI(java.net.URI) MismatchingStoreIdException(org.neo4j.kernel.impl.store.MismatchingStoreIdException) StoreUtil(org.neo4j.com.storecopy.StoreUtil) ClusterMembers.hasInstanceId(org.neo4j.kernel.ha.cluster.member.ClusterMembers.hasInstanceId) Response(org.neo4j.com.Response) PageCache(org.neo4j.io.pagecache.PageCache) Iterables.filter(org.neo4j.helpers.collection.Iterables.filter) MissingLogDataException(org.neo4j.kernel.impl.transaction.log.MissingLogDataException) LogService(org.neo4j.kernel.impl.logging.LogService) MILLISECONDS(java.util.concurrent.TimeUnit.MILLISECONDS) TransactionCommittingResponseUnpacker(org.neo4j.com.storecopy.TransactionCommittingResponseUnpacker) UpdatePuller(org.neo4j.kernel.ha.UpdatePuller) UpdatePullerScheduler(org.neo4j.kernel.ha.UpdatePullerScheduler) UnableToCopyStoreFromOldMasterException(org.neo4j.kernel.ha.store.UnableToCopyStoreFromOldMasterException) ClusterMemberAvailability(org.neo4j.cluster.member.ClusterMemberAvailability) Iterables.firstOrNull(org.neo4j.helpers.collection.Iterables.firstOrNull) DependencyResolver(org.neo4j.graphdb.DependencyResolver) RequestContextFactory(org.neo4j.kernel.ha.com.RequestContextFactory) BranchedDataException(org.neo4j.kernel.ha.BranchedDataException) MoveAfterCopy(org.neo4j.com.storecopy.MoveAfterCopy) TransactionIdStore(org.neo4j.kernel.impl.transaction.log.TransactionIdStore) StoreWriter(org.neo4j.com.storecopy.StoreWriter) Monitors(org.neo4j.kernel.monitoring.Monitors) LockSupport.parkNanos(java.util.concurrent.locks.LockSupport.parkNanos) HandshakeResult(org.neo4j.kernel.ha.com.master.HandshakeResult) Function(java.util.function.Function) Supplier(java.util.function.Supplier) PullerFactory(org.neo4j.kernel.ha.PullerFactory) ServerUtil(org.neo4j.com.ServerUtil) TransactionId(org.neo4j.kernel.impl.store.TransactionId) ClusterMembers(org.neo4j.kernel.ha.cluster.member.ClusterMembers) StoreLockerLifecycleAdapter(org.neo4j.kernel.internal.StoreLockerLifecycleAdapter) SlaveServer(org.neo4j.kernel.ha.com.slave.SlaveServer) HaIdGeneratorFactory(org.neo4j.kernel.ha.id.HaIdGeneratorFactory) CancellationRequest(org.neo4j.helpers.CancellationRequest) HighAvailabilityModeSwitcher.getServerId(org.neo4j.kernel.ha.cluster.modeswitch.HighAvailabilityModeSwitcher.getServerId) NeoStores.isStorePresent(org.neo4j.kernel.impl.store.NeoStores.isStorePresent) BASE_TX_ID(org.neo4j.kernel.impl.transaction.log.TransactionIdStore.BASE_TX_ID) Lifecycle(org.neo4j.kernel.lifecycle.Lifecycle) Config(org.neo4j.kernel.configuration.Config) IOException(java.io.IOException) HaSettings(org.neo4j.kernel.ha.HaSettings) DataSourceManager(org.neo4j.kernel.impl.transaction.state.DataSourceManager) File(java.io.File) StoreOutOfDateException(org.neo4j.kernel.ha.StoreOutOfDateException) Server(org.neo4j.com.Server) SlaveImpl(org.neo4j.kernel.ha.com.slave.SlaveImpl) IndexConfigStore(org.neo4j.kernel.impl.index.IndexConfigStore) Clock(java.time.Clock) ClusterSettings(org.neo4j.cluster.ClusterSettings) Slave(org.neo4j.kernel.ha.com.master.Slave) StoreCopyClient(org.neo4j.com.storecopy.StoreCopyClient) TransactionStats(org.neo4j.kernel.impl.transaction.TransactionStats) ClusterMember(org.neo4j.kernel.ha.cluster.member.ClusterMember) FileSystemWatcherService(org.neo4j.kernel.impl.util.watcher.FileSystemWatcherService) Clocks(org.neo4j.time.Clocks) Master(org.neo4j.kernel.ha.com.master.Master) StoreWriter(org.neo4j.com.storecopy.StoreWriter) StoreCopyClient(org.neo4j.com.storecopy.StoreCopyClient) RequestContext(org.neo4j.com.RequestContext) MoveAfterCopy(org.neo4j.com.storecopy.MoveAfterCopy)

Example 14 with MasterClient

use of org.neo4j.kernel.ha.com.slave.MasterClient in project neo4j by neo4j.

the class MasterClientTest method clientShouldReadAndApplyTransactionLogsOnNewLockSessionRequest.

@Test
public void clientShouldReadAndApplyTransactionLogsOnNewLockSessionRequest() throws Throwable {
    // Given
    MasterImpl master = spy(newMasterImpl(mockMasterImplSpiWith(StoreId.DEFAULT)));
    doReturn(voidResponseWithTransactionLogs()).when(master).newLockSession(any(RequestContext.class));
    newMasterServer(master);
    Dependencies deps = mock(Dependencies.class);
    TransactionCommitProcess commitProcess = mock(TransactionCommitProcess.class);
    when(deps.commitProcess()).thenReturn(commitProcess);
    when(deps.logService()).thenReturn(NullLogService.getInstance());
    when(deps.kernelTransactions()).thenReturn(mock(KernelTransactions.class));
    ResponseUnpacker unpacker = life.add(new TransactionCommittingResponseUnpacker(deps, DEFAULT_BATCH_SIZE, 0));
    MasterClient masterClient = newMasterClient320(StoreId.DEFAULT, unpacker);
    // When
    masterClient.newLockSession(new RequestContext(1, 2, 3, 4, 5));
    // Then
    verify(commitProcess).commit(any(TransactionToApply.class), any(CommitEvent.class), any(TransactionApplicationMode.class));
}
Also used : TransactionToApply(org.neo4j.kernel.impl.api.TransactionToApply) MasterImpl(org.neo4j.kernel.ha.com.master.MasterImpl) MasterClient(org.neo4j.kernel.ha.com.slave.MasterClient) TransactionCommitProcess(org.neo4j.kernel.impl.api.TransactionCommitProcess) KernelTransactions(org.neo4j.kernel.impl.api.KernelTransactions) TransactionApplicationMode(org.neo4j.storageengine.api.TransactionApplicationMode) CommitEvent(org.neo4j.kernel.impl.transaction.tracing.CommitEvent) RequestContext(org.neo4j.com.RequestContext) Dependencies(org.neo4j.com.storecopy.TransactionCommittingResponseUnpacker.Dependencies) TransactionCommittingResponseUnpacker(org.neo4j.com.storecopy.TransactionCommittingResponseUnpacker) TransactionCommittingResponseUnpacker(org.neo4j.com.storecopy.TransactionCommittingResponseUnpacker) ResponseUnpacker(org.neo4j.com.storecopy.ResponseUnpacker) MasterImplTest(org.neo4j.kernel.ha.com.master.MasterImplTest) Test(org.junit.Test)

Example 15 with MasterClient

use of org.neo4j.kernel.ha.com.slave.MasterClient in project neo4j by neo4j.

the class MasterClientTest method endLockSessionDoesNotUnpackResponse.

@Test
public void endLockSessionDoesNotUnpackResponse() throws Throwable {
    StoreId storeId = new StoreId(1, 2, 3, 4, 5);
    long txChecksum = 123;
    long lastAppliedTx = 5;
    ResponseUnpacker responseUnpacker = mock(ResponseUnpacker.class);
    MasterImpl.SPI masterImplSPI = MasterImplTest.mockedSpi(storeId);
    when(masterImplSPI.packTransactionObligationResponse(any(RequestContext.class), Matchers.anyObject())).thenReturn(Response.empty());
    when(masterImplSPI.getTransactionChecksum(anyLong())).thenReturn(txChecksum);
    newMasterServer(masterImplSPI);
    MasterClient client = newMasterClient320(storeId, responseUnpacker);
    HandshakeResult handshakeResult;
    try (Response<HandshakeResult> handshakeResponse = client.handshake(1, storeId)) {
        handshakeResult = handshakeResponse.response();
    }
    verify(responseUnpacker).unpackResponse(any(Response.class), any(TxHandler.class));
    reset(responseUnpacker);
    RequestContext context = new RequestContext(handshakeResult.epoch(), 1, 1, lastAppliedTx, txChecksum);
    client.endLockSession(context, false);
    verify(responseUnpacker, never()).unpackResponse(any(Response.class), any(TxHandler.class));
}
Also used : Response(org.neo4j.com.Response) TransactionStreamResponse(org.neo4j.com.TransactionStreamResponse) HandshakeResult(org.neo4j.kernel.ha.com.master.HandshakeResult) MasterImpl(org.neo4j.kernel.ha.com.master.MasterImpl) TxHandler(org.neo4j.com.storecopy.ResponseUnpacker.TxHandler) StoreId(org.neo4j.kernel.impl.store.StoreId) MasterClient(org.neo4j.kernel.ha.com.slave.MasterClient) RequestContext(org.neo4j.com.RequestContext) TransactionCommittingResponseUnpacker(org.neo4j.com.storecopy.TransactionCommittingResponseUnpacker) ResponseUnpacker(org.neo4j.com.storecopy.ResponseUnpacker) MasterImplTest(org.neo4j.kernel.ha.com.master.MasterImplTest) Test(org.junit.Test)

Aggregations

MasterClient (org.neo4j.kernel.ha.com.slave.MasterClient)16 Test (org.junit.Test)11 StoreId (org.neo4j.kernel.impl.store.StoreId)11 URI (java.net.URI)9 TransactionId (org.neo4j.kernel.impl.store.TransactionId)9 TransactionIdStore (org.neo4j.kernel.impl.transaction.log.TransactionIdStore)9 BranchedDataPolicy (org.neo4j.kernel.ha.BranchedDataPolicy)7 HandshakeResult (org.neo4j.kernel.ha.com.master.HandshakeResult)7 LifeSupport (org.neo4j.kernel.lifecycle.LifeSupport)7 CancellationRequest (org.neo4j.helpers.CancellationRequest)6 BranchedDataException (org.neo4j.kernel.ha.BranchedDataException)6 File (java.io.File)5 PageCache (org.neo4j.io.pagecache.PageCache)5 SlaveServer (org.neo4j.kernel.ha.com.slave.SlaveServer)5 MismatchingStoreIdException (org.neo4j.kernel.impl.store.MismatchingStoreIdException)5 IOException (java.io.IOException)4 InstanceId (org.neo4j.cluster.InstanceId)4 ClusterMemberAvailability (org.neo4j.cluster.member.ClusterMemberAvailability)4 MoveAfterCopy (org.neo4j.com.storecopy.MoveAfterCopy)4 StoreCopyClient (org.neo4j.com.storecopy.StoreCopyClient)4