Db4o input/output implementation comes as a pluggable module. It means that you can write your own IO system based on IoAdapter class.
Pluggable IO Adapter has control over the following:
Some of the popular implementations of IoAdapter:
You can look at the db4o source to see some of these implementations (search for classes inheriting from IoAdapter).
By default db4o uses RandomAccessFileAdapter. You can install another IoAdapter with a single call:
Java: Db4o.configure().io(new SpecificIoAdapter())
Please, note: this call should be issued before opening of a database file. IoAdapter can be changed only while the database is closed.
For a test, let's try to create debugging IoAdapter, which will log all the information about its actions to the output stream:
001/* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com */ 002
003
package com.db4odoc.ios; 004
005
import java.io.File; 006
import java.io.IOException; 007
import java.io.PrintStream; 008
import java.io.RandomAccessFile; 009
010
import com.db4o.DTrace; 011
import com.db4o.ext.DatabaseFileLockedException; 012
import com.db4o.internal.*; 013
import com.db4o.io.IoAdapter; 014
015
public class LoggingAdapter extends IoAdapter { 016
017
private String _path; 018
private RandomAccessFile _delegate; 019
private PrintStream _out = System.out; 020
021
public LoggingAdapter(){ 022
} 023
024
protected LoggingAdapter(String path, boolean lockFile, long initialLength) throws IOException { 025
_path=new File(path).getCanonicalPath(); 026
_delegate = new RandomAccessFile(path, "rw"); 027
if(initialLength>0) { 028
_delegate.seek(initialLength - 1); 029
_delegate.write(new byte[] {0}); 030
} 031
if(lockFile){ 032
try { 033
Platform4.lockFile(_path, _delegate); 034
} catch (DatabaseFileLockedException e) { 035
_delegate.close(); 036
throw e; 037
} 038
} 039
} 040
041
public void setOut(PrintStream out){ 042
_out = out; 043
} 044
045
public void close() throws IOException { 046
_out.println("Closing file"); 047
try { 048
Platform4.unlockFile(_path,_delegate); 049
} catch (Exception e) { 050
} 051
_delegate.close(); 052
} 053
054
055
public void delete(String path) { 056
_out.println("Deleting file " + path); 057
new File(path).delete(); 058
} 059
060
public boolean exists(String path){ 061
File existingFile = new File(path); 062
return existingFile.exists() && existingFile.length() > 0; 063
} 064
065
public long getLength() throws IOException { 066
_out.println("File length:" + _delegate.length()); 067
return _delegate.length(); 068
} 069
070
public IoAdapter open(String path, boolean lockFile, long initialLength) throws IOException { 071
_out.println("Opening file " + path); 072
return new LoggingAdapter(path, lockFile, initialLength); 073
} 074
075
076
public int read(byte[] bytes, int length) throws IOException { 077
_out.println("Reading " + length + " bytes"); 078
return _delegate.read(bytes, 0, length); 079
} 080
081
082
public void seek(long pos) throws IOException { 083
084
if(DTrace.enabled){ 085
DTrace.REGULAR_SEEK.log(pos); 086
} 087
_out.println("Setting pointer position to " + pos); 088
_delegate.seek(pos); 089
} 090
091
092
public void sync() throws IOException { 093
_out.println("Synchronizing"); 094
_delegate.getFD().sync(); 095
} 096
097
098
public void write(byte[] buffer, int length) throws IOException { 099
_out.println("Writing " + length + " bytes"); 100
_delegate.write(buffer, 0, length); 101
102
} 103
104
}
Now let's test how it works:
01public static void testLoggingAdapter(){ 02
Db4o.configure().io(new LoggingAdapter()); 03
ObjectContainer db = Db4o.openFile(YAPFILENAME); 04
try { 05
Pilot pilot = new Pilot("Michael Schumacher"); 06
db.set(pilot); 07
System.out.println("New pilot added"); 08
} finally { 09
db.close(); 10
} 11
12
db = Db4o.openFile(YAPFILENAME); 13
try { 14
ObjectSet result=db.get(Pilot.class); 15
listResult(result); 16
} finally { 17
db.close(); 18
} 19
Db4o.configure().io(new RandomAccessFileAdapter()); 20
}
The output can be used for debugging purposes.