001: /*
002: * Copyright 2004-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.lucene.store.jdbc.lock;
018:
019: import java.io.IOException;
020: import java.sql.PreparedStatement;
021: import java.sql.Types;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025: import org.apache.lucene.store.Lock;
026: import org.apache.lucene.store.jdbc.JdbcDirectory;
027: import org.apache.lucene.store.jdbc.support.JdbcTemplate;
028:
029: /**
030: * <p>A lock based on phantom reads and table level locking. For most database and most transaction
031: * isolation levels this lock is suffecient.
032: *
033: * <p>The existance of the lock in the database, marks it as being locked.
034: *
035: * <p>The benefits of using this lock is the ability to release it.
036: *
037: * @author kimchy
038: */
039: public class PhantomReadLock extends Lock implements JdbcLock {
040:
041: private static final Log log = LogFactory
042: .getLog(PhantomReadLock.class);
043:
044: private JdbcDirectory jdbcDirectory;
045:
046: private String name;
047:
048: public void configure(JdbcDirectory jdbcDirectory, String name)
049: throws IOException {
050: this .jdbcDirectory = jdbcDirectory;
051: this .name = name;
052: }
053:
054: public void initializeDatabase(JdbcDirectory jdbcDirectory) {
055: // do nothing
056: }
057:
058: public boolean obtain() {
059: try {
060: if (jdbcDirectory.getDialect().useExistsBeforeInsertLock()) {
061: // there are databases where the fact that an exception was thrown
062: // invalidates the connection. So first we check if it exists, and
063: // then insert it.
064: if (jdbcDirectory.fileExists(name)) {
065: return false;
066: }
067: }
068: jdbcDirectory.getJdbcTemplate().executeUpdate(
069: jdbcDirectory.getTable().sqlInsert(),
070: new JdbcTemplate.PrepateStatementAwareCallback() {
071: public void fillPrepareStatement(
072: PreparedStatement ps) throws Exception {
073: ps.setFetchSize(1);
074: ps.setString(1, name);
075: ps.setNull(2, Types.BLOB);
076: ps.setLong(3, 0);
077: ps.setBoolean(4, false);
078: }
079: });
080: } catch (Exception e) {
081: if (log.isTraceEnabled()) {
082: log.trace("Obtain Lock exception (might be valid) ["
083: + e.getMessage() + "]");
084: }
085: return false;
086: }
087: return true;
088: }
089:
090: public void release() {
091: try {
092: jdbcDirectory.getJdbcTemplate().executeUpdate(
093: jdbcDirectory.getTable().sqlDeleteByName(),
094: new JdbcTemplate.PrepateStatementAwareCallback() {
095: public void fillPrepareStatement(
096: PreparedStatement ps) throws Exception {
097: ps.setFetchSize(1);
098: ps.setString(1, name);
099: }
100: });
101: } catch (Exception e) {
102: if (log.isTraceEnabled()) {
103: log.trace("Release Lock exception (might be valid) ["
104: + e.getMessage() + "]");
105: }
106: }
107: }
108:
109: public boolean isLocked() {
110: try {
111: return jdbcDirectory.fileExists(name);
112: } catch (Exception e) {
113: return false;
114: }
115: }
116:
117: public String toString() {
118: return "PhantomReadLock[" + name + "/"
119: + jdbcDirectory.getTable() + "]";
120: }
121: }
|