📄 fileexpirationservice.java
字号:
log (SCHEDULE, file, timeInMyCache, timeoutForOthers);
mods++;
}
return;
}
// There is such a file already. It gets tricky.
// If we already have it with a longer life time, do not change
// anything at all.
if (entry.timeInMyCache > timeInMyCache) return;
// If nothing is changed at all do not bother messing with it.
if (entry.timeInMyCache == timeInMyCache &&
entry.timeoutForOthers == timeoutForOthers) return;
// For now do not put restrictions on expiration time.
hash.remove (file.getAbsolutePath ());
// We have to cancel and that cannot be done under synch. So
// drop the lock and cancel. Then try again the whole deal.
// Do that until we get the right of way.
}
// NB: cancelling an action that has already been carried out
// and removed from the scheduler does not hurt.
ss.cancelAction (entry.myPendingAction);
}
}
// There's no garantee that a new expiration does not get scheduled
// right after we cancel, though.
public void cancelFileExpiration (File file) {
Entry e = null;
synchronized (this) {
e = (Entry) hash.get (file.getAbsolutePath ());
if (e == null) return;
hash.remove (file.getAbsolutePath ());
log (CANCEL, file, 0, 0);
mods++;
}
// NB: cancelling an action that has already been carried out
// and removed from the scheduler does not hurt.
ss.cancelAction (e.myPendingAction);
}
void log (int action, File file, long timeInMyCache, long timeoutForOthers)
{
try {
logWrite (action, file, timeInMyCache, timeoutForOthers);
} catch (IOException e) {
try {
compress ();
logWrite (action, file, timeInMyCache, timeoutForOthers);
} catch (IOException e2) {
// what can we do but log it?
// while the code is running, we'll keep
// the expiration tables in memory.
if (LOG.isEnabledFor(Priority.WARN)) LOG.warn ("Cannot write to " + db + ", keeping expiration tables in memory.");
}
}
}
void logWrite (int action,
File file,
long timeInMyCache,
long timeForOthers)
throws IOException
{
out.writeInt (action);
out.writeUTF (file.getAbsolutePath ().toString ());
out.writeLong (timeInMyCache);
out.writeLong (timeForOthers);
out.getFD ().sync ();
}
// This is never executed in parallel, so it does not need to synch
// what only compress touches (db, tmpDb).
private void compress () throws IOException {
DataInputStream in = null;
long start = System.currentTimeMillis ();
// if the output stream is open, close it
if (out != null) {
try {
out.close ();
} catch (IOException e) {
}
}
if (tmpDb.exists ())
tmpDb.delete ();
// open an input stream to read existing log
// open an output stream to a temporary file
// compress input stream into output stream
try {
in = new DataInputStream(new BufferedInputStream(new FileInputStream (db)));
out = new RandomAccessFile (tmpDb, "rw");
compressStreams (in);
} finally {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug ("Compressed " + db + " in " + (System.currentTimeMillis () - start) + " ms.");
// make sure we close all streams
if (in != null)
try {
in.close ();
} catch (IOException e) {
}
if (out != null)
try {
out.close ();
} catch (IOException e) {
}
if (tmpDb.exists ()) {
if (db.exists ()) // an existing file will prevent rename on win2k!
db.delete ();
tmpDb.renameTo (db); // if we deleted but rename failed, oh well
}
out = new RandomAccessFile (db, "rw");
out.seek (out.length ());
}
removeUnknownFiles ();
mods = 0;
}
void compressStreams (DataInputStream in) throws IOException {
int action;
File file;
long timeInMyCache;
long timeoutForOthers;
int i = 0;
try {
while (true) {
action = in.readInt ();
file = new File (in.readUTF ());
timeInMyCache = in.readLong ();
timeoutForOthers = in.readLong ();
if (file.exists ()) {
switch (action) {
case SCHEDULE:
if (timeInMyCache > System.currentTimeMillis ())
scheduleFileExpiration (file,
timeInMyCache,
timeoutForOthers);
break;
case CANCEL:
cancelFileExpiration (file);
break;
}
}
i++;
}
} catch (EOFException e) {
// ugh, this is bad code, but should work all the time
}
}
void removeUnknownFiles () {
Enumeration e = docDirs.elements ();
while (e.hasMoreElements ()) {
File dir = (File) e.nextElement ();
removeUnknownFiles (dir);
}
}
void removeUnknownFiles (File dir) {
File f;
String[] list = dir.list ();
for (int i = 0; list != null && i < list.length; i++) {
f = new File (dir, list[i]);
if (! f.isDirectory () &&
hash.get (f.getAbsolutePath ()) == null && // we don't know anything
f.getName ().indexOf ("scheduler.db") == -1) { // not our db file
try {
if (listener != null) listener.expiredAndRemove (f);
} catch (Throwable t) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug ("Throwable caught while dispatching expiration listener.", t);
} finally {
f.delete();
}
}
}
}
public static void main (String[] argv) throws IOException {
SchedulerService ss = new SchedulerService ();
FileExpirationService fes;
File dir = new File (argv[0]);
Thread t = new Thread (ss);
t.start ();
fes = new FileExpirationService (ss, dir, null, null);
fes.addDocDir (new File ("testdir/"));
long time = System.currentTimeMillis () + 30 * 1000;
fes.scheduleFileExpiration (new File ("testdir/test1"), time, time);
fes.scheduleFileExpiration (new File ("testdir/test2"), time, time);
fes.scheduleFileExpiration (new File ("testdir/test3"), time, time);
fes.cancelFileExpiration (new File ("testdir/test2"));
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -