f : filesDownloaded)
+ {
+ String fname = (String) f.get(NAME);
+ // the segments file must be copied last
+ // or else if there is a failure in between the
+ // index will be corrupted
+ if (fname.startsWith("segments_"))
+ {
+ //The segments file must be copied in the end
+ //Otherwise , if the copy fails index ends up corrupted
+ segmentsFile = fname;
+ continue;
+ }
+ if (!moveAFile(tmpIdxDir, indexDir, fname))
+ return false;
+ }
+ //copy the segments file last
+ if (segmentsFile != null)
+ {
+ return moveAFile(tmpIdxDir, indexDir, segmentsFile);
+ }
+ return true;
+ }
+
+ /**
+ *
+ * Copy all the tlog files from the temp tlog dir to the actual tlog dir, and reset
+ * the {@link UpdateLog}. The copy will try to preserve the original tlog directory
+ * if the copy fails.
+ *
+ *
+ * This assumes that the tlog files transferred from the leader are in synch with the
+ * index files transferred from the leader. The reset of the update log relies on the version
+ * of the latest operations found in the tlog files. If the tlogs are ahead of the latest commit
+ * point, it will not copy all the needed buffered updates for the replay and it will miss
+ * some operations.
+ *
+ */
+ private boolean moveTlogFiles(File tmpTlogDir)
+ {
+ UpdateLog ulog = solrCore.getUpdateHandler().getUpdateLog();
+
+ VersionInfo vinfo = ulog.getVersionInfo();
+ vinfo.blockUpdates(); // block updates until the new update log is initialised
+ try
+ {
+ // reset the update log before copying the new tlog directory
+ CdcrUpdateLog.BufferedUpdates bufferedUpdates = ((CdcrUpdateLog) ulog).resetForRecovery();
+ // try to move the temp tlog files to the tlog directory
+ if (!copyTmpTlogFiles2Tlog(tmpTlogDir))
+ return false;
+ // reinitialise the update log and copy the buffered updates
+ if (bufferedUpdates.tlog != null)
+ {
+ // map file path to its new backup location
+ File parentDir = FileSystems.getDefault()
+ .getPath(solrCore.getUpdateHandler().getUpdateLog().getLogDir()).getParent().toFile();
+ File backupTlogDir = new File(parentDir, tmpTlogDir.getName());
+ bufferedUpdates.tlog = new File(backupTlogDir, bufferedUpdates.tlog.getName());
+ }
+ // init the update log with the new set of tlog files, and copy the buffered updates
+ ((CdcrUpdateLog) ulog).initForRecovery(bufferedUpdates.tlog, bufferedUpdates.offset);
+ }
+ catch (Exception e)
+ {
+ LOG.error("Unable to copy tlog files", e);
+ return false;
+ }
+ finally
+ {
+ vinfo.unblockUpdates();
+ }
+ return true;
+ }
+
+ /**
+ * Make file list
+ */
+ private List makeTmpConfDirFileList(File dir, List fileList)
+ {
+ File[] files = dir.listFiles();
+
+ if (files != null)
+ {
+ for (File file : files)
+ {
+ if (file.isFile())
+ {
+ fileList.add(file);
+ }
+ else if (file.isDirectory())
+ {
+ fileList = makeTmpConfDirFileList(file, fileList);
+ }
+ }
+ }
+ return fileList;
+ }
+
+ /**
+ * The conf files are copied to the tmp dir to the conf dir. A backup of the old file is maintained
+ */
+ private void copyTmpConfFiles2Conf(File tmpconfDir)
+ {
+ boolean status;
+ File confDir = new File(solrCore.getResourceLoader().getConfigDir());
+ for (File file : makeTmpConfDirFileList(tmpconfDir, new ArrayList<>()))
+ {
+ File oldFile = new File(confDir,
+ file.getPath().substring(tmpconfDir.getPath().length(), file.getPath().length()));
+ if (!oldFile.getParentFile().exists())
+ {
+ status = oldFile.getParentFile().mkdirs();
+ if (!status)
+ {
+ throw new SolrException(ErrorCode.SERVER_ERROR, "Unable to mkdirs: " + oldFile.getParentFile());
+ }
+ }
+ if (oldFile.exists())
+ {
+ File backupFile = new File(oldFile.getPath() + "." + getDateAsStr(new Date(oldFile.lastModified())));
+ if (!backupFile.getParentFile().exists())
+ {
+ status = backupFile.getParentFile().mkdirs();
+ if (!status)
+ {
+ throw new SolrException(ErrorCode.SERVER_ERROR,
+ "Unable to mkdirs: " + backupFile.getParentFile());
+ }
+ }
+ status = oldFile.renameTo(backupFile);
+ if (!status)
+ {
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+ "Unable to rename: " + oldFile + " to: " + backupFile);
+ }
+ }
+ status = file.renameTo(oldFile);
+ if (!status)
+ {
+ throw new SolrException(ErrorCode.SERVER_ERROR, "Unable to rename: " + file + " to: " + oldFile);
+ }
+ }
+ }
+
+ /**
+ * Copy the downloaded content store files into the contentstore directory
+ * @param tmpContentStoreDir
+ * @param contentStorePath
+ * @throws IOException
+ */
+ private void copyTmpContentStoreToContentStore(File tmpContentStoreDir, String contentStorePath) throws Exception
+ {
+
+ String tmpContentStorePath = tmpContentStoreDir.getPath();
+
+ Files.walk(tmpContentStoreDir.toPath()).forEach(p -> {
+ File tmpFile = new File(p.toUri());
+ if (!tmpFile.isDirectory())
+ {
+ File csFile = new File(p.toString().replace(tmpContentStorePath, contentStorePath));
+ try
+ {
+ Files.createDirectories(Paths.get(csFile.getParent()));
+ Files.move(tmpFile.toPath(), csFile.toPath(), StandardCopyOption.ATOMIC_MOVE);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+
+
+ /**
+ * Deletes the files in filesToDelete list from contentStore
+ * @param contentStorePath
+ * @param filesToDelete
+ */
+ private void deleteContentStoreFiles(String contentStorePath, List