Skip to content
This repository has been archived by the owner on Jul 26, 2022. It is now read-only.

Commit

Permalink
Merging develop into feature/atomic-operations
Browse files Browse the repository at this point in the history
  • Loading branch information
pimotte committed Aug 12, 2014
1 parent 4388a1b commit de47aa8
Show file tree
Hide file tree
Showing 22 changed files with 463 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.syncany.cli.util.CliUtil;

public abstract class AbstractHistoryCommand extends Command {
protected static final Logger logger = Logger.getLogger(AbstractHistoryCommand.class.getSimpleName());
protected static final String dateFormatPattern = "yy-MM-dd HH:mm:ss";
Expand All @@ -35,24 +37,7 @@ protected Date parseDateOption(String dateStr) throws Exception {
Matcher relativeDateMatcher = relativeDatePattern.matcher(dateStr);

if (relativeDateMatcher.find()) {
relativeDateMatcher.reset();
long restoreDateMillies = 0;

while (relativeDateMatcher.find()) {
double time = Double.parseDouble(relativeDateMatcher.group(1));
String unitStr = relativeDateMatcher.group(2).toLowerCase();
int unitMultiplier = 0;

if (unitStr.startsWith("mo")) { unitMultiplier = 30*24*60*60; } // must be before "m"
else if (unitStr.startsWith("s")) { unitMultiplier = 1; }
else if (unitStr.startsWith("m")) { unitMultiplier = 60; }
else if (unitStr.startsWith("h")) { unitMultiplier = 60*60; }
else if (unitStr.startsWith("d")) { unitMultiplier = 24*60*60; }
else if (unitStr.startsWith("w")) { unitMultiplier = 7*24*60*60; }
else if (unitStr.startsWith("y")) { unitMultiplier = 365*24*60*60; }

restoreDateMillies += (long) ((double)time*unitMultiplier)*1000;
}
long restoreDateMillies = CliUtil.parseTimePeriod(dateStr)*1000;

Date restoreDate = new Date(System.currentTimeMillis()-restoreDateMillies);

Expand Down
31 changes: 31 additions & 0 deletions syncany-cli/src/main/java/org/syncany/cli/CleanupCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import joptsimple.OptionSet;
import joptsimple.OptionSpec;

import org.syncany.cli.util.CliUtil;
import org.syncany.database.MultiChunkEntry;
import org.syncany.operations.cleanup.CleanupOperationOptions;
import org.syncany.operations.cleanup.CleanupOperationResult;
Expand Down Expand Up @@ -49,12 +50,18 @@ public CleanupOperationOptions parseOptions(String[] operationArgs) throws Excep
OptionParser parser = new OptionParser();
parser.allowsUnrecognizedOptions();

OptionSpec<Void> optionForce = parser.accepts("force");
OptionSpec<Void> optionNoDatabaseMerge = parser.acceptsAll(asList("M", "no-database-merge"));
OptionSpec<Void> optionNoOldVersionRemoval = parser.acceptsAll(asList("V", "no-version-remove"));
OptionSpec<Integer> optionKeepVersions = parser.acceptsAll(asList("k", "keep-versions")).withRequiredArg().ofType(Integer.class);
OptionSpec<String> optionSecondsBetweenCleanups = parser.acceptsAll(asList("t", "time-between-cleanups")).withRequiredArg().ofType(String.class);
OptionSpec<Integer> optionMaxDatabaseFiles = parser.acceptsAll(asList("x", "max-database-files")).withRequiredArg().ofType(Integer.class);

OptionSet options = parser.parse(operationArgs);

// -F, --force
operationOptions.setForce(options.has(optionForce));

// -M, --no-database-merge
operationOptions.setMergeRemoteFiles(!options.has(optionNoDatabaseMerge));

Expand All @@ -72,6 +79,28 @@ public CleanupOperationOptions parseOptions(String[] operationArgs) throws Excep
operationOptions.setKeepVersionsCount(options.valueOf(optionKeepVersions));
}

// -t=<count>, --time-between-cleanups=<count>
if (options.has(optionSecondsBetweenCleanups)) {
long secondsBetweenCleanups = CliUtil.parseTimePeriod(options.valueOf(optionSecondsBetweenCleanups));

if (secondsBetweenCleanups < 0) {
throw new Exception("Invalid value for --time-between-cleanups="+secondsBetweenCleanups+"; must be >= 0");
}

operationOptions.setMinSecondsBetweenCleanups(secondsBetweenCleanups);
}

// -d=<count>, --max-database-files=<count>
if (options.has(optionMaxDatabaseFiles)) {
int maxDatabaseFiles = options.valueOf(optionMaxDatabaseFiles);

if (maxDatabaseFiles < 1) {
throw new Exception("Invalid value for --max-database-files="+maxDatabaseFiles+"; must be >= 1");
}

operationOptions.setMaxDatabaseFiles(maxDatabaseFiles);
}

// Parse 'status' options
operationOptions.setStatusOptions(parseStatusOptions(operationArgs));

Expand Down Expand Up @@ -140,4 +169,6 @@ private void printResults(CleanupOperationResult operationResult) {
throw new RuntimeException("Invalid result code: " + operationResult.getResultCode().toString());
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ private int runCommand(Command command, String commandName, String[] commandArgs
File portFile = null;

if (config != null) {
portFile = new File(config.getAppDir(), Config.FILE_PORT);
portFile = config.getPortFile();
}

boolean localDirHandledInDaemonScope = portFile != null && portFile.exists();
Expand Down
61 changes: 61 additions & 0 deletions syncany-cli/src/main/java/org/syncany/cli/util/CliUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Syncany, www.syncany.org
* Copyright (C) 2011-2014 Philipp C. Heckel <philipp.heckel@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.syncany.cli.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Various CLI-utilities.
*
* @author Pim Otte
*/
public class CliUtil {

/**
* Parses a string of type "1y2mo3w4d5h6m7s", where the units represent
* years, months, weeks, days, hours, minutes and second respectively.
*
* returns: the duration of the period represented by the string in seconds.
*/
public static long parseTimePeriod(String period) {
Pattern relativeDatePattern = Pattern.compile("(\\d+(?:[.,]\\d+)?)(mo|[smhdwy])");
Matcher relativeDateMatcher = relativeDatePattern.matcher(period);

relativeDateMatcher.reset();
long periodSeconds = 0;

while (relativeDateMatcher.find()) {
double time = Double.parseDouble(relativeDateMatcher.group(1));
String unitStr = relativeDateMatcher.group(2).toLowerCase();
int unitMultiplier = 0;

if (unitStr.startsWith("mo")) { unitMultiplier = 30*24*60*60; } // must be before "m"
else if (unitStr.startsWith("s")) { unitMultiplier = 1; }
else if (unitStr.startsWith("m")) { unitMultiplier = 60; }
else if (unitStr.startsWith("h")) { unitMultiplier = 60*60; }
else if (unitStr.startsWith("d")) { unitMultiplier = 24*60*60; }
else if (unitStr.startsWith("w")) { unitMultiplier = 7*24*60*60; }
else if (unitStr.startsWith("y")) { unitMultiplier = 365*24*60*60; }

periodSeconds += (long) ((double)time*unitMultiplier);
}

return periodSeconds;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ OPTIONS
shortened to <count> file versions. Metadata and file content of these old
versions will be deleted, and cannot be restored! This option only works if
-V is not set.

-t, --time-between-cleanups=<seconds>
Sets the minimal amount of time between two cleanups. If the last cleanup
from this client is less then <seconds> seconds ago, no database files
will be merged. Versions will still be removed.

-x, --max-database-files=<count>
Sets the number of database files per client. If the total number of
databases exceeds <count> times the number of clients, all database
files will be merged to one per client.

%RESOURCE:incl/footer.skel%


Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ public class WatchRunner implements WatchOperationListener {
private static final Logger logger = Logger.getLogger(WatchRunner.class.getSimpleName());

private Config config;
private File portFile;
private PortTO portTO;
private Thread watchThread;
private WatchOperation watchOperation;
Expand All @@ -97,7 +96,6 @@ public class WatchRunner implements WatchOperationListener {

public WatchRunner(Config config, WatchOperationOptions watchOperationOptions, PortTO portTO) throws ConfigException {
this.config = config;
this.portFile = new File(config.getAppDir(), Config.FILE_PORT);
this.portTO = portTO;
this.watchOperation = new WatchOperation(config, watchOperationOptions, this);

Expand All @@ -114,7 +112,7 @@ public void run() {
try {
logger.log(Level.INFO, "STARTING watch at" + config.getLocalDir());
watchOperationResult = null;

File portFile = config.getPortFile();
// Write port to portFile
portFile.createNewFile();
portFile.deleteOnExit();
Expand All @@ -137,7 +135,7 @@ public void run() {

public void stop() {
watchOperation.stop();
portFile.delete();
config.getPortFile().delete();

watchThread = null;
}
Expand Down
2 changes: 0 additions & 2 deletions syncany-lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ dependencies {
compile "org.simpleframework:simple-xml:2.7.1"
compile "com.google.guava:guava:15.0"
compile "commons-codec:commons-codec:1.8"
compile 'org.reflections:reflections:0.9.8'
compile "org.slf4j:slf4j-api:1.6.0" // for reflections
compile "org.hsqldb:hsqldb:2.3.1"
compile "com.github.zafarkhaja:java-semver:0.7.2"

Expand Down
38 changes: 32 additions & 6 deletions syncany-lib/src/main/java/org/syncany/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,18 @@ public class Config {
public static final String DIR_CACHE = "cache";
public static final String DIR_DATABASE = "db";
public static final String DIR_LOG = "logs";
public static final String DIR_STATE = "state";
// Files in .syncany
public static final String FILE_CONFIG = "config.xml";
public static final String FILE_REPO = "syncany";
public static final String FILE_MASTER = "master";
// File in client root
public static final String FILE_IGNORE = ".syignore";
// File in .syncany/db
public static final String FILE_DATABASE = "local.db";
public static final String FILE_PORT = "port";
// Files in .syncany/state
public static final String FILE_PORT = "port.xml";
public static final String FILE_CLEANUP = "cleanup.xml";

private byte[] repoId;
private String machineName;
Expand All @@ -70,6 +76,7 @@ public class Config {
private File cacheDir;
private File databaseDir;
private File logDir;
private File stateDir;

private SaltedSecretKey masterKey;

Expand All @@ -94,7 +101,7 @@ public Config(File aLocalDir, ConfigTO configTO, RepoTO repoTO) throws ConfigExc
initNames(configTO);
initMasterKey(configTO);
initDirectories(aLocalDir);
initCache();
initCache(configTO);
initIgnoredFile();
initRepo(repoTO);
initConnection(configTO);
Expand All @@ -115,10 +122,15 @@ private void initDirectories(File aLocalDir) throws ConfigException {
cacheDir = FileUtil.getCanonicalFile(new File(appDir, DIR_CACHE));
databaseDir = FileUtil.getCanonicalFile(new File(appDir, DIR_DATABASE));
logDir = FileUtil.getCanonicalFile(new File(appDir, DIR_LOG));
stateDir = FileUtil.getCanonicalFile(new File(appDir, DIR_STATE));
}

private void initCache() {
private void initCache(ConfigTO configTO) {
cache = new Cache(cacheDir);

if (configTO.getCacheKeepBytes() != null && configTO.getCacheKeepBytes() >= 0) {
cache.setKeepBytes(configTO.getCacheKeepBytes());
}
}

private void initIgnoredFile() throws ConfigException {
Expand Down Expand Up @@ -296,6 +308,14 @@ public File getLocalDir() {
public File getDatabaseDir() {
return databaseDir;
}

public File getLogDir() {
return logDir;
}

public File getStateDir() {
return stateDir;
}

public SaltedSecretKey getMasterKey() {
return masterKey;
Expand All @@ -304,8 +324,14 @@ public SaltedSecretKey getMasterKey() {
public File getDatabaseFile() {
return new File(databaseDir, FILE_DATABASE);
}

public File getLogDir() {
return logDir;
public File getPortFile() {
return new File(stateDir, FILE_PORT);
}

public File getCleanupFile() {
return new File(stateDir, FILE_CLEANUP);
}


}
5 changes: 1 addition & 4 deletions syncany-lib/src/main/java/org/syncany/config/Logging.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
import java.util.logging.LogManager;
import java.util.logging.Logger;

import org.reflections.Reflections;

/**
* The logging class offers convenience functions to initialize and update the
* application's log options.
Expand Down Expand Up @@ -55,7 +53,7 @@ public synchronized static void init() {
return;
}

// Turn off INFO message of Reflections library (dirty, but the only way!)
// Turn off unwanted loggers (evil libraries and such)
disableUnwantedLoggers();

// Load logging.properties
Expand All @@ -78,7 +76,6 @@ public synchronized static void init() {
}

private static void disableUnwantedLoggers() {
Reflections.log = null;
System.setProperty("hsqldb.reconfig_logging", "false");

if (Logger.getLogger("sun.awt.X11.timeoutTask.XToolkit") != null) {
Expand Down
42 changes: 42 additions & 0 deletions syncany-lib/src/main/java/org/syncany/config/to/CleanupTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Syncany, www.syncany.org
* Copyright (C) 2011-2014 Philipp C. Heckel <philipp.heckel@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.syncany.config.to;

import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;

/**
* CleanupTO represents an xml file containing a single long value:
* the timestamp of the moment at which a cleanup was last performed
* by the relevant client.
*
* @author Pim Otte
*/
@Root(name="cleanup", strict=false)
public class CleanupTO {
@Element(name="lastTimeCleaned", required = false)
private long lastTimeCleaned = 0;

public long getLastTimeCleaned() {
return lastTimeCleaned;
}

public void setLastTimeCleaned(long lastTimeCleanup) {
this.lastTimeCleaned = lastTimeCleanup;
}
}

0 comments on commit de47aa8

Please sign in to comment.