001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.internal.fileheader;
022:
023: import com.db4o.*;
024: import com.db4o.foundation.*;
025: import com.db4o.internal.*;
026: import com.db4o.io.*;
027:
028: /**
029: * @exclude
030: */
031: public class TimerFileLockEnabled extends TimerFileLock {
032:
033: private final IoAdapter _timerFile;
034:
035: private final Object _timerLock;
036:
037: private byte[] _longBytes = new byte[Const4.LONG_LENGTH];
038:
039: private byte[] _intBytes = new byte[Const4.INT_LENGTH];
040:
041: private int _headerLockOffset = 2 + Const4.INT_LENGTH;
042:
043: private final long _opentime;
044:
045: private int _baseAddress = -1;
046:
047: private int _openTimeOffset;
048:
049: private int _accessTimeOffset;
050:
051: private boolean _closed = false;
052:
053: public TimerFileLockEnabled(IoAdaptedObjectContainer file) {
054: _timerLock = file.lock();
055:
056: // FIXME: No reason to sync over the big master lock.
057: // A local lock should be OK.
058: // _timerLock = new Object();
059:
060: _timerFile = file.timerFile();
061: _opentime = uniqueOpenTime();
062: }
063:
064: public void checkHeaderLock() {
065: if (((int) _opentime) != readInt(0, _headerLockOffset)) {
066: throw new DatabaseFileLockedException(_timerFile.toString());
067: }
068: writeHeaderLock();
069: }
070:
071: public void checkOpenTime() {
072: long readOpenTime = readLong(_baseAddress, _openTimeOffset);
073: if (_opentime != readOpenTime) {
074: throw new DatabaseFileLockedException(_timerFile.toString());
075: }
076: writeOpenTime();
077: }
078:
079: public void checkIfOtherSessionAlive(
080: LocalObjectContainer container, int address, int offset,
081: long lastAccessTime) throws Db4oIOException {
082: if (_timerFile == null) { // need to check?
083: return;
084: }
085: long waitTime = Const4.LOCK_TIME_INTERVAL * 5;
086: long currentTime = System.currentTimeMillis();
087:
088: // If someone changes the system clock here, he is out of luck.
089: while (System.currentTimeMillis() < currentTime + waitTime) {
090: Cool.sleepIgnoringInterruption(waitTime);
091: }
092:
093: long currentAccessTime = readLong(address, offset);
094: if ((currentAccessTime > lastAccessTime)) {
095: throw new DatabaseFileLockedException(container.toString());
096: }
097: }
098:
099: public void close() throws Db4oIOException {
100: writeAccessTime(true);
101: synchronized (_timerLock) {
102: _closed = true;
103: }
104: }
105:
106: public boolean lockFile() {
107: return true;
108: }
109:
110: public long openTime() {
111: return _opentime;
112: }
113:
114: public void run() {
115: while (true) {
116: synchronized (_timerLock) {
117: if (_closed) {
118: return;
119: }
120: writeAccessTime(false);
121: }
122: Cool.sleepIgnoringInterruption(Const4.LOCK_TIME_INTERVAL);
123: }
124: }
125:
126: public void setAddresses(int baseAddress, int openTimeOffset,
127: int accessTimeOffset) {
128: _baseAddress = baseAddress;
129: _openTimeOffset = openTimeOffset;
130: _accessTimeOffset = accessTimeOffset;
131: }
132:
133: public void start() throws Db4oIOException {
134: writeAccessTime(false);
135: _timerFile.sync();
136: checkOpenTime();
137: Thread thread = new Thread(this );
138: thread.setName("db4o file lock");
139: thread.setDaemon(true);
140: thread.start();
141: }
142:
143: private long uniqueOpenTime() {
144: return System.currentTimeMillis();
145: // TODO: More security is possible here to make this time unique
146: // to other processes.
147: }
148:
149: private boolean writeAccessTime(boolean closing)
150: throws Db4oIOException {
151: if (noAddressSet()) {
152: return true;
153: }
154: long time = closing ? 0 : System.currentTimeMillis();
155: boolean ret = writeLong(_baseAddress, _accessTimeOffset, time);
156: sync();
157: return ret;
158: }
159:
160: private boolean noAddressSet() {
161: return _baseAddress < 0;
162: }
163:
164: public void writeHeaderLock() {
165: writeInt(0, _headerLockOffset, (int) _opentime);
166: sync();
167: }
168:
169: public void writeOpenTime() {
170: writeLong(_baseAddress, _openTimeOffset, _opentime);
171: sync();
172: }
173:
174: private boolean writeLong(int address, int offset, long time)
175: throws Db4oIOException {
176: synchronized (_timerLock) {
177: if (_timerFile == null) {
178: return false;
179: }
180: _timerFile.blockSeek(address, offset);
181: if (Deploy.debug) {
182: Buffer lockBytes = new Buffer(Const4.LONG_LENGTH);
183: lockBytes.writeLong(time);
184: _timerFile.write(lockBytes._buffer);
185: } else {
186: PrimitiveCodec.writeLong(_longBytes, time);
187: _timerFile.write(_longBytes);
188: }
189: return true;
190: }
191: }
192:
193: private long readLong(int address, int offset)
194: throws Db4oIOException {
195: synchronized (_timerLock) {
196: if (_timerFile == null) {
197: return 0;
198: }
199: _timerFile.blockSeek(address, offset);
200: if (Deploy.debug) {
201: Buffer lockBytes = new Buffer(Const4.LONG_LENGTH);
202: _timerFile.read(lockBytes._buffer, Const4.LONG_LENGTH);
203: return lockBytes.readLong();
204: }
205: _timerFile.read(_longBytes);
206: return PrimitiveCodec.readLong(_longBytes, 0);
207: }
208: }
209:
210: private boolean writeInt(int address, int offset, int time) {
211: synchronized (_timerLock) {
212: if (_timerFile == null) {
213: return false;
214: }
215: _timerFile.blockSeek(address, offset);
216: if (Deploy.debug) {
217: Buffer lockBytes = new Buffer(Const4.INT_LENGTH);
218: lockBytes.writeInt(time);
219: _timerFile.write(lockBytes._buffer);
220: } else {
221: PrimitiveCodec.writeInt(_intBytes, 0, time);
222: _timerFile.write(_intBytes);
223: }
224: return true;
225: }
226: }
227:
228: private long readInt(int address, int offset) {
229: synchronized (_timerLock) {
230: if (_timerFile == null) {
231: return 0;
232: }
233: _timerFile.blockSeek(address, offset);
234: if (Deploy.debug) {
235: Buffer lockBytes = new Buffer(Const4.INT_LENGTH);
236: _timerFile.read(lockBytes._buffer, Const4.INT_LENGTH);
237: return lockBytes.readInt();
238: }
239: _timerFile.read(_longBytes);
240: return PrimitiveCodec.readInt(_longBytes, 0);
241: }
242: }
243:
244: private void sync() throws Db4oIOException {
245: _timerFile.sync();
246: }
247:
248: }
|