View Javadoc

1   /***
2    * Simple Web Spider - <http://simplewebspider.sourceforge.net/>
3    * Copyright (C) 2009  <berendona@users.sourceforge.net>
4    *
5    * This program is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package simplespider.simplespider.dao.db4o;
20  
21  import java.io.IOException;
22  import java.sql.SQLException;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  
27  import simplespider.simplespider.dao.DbHelper;
28  import simplespider.simplespider.dao.DbHelperFactory;
29  
30  import com.db4o.ObjectContainer;
31  import com.db4o.ObjectServer;
32  import com.db4o.constraints.UniqueFieldValueConstraint;
33  import com.db4o.cs.Db4oClientServer;
34  import com.db4o.cs.config.ServerConfiguration;
35  import com.db4o.defragment.Defragment;
36  import com.db4o.diagnostic.ClassHasNoFields;
37  import com.db4o.diagnostic.Diagnostic;
38  import com.db4o.diagnostic.DiagnosticBase;
39  import com.db4o.diagnostic.DiagnosticListener;
40  import com.db4o.ext.ExtObjectContainer;
41  import com.db4o.ext.SystemInfo;
42  import com.db4o.reflect.ReflectClass;
43  
44  public class Db4oDbHelperFactory implements DbHelperFactory {
45  
46  	private static final Log	LOG	= LogFactory.getLog(Db4oDbHelperFactory.class);
47  
48  	private ObjectServer		server;
49  
50  	public Db4oDbHelperFactory(final String filename) {
51  
52  		final ServerConfiguration dbConfig = Db4oClientServer.newServerConfiguration();
53  		dbConfig.common().objectClass(Hash.class).objectField(Hash.HASH).indexed(true);
54  		dbConfig.common().add(new UniqueFieldValueConstraint(Hash.class, Hash.HASH));
55  
56  		dbConfig.common().allowVersionUpdates(true);
57  		dbConfig.common().detectSchemaChanges(true);
58  		dbConfig.common().exceptionsOnNotStorable(true);
59  		dbConfig.common().optimizeNativeQueries(true);
60  		dbConfig.common().messageLevel(1);
61  		dbConfig.common().activationDepth(1);
62  
63  		if (LOG.isDebugEnabled()) {
64  			dbConfig.common().diagnostic().addListener(new DiagnosticListener() {
65  				public void onDiagnostic(final Diagnostic arg0) {
66  
67  					if (arg0 instanceof ClassHasNoFields) {
68  						return; // Ignore
69  					}
70  					if (arg0 instanceof DiagnosticBase) {
71  						final DiagnosticBase d = (DiagnosticBase) arg0;
72  						LOG.debug("Diagnostic: " + d.getClass() + " : " + d.problem() + " : " + d.solution() + " : " + d.reason(), new Exception(
73  								"debug"));
74  					} else {
75  						LOG.debug("Diagnostic: " + arg0 + " : " + arg0.getClass(), new Exception("debug"));
76  					}
77  				}
78  			});
79  		}
80  
81  		/* TURN OFF SHUTDOWN HOOK.
82  		 * The shutdown hook does auto-commit. 
83  		 * And it close database after getting signal (or pressing CTRL-C) */
84  		dbConfig.common().automaticShutDown(false);
85  
86  		// LAZY appears to cause ClassCastException's relating to db4o objects inside db4o code. :(
87  		// Also it causes duplicates if we activate immediately.
88  		// And the performance gain for e.g. RegisterMeRunner isn't that great.
89  		//		dbConfig.queries().evaluationMode(QueryEvaluationMode.LAZY);
90  		//		dbConfig.common().queries().evaluationMode(QueryEvaluationMode.SNAPSHOT);
91  
92  		// Reduce memory usage. After running eight hours with an 350 MB DB (than 400 MB) freeslot requires 14 MB instead of 0.4 MB on application startup
93  		dbConfig.file().freespace().useBTreeSystem();
94  
95  		/* Block size 8 should have minimal impact since pointers are this
96  		 * long, and allows databases of up to 16GB. 
97  		 * FIXME make configurable by user. */
98  		dbConfig.file().blockSize(8);
99  
100 		if (LOG.isInfoEnabled()) {
101 			LOG.info("Start defragmentation database file... This could took some while...");
102 		}
103 		try {
104 			Defragment.defrag(filename);
105 		} catch (final IOException e) {
106 			LOG.warn("Failed to defragment database file \"" + filename + "\"", e);
107 		}
108 
109 		if (LOG.isInfoEnabled()) {
110 			LOG.info("Opening database file... This could took some while...");
111 		}
112 		try {
113 			this.server = Db4oClientServer.openServer(dbConfig, filename, 0);
114 		} catch (final RuntimeException e) {
115 			throw new RuntimeException("Failed to open database file \"" + filename + "\"", e);
116 		}
117 
118 		if (LOG.isInfoEnabled()) {
119 			final ObjectContainer container = getConnection();
120 			try {
121 				final ExtObjectContainer ext = container.ext();
122 
123 				final ReflectClass[] knownClasses = ext.knownClasses();
124 				final StringBuffer sb = new StringBuffer();
125 				sb.append("Known classes: ");
126 				for (final ReflectClass knownClass : knownClasses) {
127 					sb.append(knownClass.getName());
128 					sb.append(";");
129 				}
130 				LOG.info(sb.toString());
131 
132 				final SystemInfo systemInfo = ext.systemInfo();
133 				LOG.info("Total size: " + systemInfo.totalSize());
134 				LOG.info("Freespace size: " + systemInfo.freespaceSize());
135 				LOG.info("Freespace entry count: " + systemInfo.freespaceEntryCount());
136 
137 			} finally {
138 				container.close();
139 			}
140 		}
141 	}
142 
143 	@Override
144 	public DbHelper buildDbHelper() throws SQLException {
145 		final Db4oDbHelper dbHelper = new Db4oDbHelper();
146 
147 		dbHelper.createConnection(this);
148 		return dbHelper;
149 	}
150 
151 	ObjectContainer getConnection() {
152 		return this.server.openClient();
153 	}
154 
155 	void shutdown() {
156 		this.server.close();
157 		this.server = null;
158 	}
159 
160 }