diff --git a/xapian-core/backends/chert/chert_database.cc b/xapian-core/backends/chert/chert_database.cc
index ff60d96..538554d 100644
|
a
|
b
|
ChertDatabase::set_revision_number(chert_revision_number_t new_revision)
|
| 472 | 472 | } |
| 473 | 473 | } |
| 474 | 474 | |
| | 475 | void |
| | 476 | ChertDatabase::request_document(Xapian::docid did) const |
| | 477 | { |
| | 478 | record_table.readahead_for_record(did); |
| | 479 | } |
| | 480 | |
| | 481 | void |
| | 482 | ChertDatabase::readahead_for_query(const Xapian::Query &query) |
| | 483 | { |
| | 484 | Xapian::TermIterator t; |
| | 485 | for (t = query.get_terms_begin(); t != Xapian::TermIterator(); ++t) { |
| | 486 | const string & term = *t; |
| | 487 | postlist_table.readahead_key(term); |
| | 488 | } |
| | 489 | } |
| | 490 | |
| 475 | 491 | bool |
| 476 | 492 | ChertDatabase::reopen() |
| 477 | 493 | { |
diff --git a/xapian-core/backends/chert/chert_database.h b/xapian-core/backends/chert/chert_database.h
index b7375d1..e405f05 100644
|
a
|
b
|
class ChertDatabase : public Xapian::Database::Internal {
|
| 298 | 298 | Xapian::ReplicationInfo * info); |
| 299 | 299 | string get_revision_info() const; |
| 300 | 300 | string get_uuid() const; |
| | 301 | |
| | 302 | void request_document(Xapian::docid /*did*/) const; |
| | 303 | void readahead_for_query(const Xapian::Query &query); |
| 301 | 304 | //@} |
| 302 | 305 | |
| 303 | 306 | XAPIAN_NORETURN(void throw_termlist_table_close_exception() const); |
diff --git a/xapian-core/backends/chert/chert_record.cc b/xapian-core/backends/chert/chert_record.cc
index 55ba264..000ec8d 100644
|
a
|
b
|
ChertRecordTable::get_doccount() const
|
| 66 | 66 | } |
| 67 | 67 | |
| 68 | 68 | void |
| | 69 | ChertRecordTable::readahead_for_record(Xapian::docid did) const |
| | 70 | { |
| | 71 | readahead_key(make_key(did)); |
| | 72 | } |
| | 73 | |
| | 74 | void |
| 69 | 75 | ChertRecordTable::replace_record(const string & data, Xapian::docid did) |
| 70 | 76 | { |
| 71 | 77 | LOGCALL_VOID(DB, "ChertRecordTable::replace_record", data | did); |
diff --git a/xapian-core/backends/chert/chert_record.h b/xapian-core/backends/chert/chert_record.h
index 0f6607d..8887031 100644
|
a
|
b
|
class ChertRecordTable : public ChertTable {
|
| 68 | 68 | /** Delete a record from the table. |
| 69 | 69 | */ |
| 70 | 70 | void delete_record(Xapian::docid did); |
| | 71 | |
| | 72 | void readahead_for_record(Xapian::docid did) const; |
| 71 | 73 | }; |
| 72 | 74 | |
| 73 | 75 | #endif /* OM_HGUARD_CHERT_RECORD_H */ |
diff --git a/xapian-core/backends/chert/chert_table.cc b/xapian-core/backends/chert/chert_table.cc
index a18bb5a..b603db3 100644
|
a
|
b
|
static inline byte *zeroed_new(size_t size)
|
| 167 | 167 | |
| 168 | 168 | #define BYTE_PAIR_RANGE (1 << 2 * CHAR_BIT) |
| 169 | 169 | |
| | 170 | void |
| | 171 | ChertTable::readahead_block(uint4 n) const |
| | 172 | { |
| | 173 | if (rare(handle == -2)) |
| | 174 | ChertTable::throw_database_closed(); |
| | 175 | |
| | 176 | /* Use the base bit_map_size not the bitmap's size, because |
| | 177 | * the latter is uninitialised in readonly mode. |
| | 178 | */ |
| | 179 | Assert(n / CHAR_BIT < base.get_bit_map_size()); |
| | 180 | |
| | 181 | io_readahead_block(handle, block_size, n); |
| | 182 | } |
| | 183 | |
| 170 | 184 | /// read_block(n, p) reads block n of the DB file to address p. |
| 171 | 185 | void |
| 172 | 186 | ChertTable::read_block(uint4 n, byte * p) const |
| … |
… |
ChertTable::del(const string &key)
|
| 1134 | 1148 | } |
| 1135 | 1149 | |
| 1136 | 1150 | bool |
| | 1151 | ChertTable::readahead_key(const string &key) const |
| | 1152 | { |
| | 1153 | LOGCALL(DB, bool, "ChertTable::readahead_key", key); |
| | 1154 | Assert(!key.empty()); |
| | 1155 | |
| | 1156 | form_key(key); |
| | 1157 | |
| | 1158 | const byte * p; |
| | 1159 | int c; |
| | 1160 | |
| | 1161 | Key ktkey = kt.key(); |
| | 1162 | |
| | 1163 | // We'll only readahead the first level, since descending the B-tree would |
| | 1164 | // require actual reads that would likely hurt performance more than help. |
| | 1165 | p = C[level].p; |
| | 1166 | c = find_in_block(p, ktkey, false, C[level].c); |
| | 1167 | uint4 n = Item(p, c).block_given_by(); |
| | 1168 | |
| | 1169 | readahead_block(n); |
| | 1170 | RETURN(true); |
| | 1171 | } |
| | 1172 | |
| | 1173 | bool |
| 1137 | 1174 | ChertTable::get_exact_entry(const string &key, string & tag) const |
| 1138 | 1175 | { |
| 1139 | 1176 | LOGCALL(DB, bool, "ChertTable::get_exact_entry", key | tag); |
diff --git a/xapian-core/backends/chert/chert_table.h b/xapian-core/backends/chert/chert_table.h
index 2ea61ec..f76a91f 100644
|
a
|
b
|
class XAPIAN_VISIBILITY_DEFAULT ChertTable {
|
| 334 | 334 | */ |
| 335 | 335 | void close(bool permanent=false); |
| 336 | 336 | |
| | 337 | bool readahead_key(const string &key) const; |
| | 338 | |
| 337 | 339 | /** Determine whether the btree exists on disk. |
| 338 | 340 | */ |
| 339 | 341 | bool exists() const; |
| … |
… |
class XAPIAN_VISIBILITY_DEFAULT ChertTable {
|
| 627 | 629 | bool find(Cursor *) const; |
| 628 | 630 | int delete_kt(); |
| 629 | 631 | void read_block(uint4 n, byte *p) const; |
| | 632 | void readahead_block(uint4 n) const; |
| 630 | 633 | void write_block(uint4 n, const byte *p) const; |
| 631 | 634 | XAPIAN_NORETURN(void set_overwritten() const); |
| 632 | 635 | void block_to_cursor(Cursor *C_, int j, uint4 n) const; |
diff --git a/xapian-core/backends/database.cc b/xapian-core/backends/database.cc
index e98b32a..a6153e1 100644
|
a
|
b
|
Database::Internal::keep_alive()
|
| 50 | 50 | } |
| 51 | 51 | |
| 52 | 52 | |
| | 53 | void |
| | 54 | Database::Internal::readahead_for_query (const Xapian::Query & query) |
| | 55 | { |
| | 56 | (void)query; |
| | 57 | } |
| | 58 | |
| 53 | 59 | Xapian::doccount |
| 54 | 60 | Database::Internal::get_value_freq(Xapian::valueno) const |
| 55 | 61 | { |
diff --git a/xapian-core/backends/database.h b/xapian-core/backends/database.h
index a0e7b43..372567d 100644
|
a
|
b
|
|
| 32 | 32 | #include "xapian/intrusive_ptr.h" |
| 33 | 33 | #include <xapian/types.h> |
| 34 | 34 | #include <xapian/database.h> |
| | 35 | #include <xapian/query.h> |
| 35 | 36 | #include <xapian/document.h> |
| 36 | 37 | #include <xapian/positioniterator.h> |
| 37 | 38 | #include <xapian/termiterator.h> |
| … |
… |
class Database::Internal : public Xapian::Internal::intrusive_base {
|
| 105 | 106 | */ |
| 106 | 107 | virtual void keep_alive(); |
| 107 | 108 | |
| | 109 | virtual void readahead_for_query (const Xapian::Query & query); |
| | 110 | |
| 108 | 111 | ////////////////////////////////////////////////////////////////// |
| 109 | 112 | // Database statistics: |
| 110 | 113 | // ==================== |
diff --git a/xapian-core/backends/glass/glass_database.cc b/xapian-core/backends/glass/glass_database.cc
index 32d7d20..6208be3 100644
|
a
|
b
|
GlassDatabase::set_revision_number(int flags, glass_revision_number_t new_revisi
|
| 347 | 347 | changes.commit(new_revision, flags); |
| 348 | 348 | } |
| 349 | 349 | |
| | 350 | void |
| | 351 | GlassDatabase::request_document(Xapian::docid did) const |
| | 352 | { |
| | 353 | docdata_table.readahead_for_document(did); |
| | 354 | } |
| | 355 | |
| | 356 | void |
| | 357 | GlassDatabase::readahead_for_query(const Xapian::Query &query) |
| | 358 | { |
| | 359 | Xapian::TermIterator t; |
| | 360 | for (t = query.get_terms_begin(); t != Xapian::TermIterator(); ++t) { |
| | 361 | const string & term = *t; |
| | 362 | postlist_table.readahead_key(term); |
| | 363 | } |
| | 364 | } |
| | 365 | |
| 350 | 366 | bool |
| 351 | 367 | GlassDatabase::reopen() |
| 352 | 368 | { |
diff --git a/xapian-core/backends/glass/glass_database.h b/xapian-core/backends/glass/glass_database.h
index 0f1fedd..d8dc53e 100644
|
a
|
b
|
class GlassDatabase : public Xapian::Database::Internal {
|
| 286 | 286 | Xapian::ReplicationInfo * info); |
| 287 | 287 | string get_revision_info() const; |
| 288 | 288 | string get_uuid() const; |
| | 289 | |
| | 290 | void request_document(Xapian::docid /*did*/) const; |
| | 291 | void readahead_for_query(const Xapian::Query &query); |
| 289 | 292 | //@} |
| 290 | 293 | |
| 291 | 294 | XAPIAN_NORETURN(void throw_termlist_table_close_exception() const); |
diff --git a/xapian-core/backends/glass/glass_docdata.h b/xapian-core/backends/glass/glass_docdata.h
index 4fbf57a..6e0fbc1 100644
|
a
|
b
|
class GlassDocDataTable : public GlassLazyTable {
|
| 99 | 99 | * there's no such document, or the document has no data). |
| 100 | 100 | */ |
| 101 | 101 | bool delete_document_data(Xapian::docid did) { return del(make_key(did)); } |
| | 102 | |
| | 103 | void readahead_for_document(Xapian::docid did) const { |
| | 104 | readahead_key(make_key(did)); |
| | 105 | } |
| 102 | 106 | }; |
| 103 | 107 | |
| 104 | 108 | #endif // XAPIAN_INCLUDED_GLASS_DOCDATA_H |
diff --git a/xapian-core/backends/glass/glass_table.cc b/xapian-core/backends/glass/glass_table.cc
index d90f869..2b9bc02 100644
|
a
|
b
|
GlassTable::del(const string &key)
|
| 1153 | 1153 | RETURN(true); |
| 1154 | 1154 | } |
| 1155 | 1155 | |
| | 1156 | void |
| | 1157 | GlassTable::readahead_block(uint4 n) const |
| | 1158 | { |
| | 1159 | if (rare(handle == -2)) |
| | 1160 | GlassTable::throw_database_closed(); |
| | 1161 | |
| | 1162 | /* Use the base bit_map_size not the bitmap's size, because |
| | 1163 | * the latter is uninitialised in readonly mode. |
| | 1164 | */ |
| | 1165 | Assert(n / CHAR_BIT < base.get_bit_map_size()); |
| | 1166 | |
| | 1167 | io_readahead_block(handle, block_size, n); |
| | 1168 | } |
| | 1169 | |
| | 1170 | bool |
| | 1171 | GlassTable::readahead_key(const string &key) const |
| | 1172 | { |
| | 1173 | LOGCALL(DB, bool, "GlassTable::readahead_key", key); |
| | 1174 | Assert(!key.empty()); |
| | 1175 | |
| | 1176 | form_key(key); |
| | 1177 | |
| | 1178 | const byte * p; |
| | 1179 | int c; |
| | 1180 | |
| | 1181 | Key ktkey = kt.key(); |
| | 1182 | |
| | 1183 | // We'll only readahead the first level, since descending the B-tree would |
| | 1184 | // require actual reads that would likely hurt performance more than help. |
| | 1185 | p = C[level].get_p(); |
| | 1186 | c = find_in_block(p, ktkey, false, C[level].c); |
| | 1187 | uint4 n = Item(p, c).block_given_by(); |
| | 1188 | |
| | 1189 | readahead_block(n); |
| | 1190 | RETURN(true); |
| | 1191 | } |
| | 1192 | |
| 1156 | 1193 | bool |
| 1157 | 1194 | GlassTable::get_exact_entry(const string &key, string & tag) const |
| 1158 | 1195 | { |
diff --git a/xapian-core/backends/glass/glass_table.h b/xapian-core/backends/glass/glass_table.h
index c9b2282..fe42637 100644
|
a
|
b
|
class GlassTable {
|
| 346 | 346 | */ |
| 347 | 347 | void close(bool permanent=false); |
| 348 | 348 | |
| | 349 | bool readahead_key(const string &key) const; |
| | 350 | |
| 349 | 351 | /** Determine whether the btree exists on disk. |
| 350 | 352 | */ |
| 351 | 353 | bool exists() const; |
| … |
… |
class GlassTable {
|
| 604 | 606 | bool find(Glass::Cursor *) const; |
| 605 | 607 | int delete_kt(); |
| 606 | 608 | void read_block(uint4 n, byte *p) const; |
| | 609 | void readahead_block(uint4 n) const; |
| 607 | 610 | void write_block(uint4 n, const byte *p, bool appending = false) const; |
| 608 | 611 | XAPIAN_NORETURN(void set_overwritten() const); |
| 609 | 612 | void block_to_cursor(Glass::Cursor *C_, int j, uint4 n) const; |
diff --git a/xapian-core/common/io_utils.cc b/xapian-core/common/io_utils.cc
index fefef8e..55ecc5d 100644
|
a
|
b
|
throw_block_error(const char * s, off_t b, int e)
|
| 105 | 105 | } |
| 106 | 106 | |
| 107 | 107 | void |
| | 108 | io_readahead_block(int fd, size_t n, off_t b) |
| | 109 | { |
| | 110 | #ifdef HAVE_POSIX_FADVISE |
| | 111 | off_t o = b * n; |
| | 112 | posix_fadvise(fd, o, n, POSIX_FADV_WILLNEED); |
| | 113 | #endif |
| | 114 | } |
| | 115 | |
| | 116 | void |
| 108 | 117 | io_read_block(int fd, char * p, size_t n, off_t b) |
| 109 | 118 | { |
| 110 | 119 | off_t o = b * n; |
diff --git a/xapian-core/common/io_utils.h b/xapian-core/common/io_utils.h
index 89d5d46..8b470ef 100644
|
a
|
b
|
inline void io_write(int fd, const unsigned char * p, size_t n) {
|
| 82 | 82 | io_write(fd, reinterpret_cast<const char *>(p), n); |
| 83 | 83 | } |
| 84 | 84 | |
| | 85 | /// Readahead block b size n bytes from file descriptor fd |
| | 86 | void io_readahead_block(int fd, size_t n, off_t b); |
| | 87 | |
| 85 | 88 | /// Read block b size n bytes into buffer p from file descriptor fd. |
| 86 | 89 | void io_read_block(int fd, char * p, size_t n, off_t b); |
| 87 | 90 | |
diff --git a/xapian-core/configure.ac b/xapian-core/configure.ac
index 1ab4694..edb03bf 100644
|
a
|
b
|
AC_CHECK_DECL([fdatasync(int)], [
|
| 912 | 912 | ) |
| 913 | 913 | |
| 914 | 914 | AC_CHECK_FUNCS([fsync]) |
| | 915 | AC_CHECK_FUNCS([posix_fadvise]) |
| 915 | 916 | |
| 916 | 917 | dnl HP-UX has pread and pwrite, but they don't work! Apparently this problem |
| 917 | 918 | dnl manifests when largefile support is enabled, and we definitely want that |
diff --git a/xapian-core/matcher/multimatch.cc b/xapian-core/matcher/multimatch.cc
index ef8525e..cb71e7e 100644
|
a
|
b
|
MultiMatch::MultiMatch(const Xapian::Database &db_,
|
| 332 | 332 | is_remote[i] = true; |
| 333 | 333 | } else { |
| 334 | 334 | smatch = new LocalSubMatch(subdb, query, qlen, subrsets[i], weight); |
| | 335 | subdb->readahead_for_query(query); |
| 335 | 336 | } |
| 336 | 337 | #else |
| 337 | 338 | // Avoid unused parameter warnings. |