| /* |
| * 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.iotdb.db.storageengine.dataregion.tsfile.generator; |
| |
| import org.apache.iotdb.commons.file.SystemFileFactory; |
| |
| import org.apache.commons.io.FileUtils; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.nio.file.Files; |
| |
| /** SimpleFileVersionController uses a local file and its file name to store the version. */ |
| public class SimpleFileVersionController implements VersionController { |
| |
| private static final Logger logger = LoggerFactory.getLogger(SimpleFileVersionController.class); |
| public static final String FILE_PREFIX = "Version-"; |
| public static final String UPGRADE_DIR = "upgrade"; |
| |
| /** |
| * Every time currVersion - prevVersion >= saveInterval, currVersion is persisted and prevVersion |
| * is set to currVersion. When recovering from file, the version number is automatically increased |
| * by saveInterval to avoid conflicts. |
| */ |
| private static long saveInterval = 100; |
| |
| /** time partition id to dividing time series into different database */ |
| private long timePartitionId; |
| |
| private long prevVersion; |
| private long currVersion; |
| private String directoryPath; |
| |
| public SimpleFileVersionController(String directoryPath, long timePartitionId) |
| throws IOException { |
| this.directoryPath = directoryPath + File.separator + timePartitionId; |
| this.timePartitionId = timePartitionId; |
| restore(); |
| } |
| |
| /** only used for upgrading */ |
| public SimpleFileVersionController(String directoryPath) throws IOException { |
| this.directoryPath = directoryPath + File.separator + UPGRADE_DIR; |
| restore(); |
| } |
| |
| public static long getSaveInterval() { |
| return saveInterval; |
| } |
| |
| // test only method |
| public static void setSaveInterval(long saveInterval) { |
| SimpleFileVersionController.saveInterval = saveInterval; |
| } |
| |
| public long getTimePartitionId() { |
| return timePartitionId; |
| } |
| |
| public void setTimePartitionId(long timePartitionId) { |
| this.timePartitionId = timePartitionId; |
| } |
| |
| @Override |
| public synchronized long nextVersion() { |
| currVersion++; |
| try { |
| checkPersist(); |
| } catch (IOException e) { |
| logger.error("Error occurred when getting next version.", e); |
| } |
| return currVersion; |
| } |
| |
| /** |
| * Test only method, no need for concurrency. |
| * |
| * @return the current version. |
| */ |
| @Override |
| public long currVersion() { |
| return currVersion; |
| } |
| |
| private void checkPersist() throws IOException { |
| if ((currVersion - prevVersion) >= saveInterval) { |
| persist(); |
| } |
| } |
| |
| private void persist() throws IOException { |
| File oldFile = SystemFileFactory.INSTANCE.getFile(directoryPath, FILE_PREFIX + prevVersion); |
| File newFile = SystemFileFactory.INSTANCE.getFile(directoryPath, FILE_PREFIX + currVersion); |
| if (oldFile.exists()) { |
| FileUtils.moveFile(oldFile, newFile); |
| } |
| logger.info( |
| "Version file updated, previous: {}, current: {}", |
| oldFile.getAbsolutePath(), |
| newFile.getAbsolutePath()); |
| prevVersion = currVersion; |
| } |
| |
| /** recovery from disk */ |
| @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning |
| private void restore() throws IOException { |
| File directory = SystemFileFactory.INSTANCE.getFile(directoryPath); |
| if (!directory.exists()) { |
| directory.mkdirs(); |
| } |
| File[] versionFiles = directory.listFiles((dir, name) -> name.startsWith(FILE_PREFIX)); |
| File versionFile; |
| if (versionFiles != null && versionFiles.length > 0) { |
| long maxVersion = 0; |
| int maxVersionIndex = 0; |
| for (int i = 0; i < versionFiles.length; i++) { |
| // extract version from "Version-123456" |
| long fileVersion = Long.parseLong(versionFiles[i].getName().split("-")[1]); |
| if (fileVersion > maxVersion) { |
| maxVersion = fileVersion; |
| maxVersionIndex = i; |
| } |
| } |
| prevVersion = maxVersion; |
| for (int i = 0; i < versionFiles.length; i++) { |
| if (i != maxVersionIndex) { |
| Files.delete(versionFiles[i].toPath()); |
| } |
| } |
| } else { |
| versionFile = SystemFileFactory.INSTANCE.getFile(directory, FILE_PREFIX + "0"); |
| prevVersion = 0; |
| if (!versionFile.createNewFile()) { |
| logger.warn("Cannot create new version file {}", versionFile); |
| } |
| } |
| // prevent overlapping in case of failure |
| currVersion = prevVersion + saveInterval; |
| persist(); |
| } |
| } |