Switch to using a file lock on gettingdown.lock in the app's dir to keep multiple instances of getdown from running at the same time instead of monitoring getdown.txt's modtime. The modtime is still used to see if another getdown ran while this one waited.
This commit is contained in:
@@ -22,15 +22,6 @@ package com.threerings.getdown.data;
|
|||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
|
|
||||||
import javax.swing.JApplet;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.security.AllPermission;
|
|
||||||
import java.security.CodeSource;
|
|
||||||
import java.security.PermissionCollection;
|
|
||||||
import java.security.Permissions;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@@ -40,14 +31,20 @@ import java.io.FileReader;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.channels.FileLock;
|
||||||
|
import java.security.AllPermission;
|
||||||
|
import java.security.CodeSource;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.PermissionCollection;
|
||||||
|
import java.security.Permissions;
|
||||||
import java.security.Signature;
|
import java.security.Signature;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@@ -56,16 +53,16 @@ import java.util.Map;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import com.samskivert.io.StreamUtil;
|
import javax.swing.JApplet;
|
||||||
import com.samskivert.jdbc.depot.clause.UpdateClause;
|
|
||||||
import com.samskivert.text.MessageUtil;
|
|
||||||
import com.samskivert.util.ArrayIntSet;
|
|
||||||
import com.samskivert.util.RunAnywhere;
|
|
||||||
import com.samskivert.util.StringUtil;
|
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
import org.apache.commons.codec.binary.Base64;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
import com.samskivert.io.StreamUtil;
|
||||||
|
import com.samskivert.text.MessageUtil;
|
||||||
|
import com.samskivert.util.ArrayIntSet;
|
||||||
|
import com.samskivert.util.RunAnywhere;
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
import com.threerings.getdown.Log;
|
import com.threerings.getdown.Log;
|
||||||
import com.threerings.getdown.launcher.MultipleGetdownRunning;
|
import com.threerings.getdown.launcher.MultipleGetdownRunning;
|
||||||
import com.threerings.getdown.launcher.RotatingBackgrounds;
|
import com.threerings.getdown.launcher.RotatingBackgrounds;
|
||||||
@@ -1027,49 +1024,53 @@ public class Application
|
|||||||
protected void downloadConfigFile ()
|
protected void downloadConfigFile ()
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
requireNoOtherGetdownRunning();
|
|
||||||
downloadControlFile(CONFIG_FILE, false);
|
downloadControlFile(CONFIG_FILE, false);
|
||||||
updateConfigModtime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks the modtime on CONFIG_FILE and returns whether it has changed since the last time
|
* @return true if gettingdown.lock was locked or was already locked by this application.
|
||||||
* this method was called.
|
|
||||||
*/
|
*/
|
||||||
public boolean checkForAnotherGetdown ()
|
public synchronized boolean lockForUpdates ()
|
||||||
{
|
{
|
||||||
File config = getLocalPath(CONFIG_FILE);
|
if (_lock != null && _lock.isValid()) {
|
||||||
if (_lastConfigModtime != -1 && _lastConfigModtime < config.lastModified()) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
_lastConfigModtime = config.lastModified();
|
try {
|
||||||
return false;
|
_lockChannel = new RandomAccessFile(getLocalPath("gettingdown.lock"), "rw").getChannel();
|
||||||
}
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.warning("Unable to create lock file[message=" + e.getMessage() + "]");
|
||||||
/**
|
Log.logStackTrace(e);
|
||||||
* Calls {@link #checkForAnotherGetdown} and throws a {@link MultipleGetdownRunning} if it
|
return false;
|
||||||
* detects that another Getdown instance is running.
|
|
||||||
*/
|
|
||||||
public void requireNoOtherGetdownRunning ()
|
|
||||||
throws MultipleGetdownRunning
|
|
||||||
{
|
|
||||||
if (checkForAnotherGetdown()) {
|
|
||||||
throw new MultipleGetdownRunning();
|
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
_lock = _lockChannel.tryLock();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.warning("Unable to create lock[message=" + e.getMessage() + "]");
|
||||||
|
Log.logStackTrace(e);
|
||||||
|
}
|
||||||
|
return _lock != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the modtime on CONFIG_FILE to now and notes that this application saw it at that
|
* Release gettingdown.lock
|
||||||
* time for use in checkForAnotherGetdown
|
|
||||||
*/
|
*/
|
||||||
public void updateConfigModtime ()
|
public synchronized void releaseLock ()
|
||||||
{
|
{
|
||||||
File config = getLocalPath(CONFIG_FILE);
|
if (_lock != null) {
|
||||||
_lastConfigModtime = System.currentTimeMillis();
|
try {
|
||||||
if (!config.setLastModified(_lastConfigModtime) && !_warnedAboutSetLastModified) {
|
_lock.release();
|
||||||
Log.warning("Unable to set modtime on config file, will be unable to check for " +
|
} catch (IOException e) {
|
||||||
"other instances of getdown running.");
|
Log.warning("Unable to release lock[message=" + e.getMessage() + "]");
|
||||||
_warnedAboutSetLastModified = true;
|
Log.logStackTrace(e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
_lockChannel.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.warning("Unable to close lock channel[message=" + e.getMessage() + "]");
|
||||||
|
Log.logStackTrace(e);
|
||||||
|
}
|
||||||
|
_lockChannel = null;
|
||||||
|
_lock = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1162,11 +1163,6 @@ public class Application
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that another getdown hasn't started running since we started downloading this
|
|
||||||
// file. The rename will obliterate the modtime we're tracking to keep multiple instances
|
|
||||||
// from running.
|
|
||||||
requireNoOtherGetdownRunning();
|
|
||||||
|
|
||||||
// now move the temporary file over the original
|
// now move the temporary file over the original
|
||||||
File original = getLocalPath(path);
|
File original = getLocalPath(path);
|
||||||
if (!FileUtil.renameTo(target, original)) {
|
if (!FileUtil.renameTo(target, original)) {
|
||||||
@@ -1309,8 +1305,11 @@ public class Application
|
|||||||
/** If a warning has been issued about not being able to set modtimes. */
|
/** If a warning has been issued about not being able to set modtimes. */
|
||||||
protected boolean _warnedAboutSetLastModified;
|
protected boolean _warnedAboutSetLastModified;
|
||||||
|
|
||||||
/** The modtime on CONFIG_FILE last time it was checked, or -1 if it hasn't been checked. */
|
|
||||||
protected long _lastConfigModtime = -1;
|
|
||||||
|
|
||||||
protected static final String[] SA_PROTO = new String[0];
|
protected static final String[] SA_PROTO = new String[0];
|
||||||
|
|
||||||
|
/** Locks gettingdown.lock in the app dir. Held the entire time updating is going on.*/
|
||||||
|
protected FileLock _lock;
|
||||||
|
|
||||||
|
/** Channel to the file underying _lock. Kept around solely so the lock doesn't close. */
|
||||||
|
protected FileChannel _lockChannel;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -362,17 +362,32 @@ public abstract class Getdown extends Thread
|
|||||||
// now force our UI to be recreated with the updated info
|
// now force our UI to be recreated with the updated info
|
||||||
createInterface(true);
|
createInterface(true);
|
||||||
}
|
}
|
||||||
_app.requireNoOtherGetdownRunning();
|
if (!_app.lockForUpdates()) {
|
||||||
// Update the modtime here to stake a claim that we're going to getdown eventually
|
throw new MultipleGetdownRunning();
|
||||||
_app.updateConfigModtime();
|
}
|
||||||
|
|
||||||
|
// Update the config modtime so a sleeping getdown will notice the change.
|
||||||
|
File config = _app.getLocalPath(Application.CONFIG_FILE);
|
||||||
|
if (!config.setLastModified(System.currentTimeMillis())) {
|
||||||
|
Log.warning("Unable to set modtime on config file, will be unable to check for "
|
||||||
|
+ "another instance of getdown running while this one waits.");
|
||||||
|
}
|
||||||
if (_delay > 0) {
|
if (_delay > 0) {
|
||||||
|
// don't hold the lock while waiting, let another getdown proceed if it starts.
|
||||||
|
_app.releaseLock();
|
||||||
|
// Store the config modtime before waiting the delay amount of time
|
||||||
|
long lastConfigModtime = config.lastModified();
|
||||||
try {
|
try {
|
||||||
Log.info("Waiting " + _delay + " minutes before beginning actual work");
|
Log.info("Waiting " + _delay + " minutes before beginning actual work");
|
||||||
Thread.sleep(_delay * 60 * 1000);
|
Thread.sleep(_delay * 15 * 1000);
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
Log.warning("Who dares disturb my slumber?");
|
Log.warning("Who dares disturb my slumber?");
|
||||||
Log.logStackTrace(ie);
|
Log.logStackTrace(ie);
|
||||||
}
|
}
|
||||||
|
if (lastConfigModtime < config.lastModified()) {
|
||||||
|
Log.warning("getdown.txt was modified while getdown was waiting");
|
||||||
|
throw new MultipleGetdownRunning();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we create this tracking counter here so that we properly note the first time through
|
// we create this tracking counter here so that we properly note the first time through
|
||||||
@@ -416,7 +431,9 @@ public abstract class Getdown extends Thread
|
|||||||
// Only launch if we aren't in silent mode. Some mystery program starting out
|
// Only launch if we aren't in silent mode. Some mystery program starting out
|
||||||
// of the blue would be disconcerting.
|
// of the blue would be disconcerting.
|
||||||
if (!_silent || _launchInSilent) {
|
if (!_silent || _launchInSilent) {
|
||||||
_app.requireNoOtherGetdownRunning();
|
// One last check for the lock before launching. It'll already be held
|
||||||
|
// unless we're in silent mode.
|
||||||
|
_app.lockForUpdates();
|
||||||
launch();
|
launch();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -634,8 +651,11 @@ public abstract class Getdown extends Thread
|
|||||||
public boolean downloadProgress (int percent, long remaining) {
|
public boolean downloadProgress (int percent, long remaining) {
|
||||||
// check for another getdown running at 0 and every 10% after that
|
// check for another getdown running at 0 and every 10% after that
|
||||||
if (_lastCheck == -1 || percent >= _lastCheck + 10) {
|
if (_lastCheck == -1 || percent >= _lastCheck + 10) {
|
||||||
if (_app.checkForAnotherGetdown()) {
|
if (_delay > 0){
|
||||||
return false;
|
// Stop the presses if something else is holding the lock.
|
||||||
|
boolean locked = _app.lockForUpdates();
|
||||||
|
_app.releaseLock();
|
||||||
|
return locked;
|
||||||
}
|
}
|
||||||
_lastCheck = percent;
|
_lastCheck = percent;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ public class JarDiffPatcher
|
|||||||
for (int j = 0; j < keys.length; j++) {
|
for (int j = 0; j < keys.length; j++) {
|
||||||
// Apply move <oldName> <newName> command
|
// Apply move <oldName> <newName> command
|
||||||
String newName = (String)keys[j];
|
String newName = (String)keys[j];
|
||||||
String oldName = (String)renameMap.get(newName);
|
String oldName = renameMap.get(newName);
|
||||||
|
|
||||||
// Get source JarEntry
|
// Get source JarEntry
|
||||||
JarEntry oldEntry = oldJar.getJarEntry(oldName);
|
JarEntry oldEntry = oldJar.getJarEntry(oldName);
|
||||||
|
|||||||
Reference in New Issue
Block a user