/* * Copyright (c) 2013-2017 Cinchapi Inc. * * Licensed 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 com.cinchapi.concourse.server.upgrade; import java.io.File; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel.MapMode; import com.cinchapi.concourse.annotate.Restricted; import com.cinchapi.concourse.server.GlobalState; import com.cinchapi.concourse.server.io.FileSystem; import com.cinchapi.concourse.util.Logger; /** * An {@link UpgradeTask} performs an operation that "upgrades" previously * stored data. All tasks that are defined in the * {@code com.cinchapi.concourse.server.upgrade.task} package and are * higher than the current system version are automatically run by the * {@link Upgrader} whenever the user upgrades the ConcourseServer. * * @author Jeff Nelson */ public abstract class UpgradeTask implements Comparable<UpgradeTask> { /** * Return the current system version. * * @return the current storage version */ public static int getCurrentSystemVersion() { return Math.min(getBufferSystemVersion(), getDbSystemVersion()); } /** * Update the system version of the Concourse Server installation to * {@code version}. * * @param version */ @Restricted public static void setCurrentSystemVersion(int version) { ((MappedByteBuffer) FileSystem.map(BUFFER_VERSION_FILE, MapMode.READ_WRITE, 0, 4).putInt(version)).force(); ((MappedByteBuffer) FileSystem.map(DB_VERSION_FILE, MapMode.READ_WRITE, 0, 4).putInt(version)).force(); } /** * Return the current buffer system version. * * @return the buffer system */ private static int getBufferSystemVersion() { if(FileSystem.hasFile(BUFFER_VERSION_FILE)) { return FileSystem.map(BUFFER_VERSION_FILE, MapMode.READ_ONLY, 0, 4) .getInt(); } else { return 0; } } /** * Return the current database system version. * * @return the db system */ private static int getDbSystemVersion() { if(FileSystem.hasFile(DB_VERSION_FILE)) { return FileSystem.map(DB_VERSION_FILE, MapMode.READ_ONLY, 0, 4) .getInt(); } else { return 0; } } /** * The name of the file we use to hold the internal system version of the * most recently run upgrade task. */ private static String VERSION_FILE_NAME = ".schema"; /** * The name of the file we use to hold the internal system version of the * most recently run upgrade task in the Database. */ private static final String DB_VERSION_FILE = GlobalState.DATABASE_DIRECTORY + File.separator + VERSION_FILE_NAME; /** * The name of the file we use to hold the the internal system version of * the most recently run upgrade task in the Buffer. */ private static final String BUFFER_VERSION_FILE = GlobalState.BUFFER_DIRECTORY + File.separator + VERSION_FILE_NAME; @Override public int compareTo(UpgradeTask o) { return Integer.compare(version(), o.version()); } @Override public boolean equals(Object obj) { if(obj instanceof UpgradeTask) { return version() == ((UpgradeTask) obj).version(); } else { return false; } } /** * Return a description of the upgrade task that informs the user about the * operation. * * @return the description */ public abstract String getDescription(); @Override public int hashCode() { return version(); } /** * Run the upgrade task. */ public void run() { logInfoMessage("STARTING {}", this); try { doTask(); setCurrentSystemVersion(version()); logInfoMessage("FINISHED {}", this); } catch (Exception e) { logErrorMessage("FAILED {}: {}", this, e); throw e; } } @Override public String toString() { return "Upgrade Task " + version() + ": " + getDescription(); } /** * Return the numerical system version of this task. Each upgrade task * should have a unique system version that is higher than any other task on * which it depends. * * @return the storage version of this task */ public abstract int version(); /** * Implement the logic for the upgrade task. Any thrown exceptions will * cause the task to fail. */ protected abstract void doTask(); /** * Return the path to the server installation directory, from which other * aspects of the Concourse Server deployment are accessible. This is * typically the working directory from which Concourse Server is launched. */ protected String getServerInstallDirectory() { return System.getProperty("user.dir"); } /** * Print a DEBUG log message. * * @param message * @param params */ protected final void logDebugMessage(String message, Object... params) { Logger.debug(decorateLogMessage(message), params); } /** * Print an ERROR log message. * * @param message * @param params */ protected final void logErrorMessage(String message, Object... params) { Logger.error(decorateLogMessage(message), params); } /** * Print an INFO log message. * * @param message * @param params */ protected final void logInfoMessage(String message, Object... params) { Logger.info(decorateLogMessage(message), params); } /** * Print a WARN log message. * * @param message * @param params */ protected final void logWarnMessage(String message, Object... params) { Logger.warn(decorateLogMessage(message), params); } /** * Decorate the log {@code message} to conform the upgrade task * identification standards. * * @param message * @return the formatted log message */ private String decorateLogMessage(String message) { return "Upgrade(" + version() + "): " + message; } }