/* * Copyright (c) 2002-2009 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Neo4j is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.neo4j.kernel.impl.nioneo.store; import java.nio.channels.FileChannel; import java.util.LinkedList; import org.neo4j.kernel.impl.transaction.LockException; /** * Makes a {@link PersistenceWindow} "lockable" meaning it can be locked by a * thread during a operation making sure no other thread use the same window * concurrently. */ abstract class LockableWindow implements PersistenceWindow { public abstract Buffer getBuffer(); public abstract long position(); public abstract int size(); public abstract void force(); public abstract void close(); private OperationType type = null; private final FileChannel fileChannel; private Thread lockingThread = null; private final LinkedList<Thread> waitingThreadList = new LinkedList<Thread>(); private int lockCount = 0; private int marked = 0; LockableWindow( FileChannel fileChannel ) { this.fileChannel = fileChannel; } boolean encapsulates( long position ) { return position() <= position && position < position() + size(); } FileChannel getFileChannel() { return fileChannel; } OperationType getOperationType() { return type; } void setOperationType( OperationType type ) { this.type = type; } synchronized void mark() { this.marked++; } synchronized boolean isMarked() { return marked > 0; } synchronized void lock() { Thread currentThread = Thread.currentThread(); while ( lockCount > 0 && lockingThread != currentThread ) { waitingThreadList.addFirst( currentThread ); try { wait(); } catch ( InterruptedException e ) { Thread.interrupted(); } } lockCount++; lockingThread = currentThread; marked--; } synchronized void unLock() { Thread currentThread = Thread.currentThread(); if ( lockCount == 0 ) { throw new LockException( "" + currentThread + " don't have window lock on " + this ); } lockCount--; if ( lockCount == 0 ) { lockingThread = null; if ( waitingThreadList.size() > 0 ) { waitingThreadList.removeLast().interrupt(); } } } synchronized int getWaitingThreadsCount() { return waitingThreadList.size(); } }