00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include "brass_cursor.h"
00025
00026 #include "safeerrno.h"
00027
00028 #include <xapian/error.h>
00029
00030 #include "brass_table.h"
00031 #include "debuglog.h"
00032 #include "omassert.h"
00033
00034 using namespace Brass;
00035
00036 #ifdef XAPIAN_DEBUG_LOG
00037 static string
00038 hex_display_encode(const string & input)
00039 {
00040 const char * table = "0123456789abcdef";
00041 string result;
00042 for (string::const_iterator i = input.begin(); i != input.end(); ++i) {
00043 unsigned char val = *i;
00044 result += "\\x";
00045 result += table[val/16];
00046 result += table[val%16];
00047 }
00048
00049 return result;
00050 }
00051 #endif
00052
00053 #define DIR_START 11
00054
00055 BrassCursor::BrassCursor(const BrassTable *B_)
00056 : is_positioned(false),
00057 is_after_end(false),
00058 tag_status(UNREAD),
00059 B(B_),
00060 version(B_->cursor_version),
00061 level(B_->level)
00062 {
00063 B->cursor_created_since_last_modification = true;
00064 C = new Brass::Cursor[level + 1];
00065
00066 for (int j = 0; j < level; j++) {
00067 C[j].n = BLK_UNUSED;
00068 C[j].p = new byte[B->block_size];
00069 }
00070 C[level].n = B->C[level].n;
00071 C[level].p = B->C[level].p;
00072 }
00073
00074 void
00075 BrassCursor::rebuild()
00076 {
00077 int new_level = B->level;
00078 if (new_level <= level) {
00079 for (int i = 0; i < new_level; i++) {
00080 C[i].n = BLK_UNUSED;
00081 }
00082 for (int j = new_level; j < level; ++j) {
00083 delete C[j].p;
00084 }
00085 } else {
00086 Cursor * old_C = C;
00087 C = new Cursor[new_level + 1];
00088 for (int i = 0; i < level; i++) {
00089 C[i].p = old_C[i].p;
00090 C[i].n = BLK_UNUSED;
00091 }
00092 delete old_C;
00093 for (int j = level; j < new_level; j++) {
00094 C[j].p = new byte[B->block_size];
00095 C[j].n = BLK_UNUSED;
00096 }
00097 }
00098 level = new_level;
00099 C[level].n = B->C[level].n;
00100 C[level].p = B->C[level].p;
00101 version = B->cursor_version;
00102 }
00103
00104 BrassCursor::~BrassCursor()
00105 {
00106
00107
00108 for (int j = 0; j < level; j++) {
00109 delete [] C[j].p;
00110 }
00111 delete [] C;
00112 }
00113
00114 bool
00115 BrassCursor::prev()
00116 {
00117 LOGCALL(DB, bool, "BrassCursor::prev", NO_ARGS);
00118 Assert(!is_after_end);
00119 if (B->cursor_version != version || !is_positioned) {
00120
00121
00122
00123
00124
00125 if (!find_entry(current_key)) {
00126
00127
00128 RETURN(true);
00129 }
00130 } else if (tag_status != UNREAD) {
00131 while (true) {
00132 if (! B->prev(C, 0)) {
00133 is_positioned = false;
00134 RETURN(false);
00135 }
00136 if (Item(C[0].p, C[0].c).component_of() == 1) {
00137 break;
00138 }
00139 }
00140 }
00141
00142 while (true) {
00143 if (! B->prev(C, 0)) {
00144 is_positioned = false;
00145 RETURN(false);
00146 }
00147 if (Item(C[0].p, C[0].c).component_of() == 1) {
00148 break;
00149 }
00150 }
00151 get_key(¤t_key);
00152 tag_status = UNREAD;
00153
00154 LOGLINE(DB, "Moved to entry: key=" << hex_display_encode(current_key));
00155 RETURN(true);
00156 }
00157
00158 bool
00159 BrassCursor::next()
00160 {
00161 LOGCALL(DB, bool, "BrassCursor::next", NO_ARGS);
00162 Assert(!is_after_end);
00163 if (B->cursor_version != version) {
00164
00165 (void)find_entry(current_key);
00166
00167
00168
00169 }
00170 if (tag_status == UNREAD) {
00171 while (true) {
00172 if (! B->next(C, 0)) {
00173 is_positioned = false;
00174 break;
00175 }
00176 if (Item(C[0].p, C[0].c).component_of() == 1) {
00177 is_positioned = true;
00178 break;
00179 }
00180 }
00181 }
00182
00183 if (!is_positioned) {
00184 is_after_end = true;
00185 RETURN(false);
00186 }
00187
00188 get_key(¤t_key);
00189 tag_status = UNREAD;
00190
00191 LOGLINE(DB, "Moved to entry: key=" << hex_display_encode(current_key));
00192 RETURN(true);
00193 }
00194
00195 bool
00196 BrassCursor::find_entry(const string &key)
00197 {
00198 LOGCALL(DB, bool, "BrassCursor::find_entry", key);
00199 if (B->cursor_version != version) {
00200 rebuild();
00201 }
00202
00203 is_after_end = false;
00204
00205 bool found;
00206
00207 is_positioned = true;
00208 if (key.size() > BRASS_BTREE_MAX_KEY_LEN) {
00209
00210
00211 B->form_key(key.substr(0, BRASS_BTREE_MAX_KEY_LEN));
00212 (void)(B->find(C));
00213 found = false;
00214 } else {
00215 B->form_key(key);
00216 found = B->find(C);
00217 }
00218
00219 if (!found) {
00220 if (C[0].c < DIR_START) {
00221 C[0].c = DIR_START;
00222 if (! B->prev(C, 0)) goto done;
00223 }
00224 while (Item(C[0].p, C[0].c).component_of() != 1) {
00225 if (! B->prev(C, 0)) {
00226 is_positioned = false;
00227 throw Xapian::DatabaseCorruptError("find_entry failed to find any entry at all!");
00228 }
00229 }
00230 }
00231 done:
00232
00233 if (found)
00234 current_key = key;
00235 else
00236 get_key(¤t_key);
00237 tag_status = UNREAD;
00238
00239 LOGLINE(DB, "Found entry: key=" << hex_display_encode(current_key));
00240 RETURN(found);
00241 }
00242
00243 bool
00244 BrassCursor::find_entry_ge(const string &key)
00245 {
00246 LOGCALL(DB, bool, "BrassCursor::find_entry_ge", key);
00247 if (B->cursor_version != version) {
00248 rebuild();
00249 }
00250
00251 is_after_end = false;
00252
00253 bool found;
00254
00255 is_positioned = true;
00256 if (key.size() > BRASS_BTREE_MAX_KEY_LEN) {
00257
00258
00259 B->form_key(key.substr(0, BRASS_BTREE_MAX_KEY_LEN));
00260 (void)(B->find(C));
00261 found = false;
00262 } else {
00263 B->form_key(key);
00264 found = B->find(C);
00265 }
00266
00267 if (found) {
00268 current_key = key;
00269 } else {
00270 if (! B->next(C, 0)) {
00271 is_after_end = true;
00272 is_positioned = false;
00273 RETURN(false);
00274 }
00275 Assert(Item(C[0].p, C[0].c).component_of() == 1);
00276 get_key(¤t_key);
00277 }
00278 tag_status = UNREAD;
00279
00280 LOGLINE(DB, "Found entry: key=" << hex_display_encode(current_key));
00281 RETURN(found);
00282 }
00283
00284 void
00285 BrassCursor::get_key(string * key) const
00286 {
00287 Assert(B->level <= level);
00288 Assert(is_positioned);
00289
00290 (void)Item(C[0].p, C[0].c).key().read(key);
00291 }
00292
00293 bool
00294 BrassCursor::read_tag(bool keep_compressed)
00295 {
00296 LOGCALL(DB, bool, "BrassCursor::read_tag", keep_compressed);
00297 if (tag_status == UNREAD) {
00298 Assert(B->level <= level);
00299 Assert(is_positioned);
00300
00301 if (B->read_tag(C, ¤t_tag, keep_compressed)) {
00302 tag_status = COMPRESSED;
00303 } else {
00304 tag_status = UNCOMPRESSED;
00305 }
00306
00307
00308
00309 is_positioned = B->next(C, 0);
00310
00311 LOGLINE(DB, "tag=" << hex_display_encode(current_tag));
00312 }
00313 RETURN(tag_status == COMPRESSED);
00314 }
00315
00316 bool
00317 MutableBrassCursor::del()
00318 {
00319 Assert(!is_after_end);
00320
00321
00322
00323
00324
00325 (const_cast<BrassTable*>(B))->del(current_key);
00326
00327
00328
00329
00330
00331
00332 if (!find_entry_ge(current_key)) return is_positioned;
00333 return next();
00334 }