/* * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, * Version 1.0, and under the Eclipse Public License, Version 1.0 * (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ package org.h2.test.unit; import java.io.File; import java.sql.Connection; import org.h2.constant.ErrorCode; import org.h2.engine.Constants; import org.h2.message.TraceSystem; import org.h2.store.FileLock; import org.h2.test.TestBase; /** * Tests the database file locking facility. * Both lock files and sockets locking is tested. */ public class TestFileLock extends TestBase implements Runnable { private static volatile int locks; private static volatile boolean stop; private TestBase base; private int wait; private boolean allowSockets; public TestFileLock() { // nothing to do } TestFileLock(TestBase base, boolean allowSockets) { this.base = base; this.allowSockets = allowSockets; } private String getFile() { return getBaseDir() + "/test.lock"; } /** * Run just this test. * * @param a ignored */ public static void main(String... a) throws Exception { TestBase.createCaller().init().test(); } public void test() throws Exception { if (!getFile().startsWith(TestBase.BASE_TEST_DIR)) { return; } testFsFileLock(); testFutureModificationDate(); testSimple(); test(false); test(true); } private void testFsFileLock() throws Exception { deleteDb("fileLock"); String url = "jdbc:h2:" + getBaseDir() + "/fileLock;FILE_LOCK=FS;OPEN_NEW=TRUE"; Connection conn = getConnection(url); assertThrows(ErrorCode.DATABASE_ALREADY_OPEN_1, this). getConnection(url); conn.close(); } private void testFutureModificationDate() throws Exception { File f = new File(getFile()); f.delete(); f.createNewFile(); f.setLastModified(System.currentTimeMillis() + 10000); FileLock lock = new FileLock(new TraceSystem(null), getFile(), Constants.LOCK_SLEEP); lock.lock(FileLock.LOCK_FILE); lock.unlock(); } private void testSimple() { FileLock lock1 = new FileLock(new TraceSystem(null), getFile(), Constants.LOCK_SLEEP); FileLock lock2 = new FileLock(new TraceSystem(null), getFile(), Constants.LOCK_SLEEP); lock1.lock(FileLock.LOCK_FILE); createClassProxy(FileLock.class); assertThrows(ErrorCode.DATABASE_ALREADY_OPEN_1, lock2). lock(FileLock.LOCK_FILE); lock1.unlock(); lock2 = new FileLock(new TraceSystem(null), getFile(), Constants.LOCK_SLEEP); lock2.lock(FileLock.LOCK_FILE); lock2.unlock(); } private void test(boolean allowSocketsLock) throws Exception { int threadCount = getSize(3, 5); wait = getSize(20, 200); Thread[] threads = new Thread[threadCount]; new File(getFile()).delete(); for (int i = 0; i < threadCount; i++) { threads[i] = new Thread(new TestFileLock(this, allowSocketsLock)); threads[i].start(); Thread.sleep(wait + (int) (Math.random() * wait)); } trace("wait"); Thread.sleep(500); stop = true; trace("STOP file"); for (int i = 0; i < threadCount; i++) { threads[i].join(); } assertEquals(0, locks); } public void run() { FileLock lock = null; while (!stop) { lock = new FileLock(new TraceSystem(null), getFile(), 100); try { lock.lock(allowSockets ? FileLock.LOCK_SOCKET : FileLock.LOCK_FILE); base.trace(lock + " locked"); locks++; if (locks > 1) { System.err.println("ERROR! LOCKS=" + locks + " sockets=" + allowSockets); stop = true; } Thread.sleep(wait + (int) (Math.random() * wait)); locks--; base.trace(lock + " unlock"); lock.unlock(); if (locks < 0) { System.err.println("ERROR! LOCKS=" + locks); stop = true; } } catch (Exception e) { // log(id+" cannot lock: " + e); } try { Thread.sleep(wait + (int) (Math.random() * wait)); } catch (InterruptedException e1) { // ignore } } if (lock != null) { lock.unlock(); } } }