blob: 20efdfdf5aab11cd7032e8a9a4f877eb99be0f91 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.geode.internal.cache.backup;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.Logger;
import org.apache.geode.cache.DiskStore;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.internal.ClassPathLoader;
import org.apache.geode.internal.DeployedJar;
import org.apache.geode.internal.JarDeployer;
import org.apache.geode.internal.cache.DirectoryHolder;
import org.apache.geode.internal.cache.DiskStoreImpl;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.cache.Oplog;
import org.apache.geode.internal.lang.SystemUtils;
import org.apache.geode.internal.logging.LogService;
class BackupFileCopier {
private static final Logger logger = LogService.getLogger();
private static final String CONFIG_DIRECTORY = "config";
private static final String USER_FILES = "user";
private final InternalCache cache;
private final TemporaryBackupFiles temporaryFiles;
private final BackupDefinition backupDefinition = new BackupDefinition();
private final Path userDirectory;
private final Path configDirectory;
BackupFileCopier(InternalCache cache, TemporaryBackupFiles temporaryFiles) {
this.cache = cache;
this.temporaryFiles = temporaryFiles;
userDirectory = temporaryFiles.getDirectory().resolve(USER_FILES);
configDirectory = temporaryFiles.getDirectory().resolve(CONFIG_DIRECTORY);
}
BackupDefinition getBackupDefinition() {
return backupDefinition;
}
void copyConfigFiles() throws IOException {
ensureExistence(configDirectory);
addConfigFileToBackup(cache.getCacheXmlURL());
addConfigFileToBackup(DistributedSystem.getPropertiesFileURL());
// TODO: should the gfsecurity.properties file be backed up?
}
private void ensureExistence(Path directory) throws IOException {
if (!Files.exists(directory)) {
Files.createDirectories(directory);
}
}
private void addConfigFileToBackup(URL fileUrl) throws IOException {
if (fileUrl == null) {
return;
}
try {
Path source = getSource(fileUrl);
if (Files.notExists(source)) {
return;
}
Path destination = configDirectory.resolve(source.getFileName());
Files.copy(source, destination, StandardCopyOption.COPY_ATTRIBUTES);
backupDefinition.addConfigFileToBackup(destination);
} catch (URISyntaxException e) {
throw new IOException(e);
}
}
Set<File> copyUserFiles() throws IOException {
ensureExistence(userDirectory);
List<File> backupFiles = cache.getBackupFiles();
Set<File> userFilesBackedUp = new HashSet<>();
for (File original : backupFiles) {
if (original.exists()) {
original = original.getAbsoluteFile();
Path destination = userDirectory.resolve(original.getName());
if (original.isDirectory()) {
FileUtils.copyDirectory(original, destination.toFile());
} else {
Files.copy(original.toPath(), destination, StandardCopyOption.COPY_ATTRIBUTES);
}
backupDefinition.addUserFilesToBackup(destination, original.toPath());
userFilesBackedUp.add(original);
}
}
return userFilesBackedUp;
}
Set<File> copyDeployedJars() throws IOException {
ensureExistence(userDirectory);
Set<File> userJars = new HashSet<>();
JarDeployer deployer = null;
try {
// Suspend any user deployed jar file updates during this backup.
deployer = getJarDeployer();
deployer.suspendAll();
List<DeployedJar> jarList = deployer.findDeployedJars();
for (DeployedJar jar : jarList) {
File source = new File(jar.getFileCanonicalPath());
String sourceFileName = source.getName();
Path destination = userDirectory.resolve(sourceFileName);
Files.copy(source.toPath(), destination, StandardCopyOption.COPY_ATTRIBUTES);
backupDefinition.addDeployedJarToBackup(destination, source.toPath());
userJars.add(source);
}
} finally {
// Re-enable user deployed jar file updates.
if (deployer != null) {
deployer.resumeAll();
}
}
return userJars;
}
void copyDiskInitFile(DiskStoreImpl diskStore) throws IOException {
File diskInitFile = diskStore.getDiskInitFile().getIFFile();
String subDirName = Integer.toString(diskStore.getInforFileDirIndex());
Path subDir = temporaryFiles.getDirectory().resolve(subDirName);
Files.createDirectories(subDir);
Files.copy(diskInitFile.toPath(), subDir.resolve(diskInitFile.getName()),
StandardCopyOption.COPY_ATTRIBUTES);
backupDefinition.addDiskInitFile(diskStore, subDir.resolve(diskInitFile.getName()));
}
void copyOplog(DiskStore diskStore, Oplog oplog) throws IOException {
DirectoryHolder dirHolder = oplog.getDirectoryHolder();
copyOplogFile(diskStore, dirHolder, oplog.getCrfFile());
copyOplogFile(diskStore, dirHolder, oplog.getDrfFile());
copyOplogFile(diskStore, dirHolder, oplog.getKrfFile());
}
private void copyOplogFile(DiskStore diskStore, DirectoryHolder dirHolder, File file)
throws IOException {
if (file == null || !file.exists()) {
return;
}
Path tempDiskDir = temporaryFiles.getDiskStoreDirectory(diskStore, dirHolder);
if (!SystemUtils.isWindows()) {
try {
createLink(tempDiskDir.resolve(file.getName()), file.toPath());
} catch (IOException e) {
logger.warn("Unable to create hard link for {}. Reverting to file copy",
tempDiskDir.toString());
FileUtils.copyFileToDirectory(file, tempDiskDir.toFile());
}
} else {
// Hard links cannot be deleted on Windows if the process is still running, so prefer to
// actually copy the files.
FileUtils.copyFileToDirectory(file, tempDiskDir.toFile());
}
backupDefinition.addOplogFileToBackup(diskStore, tempDiskDir.resolve(file.getName()));
}
JarDeployer getJarDeployer() {
return ClassPathLoader.getLatest().getJarDeployer();
}
void createLink(Path link, Path existing) throws IOException {
Files.createLink(link, existing);
}
Path getSource(URL fileUrl) throws URISyntaxException {
return Paths.get(fileUrl.toURI());
}
}