Pluggable IO Concept

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:

LoggingAdapter.java
001/* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com */ 002 003package com.db4odoc.ios; 004 005import java.io.File; 006import java.io.IOException; 007import java.io.PrintStream; 008import java.io.RandomAccessFile; 009 010import com.db4o.DTrace; 011import com.db4o.ext.DatabaseFileLockedException; 012import com.db4o.ext.Db4oIOException; 013import com.db4o.internal.Platform4; 014import com.db4o.io.IoAdapter; 015 016public class LoggingAdapter extends IoAdapter { 017 018 @Override 019 public IoAdapter open(String path, boolean lockFile, long initialLength, boolean readOnly) throws Db4oIOException { 020 _out.println("Opening file " + path); 021 return new LoggingAdapter(path, lockFile, initialLength, readOnly); 022 } 023 024 025 private String _path; 026 private RandomAccessFile _delegate; 027 private PrintStream _out = System.out; 028 029 public LoggingAdapter(){ 030 } 031 032 protected LoggingAdapter(String path, boolean lockFile, long initialLength, boolean readOnly) throws Db4oIOException { 033 try { 034 String mode = readOnly ? "r" : "rw"; 035 _path=new File(path).getCanonicalPath(); 036 _delegate = new RandomAccessFile(path, mode); 037 if(initialLength>0) { 038 _delegate.seek(initialLength - 1); 039 _delegate.write(new byte[] {0}); 040 } 041 if(lockFile){ 042 try { 043 Platform4.lockFile(_path, _delegate); 044 } catch (DatabaseFileLockedException e) { 045 _delegate.close(); 046 throw e; 047 } 048 } 049 } catch (IOException e) { 050 throw new Db4oIOException(e); 051 } 052 } 053 054 public void setOut(PrintStream out){ 055 _out = out; 056 } 057 058 public void close() throws Db4oIOException { 059 _out.println("Closing file"); 060 try { 061 Platform4.unlockFile(_path,_delegate); 062 _delegate.close(); 063 } catch (IOException e) { 064 throw new Db4oIOException(e); 065 } catch (Exception e) { 066 } 067 } 068 069 070 public void delete(String path) { 071 _out.println("Deleting file " + path); 072 new File(path).delete(); 073 } 074 075 public boolean exists(String path){ 076 File existingFile = new File(path); 077 return existingFile.exists() && existingFile.length() > 0; 078 } 079 080 public long getLength() throws Db4oIOException { 081 long length; 082 try { 083 _out.println("File length:" + _delegate.length()); 084 length = _delegate.length(); 085 } catch (IOException e) { 086 throw new Db4oIOException(e); 087 } 088 return length; 089 } 090 091 public int read(byte[] bytes, int length) throws Db4oIOException { 092 int readBytes; 093 try { 094 _out.println("Reading " + length + " bytes"); 095 readBytes = _delegate.read(bytes, 0, length); 096 } catch (IOException e) { 097 throw new Db4oIOException(e); 098 } 099 return readBytes; 100 } 101 102 103 public void seek(long pos) throws Db4oIOException { 104 105 if(DTrace.enabled){ 106 DTrace.REGULAR_SEEK.log(pos); 107 } 108 try { 109 _out.println("Setting pointer position to " + pos); 110 _delegate.seek(pos); 111 } catch (IOException e) { 112 throw new Db4oIOException(e); 113 } 114 } 115 116 117 public void sync() throws Db4oIOException { 118 _out.println("Synchronizing"); 119 try { 120 _delegate.getFD().sync(); 121 } catch (IOException e) { 122 throw new Db4oIOException(e); 123 } 124 } 125 126 127 public void write(byte[] buffer, int length) throws Db4oIOException { 128 _out.println("Writing " + length + " bytes"); 129 try { 130 _delegate.write(buffer, 0, length); 131 } catch (IOException e) { 132 new Db4oIOException(e); 133 } 134 135 } 136 137}

Now let's test how it works:

IOExample.java: testLoggingAdapter
01private static void testLoggingAdapter(){ 02 Configuration configuration = Db4o.newConfiguration(); 03 configuration.io(new LoggingAdapter()); 04 ObjectServer server = Db4o.openServer(configuration, DB4O_FILE_NAME, 0xdb40); 05 server.grantAccess("y", "y"); 06 ObjectContainer container = server.openClient(); 07 //ObjectContainer container = Db4o.openClient(configuration, "localhost", 0xdb40,"y", "y"); 08 try { 09 Pilot pilot = new Pilot("Michael Schumacher"); 10 container.set(pilot); 11 System.out.println("New pilot added"); 12 } finally { 13 14 container.close(); 15 server.close(); 16 } 17 18 container = Db4o.openFile(DB4O_FILE_NAME); 19 try { 20 ObjectSet result=container.get(Pilot.class); 21 listResult(result); 22 } finally { 23 container.close(); 24 } 25 }

The output can be used for debugging purposes.