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;
022:
023: import java.io.*;
024:
025: import com.db4o.*;
026: import com.db4o.config.*;
027: import com.db4o.ext.*;
028: import com.db4o.foundation.*;
029: import com.db4o.internal.slots.*;
030: import com.db4o.io.*;
031:
032: /**
033: * @exclude
034: */
035: public class IoAdaptedObjectContainer extends LocalObjectContainer {
036:
037: private final String _fileName;
038:
039: private IoAdapter _file;
040: private IoAdapter _timerFile; //This is necessary as a separate File because access is not synchronized with access for normal data read/write so the seek pointer can get lost.
041: private volatile IoAdapter _backupFile;
042:
043: private Object _fileLock;
044:
045: private final FreespaceFiller _freespaceFiller;
046:
047: IoAdaptedObjectContainer(Configuration config, String fileName)
048: throws OldFormatException {
049: super (config, null);
050: _fileLock = new Object();
051: _fileName = fileName;
052: _freespaceFiller = createFreespaceFiller();
053: open();
054: }
055:
056: protected final void openImpl() throws OldFormatException,
057: DatabaseReadOnlyException {
058: IoAdapter ioAdapter = configImpl().ioAdapter();
059: boolean isNew = !ioAdapter.exists(fileName());
060: if (isNew) {
061: logMsg(14, fileName());
062: checkReadOnly();
063: _handlers.oldEncryptionOff();
064: }
065: boolean readOnly = configImpl().isReadOnly();
066: boolean lockFile = Debug.lockFile && configImpl().lockFile()
067: && (!readOnly);
068: _file = ioAdapter.open(fileName(), lockFile, 0, readOnly);
069: if (needsLockFileThread()) {
070: _timerFile = ioAdapter.delegatedIoAdapter().open(
071: fileName(), false, 0, false);
072: }
073: if (isNew) {
074: configureNewFile();
075: if (configImpl().reservedStorageSpace() > 0) {
076: reserve(configImpl().reservedStorageSpace());
077: }
078: commitTransaction();
079: writeHeader(true, false);
080: } else {
081: readThis();
082: }
083: }
084:
085: public void backup(String path) throws DatabaseClosedException,
086: Db4oIOException {
087: synchronized (_lock) {
088: checkClosed();
089: if (_backupFile != null) {
090: throw new BackupInProgressException();
091: }
092: _backupFile = configImpl().ioAdapter().open(path, true,
093: _file.getLength(), false);
094: _backupFile.blockSize(blockSize());
095: }
096: long pos = 0;
097: byte[] buffer = new byte[8192];
098: while (true) {
099: synchronized (_lock) {
100: _file.seek(pos);
101: int read = _file.read(buffer);
102: if (read <= 0) {
103: break;
104: }
105: _backupFile.seek(pos);
106: _backupFile.write(buffer, read);
107: pos += read;
108: }
109: }
110:
111: Cool.sleepIgnoringInterruption(1);
112:
113: synchronized (_lock) {
114: _backupFile.close();
115: _backupFile = null;
116: }
117: }
118:
119: public void blockSize(int size) {
120: _file.blockSize(size);
121: if (_timerFile != null) {
122: _timerFile.blockSize(size);
123: }
124: }
125:
126: public byte blockSize() {
127: return (byte) _file.blockSize();
128: }
129:
130: protected void freeInternalResources() {
131: freePrefetchedPointers();
132: }
133:
134: protected void shutdownDataStorage() {
135: synchronized (_fileLock) {
136: closeDatabaseFile();
137: closeFileHeader();
138: closeTimerFile();
139: }
140: }
141:
142: /*
143: * This method swallows IOException,
144: * because it should not affect other close precedures.
145: */
146: private void closeDatabaseFile() {
147: try {
148: if (_file != null) {
149: _file.close();
150: }
151: } finally {
152: _file = null;
153: }
154: }
155:
156: /*
157: * This method swallows IOException,
158: * because it should not affect other close precedures.
159: */
160: private void closeFileHeader() {
161: try {
162: if (_fileHeader != null) {
163: _fileHeader.close();
164: }
165: } finally {
166: _fileHeader = null;
167: }
168: }
169:
170: /*
171: * This method swallows IOException,
172: * because it should not affect other close precedures.
173: */
174: private void closeTimerFile() {
175: try {
176: if (_timerFile != null) {
177: _timerFile.close();
178: }
179: } finally {
180: _timerFile = null;
181: }
182: }
183:
184: public void commit1(Transaction trans) {
185: ensureLastSlotWritten();
186: super .commit1(trans);
187: }
188:
189: public void copy(int oldAddress, int oldAddressOffset,
190: int newAddress, int newAddressOffset, int length) {
191:
192: if (Debug.xbytes && Deploy.overwrite) {
193: checkXBytes(newAddress, newAddressOffset, length);
194: }
195:
196: try {
197:
198: if (_backupFile == null) {
199: _file.blockCopy(oldAddress, oldAddressOffset,
200: newAddress, newAddressOffset, length);
201: return;
202: }
203:
204: byte[] copyBytes = new byte[length];
205: _file.blockSeek(oldAddress, oldAddressOffset);
206: _file.read(copyBytes);
207:
208: _file.blockSeek(newAddress, newAddressOffset);
209: _file.write(copyBytes);
210:
211: if (_backupFile != null) {
212: _backupFile.blockSeek(newAddress, newAddressOffset);
213: _backupFile.write(copyBytes);
214: }
215:
216: } catch (Exception e) {
217: Exceptions4.throwRuntimeException(16, e);
218: }
219:
220: }
221:
222: private void checkXBytes(int newAddress, int newAddressOffset,
223: int length) {
224: if (Debug.xbytes && Deploy.overwrite) {
225: try {
226: byte[] checkXBytes = new byte[length];
227: _file.blockSeek(newAddress, newAddressOffset);
228: _file.read(checkXBytes);
229: for (int i = 0; i < checkXBytes.length; i++) {
230: if (checkXBytes[i] != Const4.XBYTE) {
231: String msg = "XByte corruption adress:"
232: + newAddress + " length:" + length
233: + " starting:" + i;
234: throw new RuntimeException(msg);
235: }
236: }
237: } catch (Exception e) {
238: e.printStackTrace();
239: }
240: }
241: }
242:
243: public long fileLength() {
244: try {
245: return _file.getLength();
246: } catch (Exception e) {
247: throw new RuntimeException();
248: }
249: }
250:
251: public String fileName() {
252: return _fileName;
253: }
254:
255: public void readBytes(byte[] bytes, int address, int length)
256: throws Db4oIOException {
257: readBytes(bytes, address, 0, length);
258: }
259:
260: public void readBytes(byte[] bytes, int address, int addressOffset,
261: int length) throws Db4oIOException {
262:
263: if (DTrace.enabled) {
264: DTrace.READ_BYTES
265: .logLength(address + addressOffset, length);
266: }
267: _file.blockSeek(address, addressOffset);
268: int bytesRead = _file.read(bytes, length);
269: checkReadCount(bytesRead, length);
270: }
271:
272: private void checkReadCount(int bytesRead, int expected) {
273: if (bytesRead != expected) {
274: throw new IncompatibleFileFormatException();
275: }
276: }
277:
278: public void reserve(int byteCount) throws DatabaseReadOnlyException {
279: checkReadOnly();
280: synchronized (_lock) {
281: Slot slot = getSlot(byteCount);
282: zeroReservedSlot(slot);
283: free(slot);
284: }
285: }
286:
287: private void zeroReservedSlot(Slot slot) {
288: zeroFile(_file, slot);
289: zeroFile(_backupFile, slot);
290: }
291:
292: private void zeroFile(IoAdapter io, Slot slot) {
293: if (io == null) {
294: return;
295: }
296: byte[] zeroBytes = new byte[1024];
297: int left = slot.length();
298: io.blockSeek(slot.address(), 0);
299: while (left > zeroBytes.length) {
300: io.write(zeroBytes, zeroBytes.length);
301: left -= zeroBytes.length;
302: }
303: if (left > 0) {
304: io.write(zeroBytes, left);
305: }
306: }
307:
308: public void syncFiles() {
309: try {
310: _file.sync();
311: if (_timerFile != null) {
312: _timerFile.sync();
313: }
314: } catch (Exception e) {
315: }
316: }
317:
318: public void writeBytes(Buffer bytes, int address, int addressOffset) {
319: if (Deploy.debug && !Deploy.flush) {
320: return;
321: }
322:
323: if (Debug.xbytes && Deploy.overwrite) {
324:
325: boolean doCheck = true;
326: if (bytes instanceof StatefulBuffer) {
327: StatefulBuffer writer = (StatefulBuffer) bytes;
328: if (writer.getID() == Const4.IGNORE_ID) {
329: doCheck = false;
330: }
331: }
332: if (doCheck) {
333: checkXBytes(address, addressOffset, bytes.length());
334: }
335: }
336:
337: if (DTrace.enabled) {
338: DTrace.WRITE_BYTES.logLength(address + addressOffset, bytes
339: .length());
340: }
341:
342: _file.blockSeek(address, addressOffset);
343: _file.write(bytes._buffer, bytes.length());
344: if (_backupFile != null) {
345: _backupFile.blockSeek(address, addressOffset);
346: _backupFile.write(bytes._buffer, bytes.length());
347: }
348: }
349:
350: public void overwriteDeletedBytes(int address, int length) {
351: if (!Deploy.flush) {
352: return;
353: }
354: if (_freespaceFiller == null) {
355: return;
356: }
357: if (address > 0 && length > 0) {
358: if (DTrace.enabled) {
359: DTrace.WRITE_XBYTES.logLength(address, length);
360: }
361: IoAdapterWindow window = new IoAdapterWindow(_file,
362: address, length);
363: try {
364: createFreespaceFiller().fill(window);
365: } catch (IOException e) {
366: e.printStackTrace();
367: } finally {
368: window.disable();
369: }
370: }
371:
372: }
373:
374: public IoAdapter timerFile() {
375: return _timerFile;
376: }
377:
378: private FreespaceFiller createFreespaceFiller() {
379: FreespaceFiller freespaceFiller = config().freespaceFiller();
380: if (Debug.xbytes) {
381: freespaceFiller = new XByteFreespaceFiller();
382: }
383: return freespaceFiller;
384: }
385:
386: private static class XByteFreespaceFiller implements
387: FreespaceFiller {
388:
389: public void fill(IoAdapterWindow io) throws IOException {
390: io.write(0, xBytes(io.length()));
391: }
392:
393: private byte[] xBytes(int len) {
394: byte[] bytes = new byte[len];
395: for (int i = 0; i < len; i++) {
396: bytes[i] = Const4.XBYTE;
397: }
398: return bytes;
399: }
400: }
401: }
|