/*
* Copyright 2008 Niclas Hedhman.
*
* 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 org.qi4j.entitystore.swift;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import org.qi4j.spi.entitystore.EntityStoreException;
public class BucketManager
implements Runnable
{
private HashMap<Integer, LruEntry> cache;
private File bucketdir;
private Thread cleanUpThread;
private boolean running;
public BucketManager( File bucketdir )
{
cache = new HashMap<Integer, LruEntry>();
this.bucketdir = bucketdir;
bucketdir.mkdirs();
cleanUpThread = new Thread( this, "SwiftEntityStore-cleanup" );
cleanUpThread.start();
}
synchronized RandomAccessFile get( int hash )
throws IOException
{
LruEntry entry = cache.get( hash );
if( entry != null )
{
return entry.file;
}
File bucketFile = new File( bucketdir, Integer.toHexString( hash ) );
RandomAccessFile bucket = new RandomAccessFile( bucketFile, "rw" );
entry = new LruEntry( bucket, hash );
cache.put( hash, entry );
return bucket;
}
synchronized void close()
throws IOException
{
running = false;
cleanUpThread.interrupt();
for( LruEntry entry : cache.values() )
{
entry.file.close();
}
}
private void cleanUp()
throws IOException
{
if( cache.size() < 30 )
{
return;
}
LinkedList<LruEntry> sorting = new LinkedList<LruEntry>();
sorting.addAll( cache.values() );
Collections.sort( sorting, new Comparator<LruEntry>()
{
public int compare( LruEntry lruEntry1, LruEntry lruEntry2 )
{
if( lruEntry1.created == lruEntry2.created )
{
return 0;
}
if( lruEntry1.created > lruEntry2.created )
{
return 1;
}
return -1;
}
} );
while( cache.size() > 20 )
{
LruEntry entry = sorting.removeFirst(); // Check if this is at the right end;
entry.file.close();
cache.remove( entry.hash );
}
}
public void run()
{
running = true;
try
{
while( running )
{
synchronized( this )
{
wait( 15000 );
cleanUp();
}
}
}
catch( InterruptedException e )
{
// ignore, normal shutdown
}
catch( IOException e )
{
throw new EntityStoreException( "What the hell!!!???", e );
}
}
private static class LruEntry
{
private long created;
private RandomAccessFile file;
private int hash;
public LruEntry( RandomAccessFile bucket, int hash )
{
this.file = bucket;
this.hash = hash;
created = System.currentTimeMillis();
}
}
}