blob: bbf4839d965819f5158f26e66129c9049672c2a9 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
5#include <stdio.h>
6#include <stdlib.h>
7
[email protected]d9eb3c42008-12-12 12:00:408#include <limits>
initial.commit09911bf2008-07-26 23:55:299#include <set>
10
[email protected]d9eb3c42008-12-12 12:00:4011#include "base/file_path.h"
initial.commit09911bf2008-07-26 23:55:2912#include "base/file_util.h"
13#include "base/logging.h"
14#include "base/path_service.h"
15#include "base/perftimer.h"
[email protected]d9eb3c42008-12-12 12:00:4016#include "base/rand_util.h"
17#include "base/scoped_ptr.h"
initial.commit09911bf2008-07-26 23:55:2918#include "base/string_util.h"
[email protected]e14b1572008-11-25 23:29:5619#include "base/test_file_util.h"
initial.commit09911bf2008-07-26 23:55:2920#include "chrome/browser/safe_browsing/safe_browsing_database.h"
21#include "chrome/common/chrome_paths.h"
22#include "chrome/common/sqlite_compiled_statement.h"
23#include "chrome/common/sqlite_utils.h"
[email protected]d9eb3c42008-12-12 12:00:4024#include "googleurl/src/gurl.h"
initial.commit09911bf2008-07-26 23:55:2925#include "testing/gtest/include/gtest/gtest.h"
26
initial.commit09911bf2008-07-26 23:55:2927namespace {
28
29// Base class for a safebrowsing database. Derived classes can implement
30// different types of tables to compare performance characteristics.
31class Database {
32 public:
33 Database() : db_(NULL) {
34 }
35
36 ~Database() {
37 if (db_) {
initial.commit09911bf2008-07-26 23:55:2938 sqlite3_close(db_);
39 db_ = NULL;
40 }
41 }
42
[email protected]d9eb3c42008-12-12 12:00:4043 bool Init(const FilePath& name, bool create) {
initial.commit09911bf2008-07-26 23:55:2944 // get an empty file for the test DB
[email protected]d9eb3c42008-12-12 12:00:4045 FilePath filename;
initial.commit09911bf2008-07-26 23:55:2946 PathService::Get(base::DIR_TEMP, &filename);
[email protected]d9eb3c42008-12-12 12:00:4047 filename = filename.Append(name);
initial.commit09911bf2008-07-26 23:55:2948
49 if (create) {
[email protected]d9eb3c42008-12-12 12:00:4050 file_util::Delete(filename, false);
initial.commit09911bf2008-07-26 23:55:2951 } else {
[email protected]d9eb3c42008-12-12 12:00:4052 DLOG(INFO) << "evicting " << name.value() << " ...";
53 file_util::EvictFileFromSystemCache(filename);
initial.commit09911bf2008-07-26 23:55:2954 DLOG(INFO) << "... evicted";
55 }
56
[email protected]d9eb3c42008-12-12 12:00:4057 const std::string sqlite_path = WideToUTF8(filename.ToWStringHack());
58 if (sqlite3_open(sqlite_path.c_str(), &db_) != SQLITE_OK)
initial.commit09911bf2008-07-26 23:55:2959 return false;
60
61 statement_cache_.set_db(db_);
62
63 if (!create)
64 return true;
65
66 return CreateTable();
67 }
68
69 virtual bool CreateTable() = 0;
70 virtual bool Add(int host_key, int* prefixes, int count) = 0;
71 virtual bool Read(int host_key, int* prefixes, int size, int* count) = 0;
72 virtual int Count() = 0;
73 virtual std::string GetDBSuffix() = 0;
74
75 sqlite3* db() { return db_; }
76
77 protected:
78 // The database connection.
79 sqlite3* db_;
80
81 // Cache of compiled statements for our database.
82 SqliteStatementCache statement_cache_;
83};
84
85class SimpleDatabase : public Database {
86 public:
87 virtual bool CreateTable() {
88 if (DoesSqliteTableExist(db_, "hosts"))
89 return false;
90
91 return sqlite3_exec(db_, "CREATE TABLE hosts ("
92 "host INTEGER,"
93 "prefixes BLOB)",
94 NULL, NULL, NULL) == SQLITE_OK;
95 }
96
97 virtual bool Add(int host_key, int* prefixes, int count) {
98 SQLITE_UNIQUE_STATEMENT(statement, statement_cache_,
99 "INSERT OR REPLACE INTO hosts"
100 "(host,prefixes)"
101 "VALUES (?,?)");
102 if (!statement.is_valid())
103 return false;
104
105 statement->bind_int(0, host_key);
106 statement->bind_blob(1, prefixes, count*sizeof(int));
107 return statement->step() == SQLITE_DONE;
108 }
109
110 virtual bool Read(int host_key, int* prefixes, int size, int* count) {
111 SQLITE_UNIQUE_STATEMENT(statement, statement_cache_,
112 "SELECT host, prefixes FROM hosts WHERE host=?");
113 if (!statement.is_valid())
114 return false;
115
116 statement->bind_int(0, host_key);
117
118 int rv = statement->step();
119 if (rv == SQLITE_DONE) {
120 // no hostkey found, not an error
121 *count = -1;
122 return true;
123 }
124
125 if (rv != SQLITE_ROW)
126 return false;
127
128 *count = statement->column_bytes(1);
129 if (*count > size)
130 return false;
131
132 memcpy(prefixes, statement->column_blob(0), *count);
133 return true;
134 }
135
136 int Count() {
137 SQLITE_UNIQUE_STATEMENT(statement, statement_cache_,
138 "SELECT COUNT(*) FROM hosts");
139 if (!statement.is_valid()) {
140 EXPECT_TRUE(false);
141 return -1;
142 }
143
144 if (statement->step() != SQLITE_ROW) {
145 EXPECT_TRUE(false);
146 return -1;
147 }
148
149 return statement->column_int(0);
150 }
151
152 std::string GetDBSuffix() {
153 return "Simple";
154 }
155};
156
157class IndexedDatabase : public SimpleDatabase {
158 public:
159 virtual bool CreateTable() {
160 return sqlite3_exec(db_, "CREATE TABLE hosts ("
161 "host INTEGER PRIMARY KEY,"
162 "prefixes BLOB)",
163 NULL, NULL, NULL) == SQLITE_OK;
164 }
165
166 std::string GetDBSuffix() {
167 return "Indexed";
168 }
169};
170
171class IndexedWithIDDatabase : public SimpleDatabase {
172 public:
173 virtual bool CreateTable() {
174 return sqlite3_exec(db_, "CREATE TABLE hosts ("
175 "id INTEGER PRIMARY KEY AUTOINCREMENT,"
176 "host INTEGER UNIQUE,"
177 "prefixes BLOB)",
178 NULL, NULL, NULL) == SQLITE_OK;
179 }
180
181 virtual bool Add(int host_key, int* prefixes, int count) {
182 SQLITE_UNIQUE_STATEMENT(statement, statement_cache_,
183 "INSERT OR REPLACE INTO hosts"
184 "(id,host,prefixes)"
185 "VALUES (NULL,?,?)");
186 if (!statement.is_valid())
187 return false;
188
189 statement->bind_int(0, host_key);
190 statement->bind_blob(1, prefixes, count * sizeof(int));
191 return statement->step() == SQLITE_DONE;
192 }
193
194 std::string GetDBSuffix() {
195 return "IndexedWithID";
196 }
197};
198
[email protected]d9eb3c42008-12-12 12:00:40199} // namespace
initial.commit09911bf2008-07-26 23:55:29200
201class SafeBrowsing: public testing::Test {
202 protected:
203 // Get the test parameters from the test case's name.
204 virtual void SetUp() {
205 logging::InitLogging(
206 NULL, logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
207 logging::LOCK_LOG_FILE,
208 logging::DELETE_OLD_LOG_FILE);
209
210 const testing::TestInfo* const test_info =
211 testing::UnitTest::GetInstance()->current_test_info();
212 std::string test_name = test_info->name();
213
214 TestType type;
215 if (test_name.find("Write") != std::string::npos) {
216 type = WRITE;
217 } else if (test_name.find("Read") != std::string::npos) {
218 type = READ;
219 } else {
220 type = COUNT;
221 }
222
223 if (test_name.find("IndexedWithID") != std::string::npos) {
224 db_ = new IndexedWithIDDatabase();
225 } else if (test_name.find("Indexed") != std::string::npos) {
226 db_ = new IndexedDatabase();
227 } else {
228 db_ = new SimpleDatabase();
229 }
230
231
232 char multiplier_letter = test_name[test_name.size() - 1];
233 int multiplier = 0;
234 if (multiplier_letter == 'K') {
235 multiplier = 1000;
236 } else if (multiplier_letter == 'M') {
237 multiplier = 1000000;
238 } else {
239 NOTREACHED();
240 }
241
242 size_t index = test_name.size() - 1;
243 while (index != 0 && test_name[index] != '_')
244 index--;
245
246 DCHECK(index);
247 const char* count_start = test_name.c_str() + ++index;
248 int count = atoi(count_start);
249 int size = count * multiplier;
250
251 db_name_ = StringPrintf("TestSafeBrowsing");
252 db_name_.append(count_start);
253 db_name_.append(db_->GetDBSuffix());
254
[email protected]d9eb3c42008-12-12 12:00:40255 FilePath path = FilePath::FromWStringHack(ASCIIToWide(db_name_));
256 ASSERT_TRUE(db_->Init(path, type == WRITE));
initial.commit09911bf2008-07-26 23:55:29257
258 if (type == WRITE) {
259 WriteEntries(size);
260 } else if (type == READ) {
261 ReadEntries(100);
262 } else {
263 CountEntries();
264 }
265 }
266
267 virtual void TearDown() {
268 delete db_;
269 }
270
271 // This writes the given number of entries to the database.
272 void WriteEntries(int count) {
273 int prefixes[4];
274
275 SQLTransaction transaction(db_->db());
276 transaction.Begin();
277
initial.commit09911bf2008-07-26 23:55:29278 for (int i = 0; i < count; i++) {
[email protected]d9eb3c42008-12-12 12:00:40279 int hostkey = base::RandInt(std::numeric_limits<int>::min(),
280 std::numeric_limits<int>::max());
initial.commit09911bf2008-07-26 23:55:29281 ASSERT_TRUE(db_->Add(hostkey, prefixes, 1));
282 }
283
284 transaction.Commit();
285 }
286
287 // Read the given number of entries from the database.
288 void ReadEntries(int count) {
289 int prefixes[4];
290
291 int64 total_ms = 0;
292
293 for (int i = 0; i < count; ++i) {
[email protected]d9eb3c42008-12-12 12:00:40294 int key = base::RandInt(std::numeric_limits<int>::min(),
295 std::numeric_limits<int>::max());
initial.commit09911bf2008-07-26 23:55:29296
297 PerfTimer timer;
298
299 int read;
300 ASSERT_TRUE(db_->Read(key, prefixes, sizeof(prefixes), &read));
301
302 int64 time_ms = timer.Elapsed().InMilliseconds();
303 total_ms += time_ms;
304 DLOG(INFO) << "Read in " << time_ms << " ms.";
305 }
306
307 DLOG(INFO) << db_name_ << " read " << count << " entries in average of " <<
308 total_ms/count << " ms.";
309 }
310
311 // Counts how many entries are in the database, which effectively does a full
312 // table scan.
313 void CountEntries() {
314 PerfTimer timer;
315
316 int count = db_->Count();
317
318 DLOG(INFO) << db_name_ << " counted " << count << " entries in " <<
319 timer.Elapsed().InMilliseconds() << " ms";
320 }
321
322 enum TestType {
323 WRITE,
324 READ,
325 COUNT,
326 };
327
328 private:
329
330 Database* db_;
331 std::string db_name_;
332};
333
[email protected]d9eb3c42008-12-12 12:00:40334TEST_F(SafeBrowsing, DISABLED_Write_100K) {
initial.commit09911bf2008-07-26 23:55:29335}
336
[email protected]d9eb3c42008-12-12 12:00:40337TEST_F(SafeBrowsing, DISABLED_Read_100K) {
initial.commit09911bf2008-07-26 23:55:29338}
339
[email protected]d9eb3c42008-12-12 12:00:40340TEST_F(SafeBrowsing, DISABLED_WriteIndexed_100K) {
initial.commit09911bf2008-07-26 23:55:29341}
342
[email protected]d9eb3c42008-12-12 12:00:40343TEST_F(SafeBrowsing, DISABLED_ReadIndexed_100K) {
initial.commit09911bf2008-07-26 23:55:29344}
345
[email protected]d9eb3c42008-12-12 12:00:40346TEST_F(SafeBrowsing, DISABLED_WriteIndexed_250K) {
initial.commit09911bf2008-07-26 23:55:29347}
348
[email protected]d9eb3c42008-12-12 12:00:40349TEST_F(SafeBrowsing, DISABLED_ReadIndexed_250K) {
initial.commit09911bf2008-07-26 23:55:29350}
351
[email protected]d9eb3c42008-12-12 12:00:40352TEST_F(SafeBrowsing, DISABLED_WriteIndexed_500K) {
initial.commit09911bf2008-07-26 23:55:29353}
354
[email protected]d9eb3c42008-12-12 12:00:40355TEST_F(SafeBrowsing, DISABLED_ReadIndexed_500K) {
initial.commit09911bf2008-07-26 23:55:29356}
357
[email protected]d9eb3c42008-12-12 12:00:40358TEST_F(SafeBrowsing, DISABLED_WriteIndexedWithID_250K) {
initial.commit09911bf2008-07-26 23:55:29359}
360
[email protected]d9eb3c42008-12-12 12:00:40361TEST_F(SafeBrowsing, DISABLED_ReadIndexedWithID_250K) {
initial.commit09911bf2008-07-26 23:55:29362}
363
[email protected]d9eb3c42008-12-12 12:00:40364TEST_F(SafeBrowsing, DISABLED_WriteIndexedWithID_500K) {
initial.commit09911bf2008-07-26 23:55:29365}
366
[email protected]d9eb3c42008-12-12 12:00:40367TEST_F(SafeBrowsing, DISABLED_ReadIndexedWithID_500K) {
initial.commit09911bf2008-07-26 23:55:29368}
369
[email protected]d9eb3c42008-12-12 12:00:40370TEST_F(SafeBrowsing, DISABLED_CountIndexed_250K) {
initial.commit09911bf2008-07-26 23:55:29371}
372
[email protected]d9eb3c42008-12-12 12:00:40373TEST_F(SafeBrowsing, DISABLED_CountIndexed_500K) {
initial.commit09911bf2008-07-26 23:55:29374}
375
[email protected]d9eb3c42008-12-12 12:00:40376TEST_F(SafeBrowsing, DISABLED_CountIndexedWithID_250K) {
initial.commit09911bf2008-07-26 23:55:29377}
378
[email protected]d9eb3c42008-12-12 12:00:40379TEST_F(SafeBrowsing, DISABLED_CountIndexedWithID_500K) {
initial.commit09911bf2008-07-26 23:55:29380}
381
382
383class SafeBrowsingDatabaseTest {
384 public:
[email protected]d9eb3c42008-12-12 12:00:40385 SafeBrowsingDatabaseTest(const FilePath& filename) {
initial.commit09911bf2008-07-26 23:55:29386 logging::InitLogging(
387 NULL, logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
388 logging::LOCK_LOG_FILE,
389 logging::DELETE_OLD_LOG_FILE);
390
[email protected]c870c762009-01-28 05:47:15391 FilePath tmp_path;
[email protected]d9eb3c42008-12-12 12:00:40392 PathService::Get(base::DIR_TEMP, &tmp_path);
[email protected]c870c762009-01-28 05:47:15393 path_ = tmp_path.Append(filename);
initial.commit09911bf2008-07-26 23:55:29394 }
395
396 void Create(int size) {
[email protected]d9eb3c42008-12-12 12:00:40397 file_util::Delete(path_, false);
initial.commit09911bf2008-07-26 23:55:29398
[email protected]d9eb3c42008-12-12 12:00:40399 scoped_ptr<SafeBrowsingDatabase> database(SafeBrowsingDatabase::Create());
400 database->SetSynchronous();
[email protected]c870c762009-01-28 05:47:15401 EXPECT_TRUE(database->Init(path_, NULL));
initial.commit09911bf2008-07-26 23:55:29402
403 int chunk_id = 0;
404 int total_host_keys = size;
405 int host_keys_per_chunk = 100;
406
407 std::deque<SBChunk>* chunks = new std::deque<SBChunk>;
408
409 for (int i = 0; i < total_host_keys / host_keys_per_chunk; ++i) {
410 chunks->push_back(SBChunk());
411 chunks->back().chunk_number = ++chunk_id;
412
413 for (int j = 0; j < host_keys_per_chunk; ++j) {
414 SBChunkHost host;
[email protected]d9eb3c42008-12-12 12:00:40415 host.host = base::RandInt(std::numeric_limits<int>::min(),
416 std::numeric_limits<int>::max());
initial.commit09911bf2008-07-26 23:55:29417 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 2);
418 host.entry->SetPrefixAt(0, 0x2425525);
419 host.entry->SetPrefixAt(1, 0x1536366);
420
421 chunks->back().hosts.push_back(host);
422 }
423 }
424
[email protected]d9eb3c42008-12-12 12:00:40425 database->InsertChunks("goog-malware", chunks);
initial.commit09911bf2008-07-26 23:55:29426 }
427
428 void Read(bool use_bloom_filter) {
429 int keys_to_read = 500;
[email protected]d9eb3c42008-12-12 12:00:40430 file_util::EvictFileFromSystemCache(path_);
initial.commit09911bf2008-07-26 23:55:29431
[email protected]d9eb3c42008-12-12 12:00:40432 scoped_ptr<SafeBrowsingDatabase> database(SafeBrowsingDatabase::Create());
433 database->SetSynchronous();
[email protected]c870c762009-01-28 05:47:15434 EXPECT_TRUE(database->Init(path_, NULL));
initial.commit09911bf2008-07-26 23:55:29435
436 PerfTimer total_timer;
437 int64 db_ms = 0;
438 int keys_from_db = 0;
439 for (int i = 0; i < keys_to_read; ++i) {
[email protected]d9eb3c42008-12-12 12:00:40440 int key = base::RandInt(std::numeric_limits<int>::min(),
441 std::numeric_limits<int>::max());
initial.commit09911bf2008-07-26 23:55:29442
443 std::string url = StringPrintf("http://www.%d.com/blah.html", key);
444
445 std::string matching_list;
446 std::vector<SBPrefix> prefix_hits;
[email protected]d9eb3c42008-12-12 12:00:40447 std::vector<SBFullHashResult> full_hits;
initial.commit09911bf2008-07-26 23:55:29448 GURL gurl(url);
[email protected]d9eb3c42008-12-12 12:00:40449 if (!use_bloom_filter || database->NeedToCheckUrl(gurl)) {
initial.commit09911bf2008-07-26 23:55:29450 PerfTimer timer;
[email protected]d9eb3c42008-12-12 12:00:40451 database->ContainsUrl(gurl,
452 &matching_list,
453 &prefix_hits,
454 &full_hits,
455 base::Time::Now());
initial.commit09911bf2008-07-26 23:55:29456
457 int64 time_ms = timer.Elapsed().InMilliseconds();
458
459 DLOG(INFO) << "Read from db in " << time_ms << " ms.";
460
461 db_ms += time_ms;
462 keys_from_db++;
463 }
464 }
465
466 int64 total_ms = total_timer.Elapsed().InMilliseconds();
467
[email protected]5e207882009-01-05 23:59:36468 DLOG(INFO) << path_.BaseName().value() << " read " << keys_to_read <<
[email protected]d9eb3c42008-12-12 12:00:40469 " entries in " << total_ms << " ms. " << keys_from_db <<
470 " keys were read from the db, with average read taking " <<
initial.commit09911bf2008-07-26 23:55:29471 db_ms / keys_from_db << " ms";
472 }
473
474 void BuildBloomFilter() {
[email protected]d9eb3c42008-12-12 12:00:40475 file_util::EvictFileFromSystemCache(path_);
[email protected]c870c762009-01-28 05:47:15476 file_util::Delete(SafeBrowsingDatabase::BloomFilterFilename(path_), false);
initial.commit09911bf2008-07-26 23:55:29477
478 PerfTimer total_timer;
479
[email protected]d9eb3c42008-12-12 12:00:40480 scoped_ptr<SafeBrowsingDatabase> database(SafeBrowsingDatabase::Create());
481 database->SetSynchronous();
[email protected]c870c762009-01-28 05:47:15482 EXPECT_TRUE(database->Init(path_, NULL));
initial.commit09911bf2008-07-26 23:55:29483
484 int64 total_ms = total_timer.Elapsed().InMilliseconds();
485
[email protected]5e207882009-01-05 23:59:36486 DLOG(INFO) << path_.BaseName().value() <<
initial.commit09911bf2008-07-26 23:55:29487 " built bloom filter in " << total_ms << " ms.";
488 }
489
490 private:
[email protected]d9eb3c42008-12-12 12:00:40491 FilePath path_;
initial.commit09911bf2008-07-26 23:55:29492};
493
494// Adds 100K host records.
[email protected]d9eb3c42008-12-12 12:00:40495TEST(SafeBrowsingDatabase, DISABLED_FillUp100K) {
496 SafeBrowsingDatabaseTest db(FilePath(FILE_PATH_LITERAL("SafeBrowsing100K")));
initial.commit09911bf2008-07-26 23:55:29497 db.Create(100000);
498}
499
500// Adds 250K host records.
[email protected]d9eb3c42008-12-12 12:00:40501TEST(SafeBrowsingDatabase, DISABLED_FillUp250K) {
502 SafeBrowsingDatabaseTest db(FilePath(FILE_PATH_LITERAL("SafeBrowsing250K")));
initial.commit09911bf2008-07-26 23:55:29503 db.Create(250000);
504}
505
506// Adds 500K host records.
[email protected]d9eb3c42008-12-12 12:00:40507TEST(SafeBrowsingDatabase, DISABLED_FillUp500K) {
508 SafeBrowsingDatabaseTest db(FilePath(FILE_PATH_LITERAL("SafeBrowsing500K")));
initial.commit09911bf2008-07-26 23:55:29509 db.Create(500000);
510}
511
512// Reads 500 entries and prints the timing.
[email protected]d9eb3c42008-12-12 12:00:40513TEST(SafeBrowsingDatabase, DISABLED_ReadFrom250K) {
514 SafeBrowsingDatabaseTest db(FilePath(FILE_PATH_LITERAL("SafeBrowsing250K")));
initial.commit09911bf2008-07-26 23:55:29515 db.Read(false);
516}
517
[email protected]d9eb3c42008-12-12 12:00:40518TEST(SafeBrowsingDatabase, DISABLED_ReadFrom500K) {
519 SafeBrowsingDatabaseTest db(FilePath(FILE_PATH_LITERAL("SafeBrowsing500K")));
initial.commit09911bf2008-07-26 23:55:29520 db.Read(false);
521}
522
523// Read 500 entries with a bloom filter and print the timing.
[email protected]d9eb3c42008-12-12 12:00:40524TEST(SafeBrowsingDatabase, DISABLED_BloomReadFrom250K) {
525 SafeBrowsingDatabaseTest db(FilePath(FILE_PATH_LITERAL("SafeBrowsing250K")));
initial.commit09911bf2008-07-26 23:55:29526 db.Read(true);
527}
528
[email protected]d9eb3c42008-12-12 12:00:40529TEST(SafeBrowsingDatabase, DISABLED_BloomReadFrom500K) {
530 SafeBrowsingDatabaseTest db(FilePath(FILE_PATH_LITERAL("SafeBrowsing500K")));
initial.commit09911bf2008-07-26 23:55:29531 db.Read(true);
532}
533
534// Test how long bloom filter creation takes.
[email protected]d9eb3c42008-12-12 12:00:40535TEST(SafeBrowsingDatabase, DISABLED_BuildBloomFilter250K) {
536 SafeBrowsingDatabaseTest db(FilePath(FILE_PATH_LITERAL("SafeBrowsing250K")));
initial.commit09911bf2008-07-26 23:55:29537 db.BuildBloomFilter();
538}
539
[email protected]d9eb3c42008-12-12 12:00:40540TEST(SafeBrowsingDatabase, DISABLED_BuildBloomFilter500K) {
541 SafeBrowsingDatabaseTest db(FilePath(FILE_PATH_LITERAL("SafeBrowsing500K")));
initial.commit09911bf2008-07-26 23:55:29542 db.BuildBloomFilter();
543}