📄 fileexpirationservice.java
字号:
/*
* Copyright (c) 2001 Sun Microsystems, Inc. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Sun Microsystems, Inc. for Project JXTA."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA"
* must not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact Project JXTA at http://www.jxta.org.
*
* 5. Products derived from this software may not be called "JXTA",
* nor may "JXTA" appear in their name, without prior written
* permission of Sun.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of Project JXTA. For more
* information on Project JXTA, please see
* <http://www.jxta.org/>.
*
* This license is based on the BSD license adopted by the Apache Foundation.
*
* $Id: FileExpirationService.java,v 1.2 2002/03/04 21:38:14 echtcherbina Exp $
*/
package net.jxta.impl.cm;
import java.io.*;
import java.util.*;
import org.apache.log4j.Category; import org.apache.log4j.Priority;
class FileExpirationService {
File dir;
File db;
File tmpDb;
Vector docDirs;
SchedulerService ss;
RandomAccessFile out;
Hashtable hash;
int mods;
SchedulerService.PendingAction pendingCompressAction;
ExpirationListener listener;
static final int SCHEDULE = 1;
static final int CANCEL = 2;
static final long COMPRESS_INTERVAL = 1000 * 60 * 30;
static final int MOD_THRESHOLD = 128;
static final Category LOG =
Category.getInstance(FileExpirationService.class.getName());
interface ExpirationListener {
public void expiredAndRemove (File file);
}
class Entry {
File file;
SchedulerService.PendingAction myPendingAction;
long timeInMyCache;
long timeoutForOthers;
Entry (File file,
long timeInMyCache,
long timeoutForOthers)
{
this.file = file;
this.timeInMyCache = timeInMyCache;
this.timeoutForOthers = timeoutForOthers;
}
}
/**
* @param dir - The directory used for storing persistent scheduler data.
* @param docDirs - The directories where documents will actually be
* stored. In those directories we will delete the files which are
* not scheduled to be expired. We do this in case the scheduler
* data becomes corrupt, so that when new scheduler data is written,
* the old files expire anyway.
*/
FileExpirationService (SchedulerService ss,
File dir,
File[] docDirs,
ExpirationListener listener)
throws IOException
{
db = new File (dir, "scheduler.db");
tmpDb = new File (dir, ".tmp.scheduler.db");
if (! dir.exists ())
dir.mkdirs ();
this.ss = ss;
this.dir = dir;
this.listener = listener;
this.docDirs = new Vector ();
this.hash = new Hashtable ();
if (db.exists ()) {
compress ();
} else {
out = new RandomAccessFile (db, "rw");
}
pendingCompressAction =
ss.scheduleAction (new CleanupAction (), COMPRESS_INTERVAL);
for (int i = 0; docDirs != null && i < docDirs.length; i++)
addDocDir (dir);
}
void addDocDir (File dir) {
docDirs.addElement (dir);
}
void stop () {
ss.cancelAction (pendingCompressAction);
try {
if (db.exists ())
compress ();
out.close ();
} catch (IOException e) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug ("Compression of log stream failed on stop()", e);
}
}
class CleanupAction implements SchedulerService.Action {
public void perform (SchedulerService ss) {
try{
if (db.exists ())
compress ();
} catch (IOException e) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug ("Compression of log stream failed.", e);
}
// still re-schedule, because the administrator may
// see the log messages and do something that will
// make the compress action succeed later. or something.
pendingCompressAction =
ss.scheduleAction (this, COMPRESS_INTERVAL);
}
}
class ExpireAction implements SchedulerService.Action {
Entry entry;
ExpireAction (Entry entry) {
this.entry = entry;
}
public void perform (SchedulerService ss) {
// Do not synchronize for the listener, it never changes after
// construction.
// But do synchronize for hash.remove. Other methods rely
// on the hashtable not changing while they're synchronized.
try {
if (listener != null) listener.expiredAndRemove (entry.file);
} catch (Throwable t) {
if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug ("Throwable caught while dispatching expiration " + "listener.", t);
} finally {
synchronized(FileExpirationService.this) {
entry.file.delete ();
hash.remove (entry.file.getAbsolutePath ());
}
}
}
}
public synchronized long getExpirationTime (File f) {
Entry entry = (Entry) hash.get (f.getAbsolutePath ());
if (entry == null)
return -1;
else
return Math.min(entry.timeInMyCache,
entry.timeoutForOthers+System.currentTimeMillis());
}
public void scheduleFileExpiration (File file,
long timeInMyCache,
long timeoutForOthers)
throws IOException
{
while (true) {
// We must do a collision mechanism here. We must release
// the synchro top cancel, but we must keep it once we've
// managed to get rid of it. Everytime we release the synchro
// the situation may change and we may have to cancel again
// or discover that the file re-appeared with a longer life-time.
Entry entry = null;
synchronized(this) {
entry = (Entry) hash.get (file.getAbsolutePath ());
if (entry == null) {
// Bingo we can proceed.
long myTimeout = timeInMyCache - System.currentTimeMillis ();
ExpireAction action1;
entry = new Entry (file, timeInMyCache, timeoutForOthers);
action1 = new ExpireAction (entry);
entry.myPendingAction = ss.scheduleAction (action1,
myTimeout);
if (entry.myPendingAction != null) {
hash.put (file.getAbsolutePath (), entry);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -