/* * Copyright 2004-2009 the original author or authors. * * 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.compass.needle.terracotta; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.ReadWriteLock; import org.apache.lucene.store.Lock; /** * Managed terracotta directory allows to use the terracotta directory by managing a more coarse * grained transactions and operations against the directory. This should provide an improved * performance with terracotta since there is no need to obtain locks on a fine grained level * (CHM) within a transactional context. * * <p>The directory accepts a RWL, which should be managed by terracotta. In order to begin a * transaction, the RWL read lock should be obtained. Releasing the transaction should be performed * by unlocking the read lock. * * @author kimchy */ public class ManagedTerracottaDirectory extends TerracottaDirectory { private final ReadWriteLock rwl; public ManagedTerracottaDirectory(ReadWriteLock rwl) { super(); this.rwl = rwl; } public ManagedTerracottaDirectory(ReadWriteLock rwl, int bufferSize, int flushRate) { super(bufferSize, flushRate); this.rwl = rwl; } public ManagedTerracottaDirectory(ReadWriteLock rwl, int bufferSize, int flushRate, int chmInitialCapacity, float chmLoadFactor, int chmConcurrencyLevel) { super(bufferSize, flushRate, chmInitialCapacity, chmLoadFactor, chmConcurrencyLevel); this.rwl = rwl; } @Override protected Map<String, TerracottaFile> createMap(int chmInitialCapacity, float chmLoadFactor, int chmConcurrencyLevel) { return new HashMap<String, TerracottaFile>(chmInitialCapacity, chmLoadFactor); } @Override public Lock makeLock(String name) { return new ManagedTerracottaLockAdapter(rwl, super.makeLock(name)); } @Override public void deleteFile(final String name) throws IOException { doWithWriteLock(new WriteLockTask<Object>() { public Object execute() throws IOException { ManagedTerracottaDirectory.super.deleteFile(name); return null; } }); } @Override public void renameFile(final String from, final String to) throws IOException { doWithWriteLock(new WriteLockTask<Object>() { public Object execute() throws IOException { ManagedTerracottaDirectory.super.renameFile(from, to); return null; } }); } @Override void addFile(final String name, final TerracottaFile file) throws IOException { doWithWriteLock(new WriteLockTask<Object>() { public Object execute() throws IOException { ManagedTerracottaDirectory.super.addFile(name, file); return null; } }); } protected <T> T doWithWriteLock(WriteLockTask<T> task) throws IOException { boolean unlocked; try { rwl.readLock().unlock(); unlocked = true; } catch (IllegalMonitorStateException e) { unlocked = false; } rwl.writeLock().lock(); try { return task.execute(); } finally { if (unlocked) { rwl.readLock().lock(); } rwl.writeLock().unlock(); } } private static interface WriteLockTask<T> { T execute() throws IOException; } }