private void DownloadDatabase(StoreId localStoreId) { try { _localDatabase.stopForStoreCopy(); _enableDisableOnStoreCopy.disable(); } catch (Exception throwable) { throw new Exception(throwable); } try { MemberId source = _selectionStrategy.bestUpstreamDatabase(); AdvertisedSocketAddress fromAddress = _topologyService.findCatchupAddress(source).orElseThrow(() => new TopologyLookupException(source)); _storeCopyProcess.replaceWithStoreFrom(new CatchupAddressProvider_SingleAddressProvider(fromAddress), localStoreId); } catch (Exception e) when(e is IOException || e is StoreCopyFailedException || e is UpstreamDatabaseSelectionException || e is TopologyLookupException) { _log.warn("Error copying store. Will retry shortly.", e); return; } catch (DatabaseShutdownException e) { _log.warn("Store copy aborted due to shutdown.", e); return; } try { _localDatabase.start(); _enableDisableOnStoreCopy.enable(); } catch (Exception throwable) { throw new Exception(throwable); } _latestTxIdOfUpStream = 0; // we will find out on the next pull request response _state = TX_PULLING; _applier.refreshFromNewStore(); }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: private void syncStoreWithUpstream(org.neo4j.causalclustering.identity.MemberId source) throws java.io.IOException, org.neo4j.causalclustering.catchup.storecopy.StoreIdDownloadFailedException, org.neo4j.causalclustering.catchup.storecopy.StoreCopyFailedException, org.neo4j.causalclustering.core.state.snapshot.TopologyLookupException, org.neo4j.causalclustering.catchup.storecopy.DatabaseShutdownException private void SyncStoreWithUpstream(MemberId source) { if (_localDatabase.Empty) { _debugLog.info("Local database is empty, attempting to replace with copy from upstream server %s", source); _debugLog.info("Finding store id of upstream server %s", source); AdvertisedSocketAddress fromAddress = _topologyService.findCatchupAddress(source).orElseThrow(() => new TopologyLookupException(source)); StoreId storeId = _remoteStore.getStoreId(fromAddress); _debugLog.info("Copying store from upstream server %s", source); _localDatabase.delete(); _storeCopyProcess.replaceWithStoreFrom(new CatchupAddressProvider_SingleAddressProvider(fromAddress), storeId); _debugLog.info("Restarting local database after copy.", source); } else { EnsureSameStoreIdAs(source); } }
/// <summary> /// Tries to catchup this instance by downloading a snapshot. A snapshot consists of both the /// comparatively small state of the cluster state machines as well as the database store. The /// store is however caught up using two different approach. If it is possible to catchup by /// pulling transactions, then this will be sufficient, but if the store is lagging too far /// behind then a complete store copy will be attempted. /// </summary> /// <param name="addressProvider"> Provider of addresses to catchup from. </param> /// <returns> True if the operation succeeded, and false otherwise. </returns> /// <exception cref="LifecycleException"> A major database component failed to start or stop. </exception> /// <exception cref="IOException"> An issue with I/O. </exception> /// <exception cref="DatabaseShutdownException"> The database is shutting down. </exception> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //ORIGINAL LINE: boolean downloadSnapshot(org.neo4j.causalclustering.catchup.CatchupAddressProvider addressProvider) throws org.neo4j.kernel.lifecycle.LifecycleException, java.io.IOException, org.neo4j.causalclustering.catchup.storecopy.DatabaseShutdownException internal virtual bool DownloadSnapshot(CatchupAddressProvider addressProvider) { /* Extract some key properties before shutting it down. */ bool isEmptyStore = _localDatabase.Empty; /* * There is no reason to try to recover if there are no transaction logs and in fact it is * also problematic for the initial transaction pull during the snapshot download because the * kernel will create a transaction log with a header where previous index points to the same * index as that written down into the metadata store. This is problematic because we have no * guarantee that there are later transactions and we need at least one transaction in * the log to figure out the Raft log index (see {@link RecoverConsensusLogIndex}). */ if (_commitStateHelper.hasTxLogs(_localDatabase.databaseLayout())) { _log.info("Recovering local database"); Ensure(_localDatabase.start, "start local database"); Ensure(_localDatabase.stop, "stop local database"); } AdvertisedSocketAddress primary; StoreId remoteStoreId; try { primary = addressProvider.Primary(); remoteStoreId = _remoteStore.getStoreId(primary); } catch (Exception e) when(e is CatchupAddressResolutionException || e is StoreIdDownloadFailedException) { _log.warn("Store copy failed", e); return(false); } if (!isEmptyStore && !remoteStoreId.Equals(_localDatabase.storeId())) { _log.error("Store copy failed due to store ID mismatch"); return(false); } Ensure(_suspendOnStoreCopy.disable, "disable auxiliary services before store copy"); Ensure(_localDatabase.stopForStoreCopy, "stop local database for store copy"); _log.info("Downloading snapshot from core server at %s", primary); /* The core snapshot must be copied before the store, because the store has a dependency on * the state of the state machines. The store will thus be at or ahead of the state machines, * in consensus log index, and application of commands will bring them in sync. Any such commands * that carry transactions will thus be ignored by the transaction/token state machines, since they * are ahead, and the correct decisions for their applicability have already been taken as encapsulated * in the copied store. */ CoreSnapshot coreSnapshot; try { coreSnapshot = _catchUpClient.makeBlockingRequest(primary, new CoreSnapshotRequest(), new CatchUpResponseAdaptorAnonymousInnerClass(this)); } catch (CatchUpClientException e) { _log.warn("Store copy failed", e); return(false); } if (!isEmptyStore) { StoreId localStoreId = _localDatabase.storeId(); CatchupResult catchupResult; try { catchupResult = _remoteStore.tryCatchingUp(primary, localStoreId, _localDatabase.databaseLayout(), false, false); } catch (StoreCopyFailedException e) { _log.warn("Failed to catch up", e); return(false); } if (catchupResult == E_TRANSACTION_PRUNED) { _log.warn(format("Failed to pull transactions from (%s). They may have been pruned away", primary)); _localDatabase.delete(); isEmptyStore = true; } else if (catchupResult != SUCCESS_END_OF_STREAM) { _log.warn(format("Unexpected catchup operation result %s from %s", catchupResult, primary)); return(false); } } if (isEmptyStore) { try { _storeCopyProcess.replaceWithStoreFrom(addressProvider, remoteStoreId); } catch (StoreCopyFailedException e) { _log.warn("Failed to copy and replace store", e); return(false); } } /* We install the snapshot after the store has been downloaded, * so that we are not left with a state ahead of the store. */ _snapshotService.installSnapshot(coreSnapshot); _log.info("Core snapshot installed: " + coreSnapshot); /* Starting the database will invoke the commit process factory in * the EnterpriseCoreEditionModule, which has important side-effects. */ _log.info("Starting local database"); Ensure(_localDatabase.start, "start local database after store copy"); _coreStateMachines.installCommitProcess(_localDatabase.CommitProcess); Ensure(_suspendOnStoreCopy.enable, "enable auxiliary services after store copy"); return(true); }