Ticket #250: patch_kan_ru_4.patch

File patch_kan_ru_4.patch, 8.9 KB (added by Richard Boulton, 14 years ago)

Updated version of the patch, which applies to SVN head, and passes all the newly added tests.

  • backends/flint/flint_database.cc

     
    66 * Copyright 2002,2003,2004,2005,2006,2007,2008,2009 Olly Betts
    77 * Copyright 2006,2008 Lemur Consulting Ltd
    88 * Copyright 2009 Richard Boulton
     9 * Copyright 2009 Kan-Ru Chen
    910 *
    1011 * This program is free software; you can redistribute it and/or
    1112 * modify it under the terms of the GNU General Public License as
     
    12521253    }
    12531254}
    12541255
     1256/** Compare the positionlists for a term iterator and a termlist.
     1257 *
     1258 *  @return true if they're equal, false otherwise.
     1259 */
     1260static bool positionlists_equal(Xapian::TermIterator & termiter,
     1261                                FlintTermList & termlist)
     1262{
     1263    int new_count = termiter.positionlist_count();
     1264    int old_count = termlist.positionlist_count();
     1265    if (old_count != new_count)
     1266        return false;
     1267
     1268    PositionIterator it = termiter.positionlist_begin();
     1269    PositionIterator it_end = termiter.positionlist_end();
     1270    PositionIterator old = termlist.positionlist_begin();
     1271    return equal(it, it_end, old);
     1272}
     1273
    12551274void
    12561275FlintWritableDatabase::replace_document(Xapian::docid did,
    12571276                                        const Xapian::Document & document)
     
    12931312        }
    12941313 
    12951314        if (!modifying || document.internal->terms_modified()) {
    1296             // FIXME - in the case where there is overlap between the new
    1297             // termlist and the old termlist, it would be better to compare the
    1298             // two lists, and make the minimum set of modifications required.
    1299             // This would lead to smaller changesets for replication, and
    1300             // probably be faster overall.
    1301 
    1302             // First, add entries to remove the postings in the underlying record.
    13031315            Xapian::Internal::RefCntPtr<const FlintWritableDatabase> ptrtothis(this);
    13041316            FlintTermList termlist(ptrtothis, did);
    13051317            Xapian::TermIterator term = document.termlist_begin();
     1318            Xapian::TermIterator term_end = document.termlist_end();
     1319            flint_doclen_t new_doclen = termlist.get_doclength();
     1320            string old_tname, new_tname;
     1321 
     1322            total_length -= new_doclen;
    13061323
    13071324            termlist.next();
    1308             while (!termlist.at_end()) {
    1309                 string tname = termlist.get_termname();
    1310                 termcount wdf = termlist.get_wdf();
     1325            while (!termlist.at_end() || term != term_end) {
     1326                int cmp;
     1327                if (!termlist.at_end() && term != term_end) {
     1328                    old_tname = termlist.get_termname();
     1329                    new_tname = *term;
     1330                    cmp = old_tname.compare(new_tname);
    13111331
    1312                 map<string, pair<termcount_diff, termcount_diff> >::iterator i;
    1313                 i = freq_deltas.find(tname);
    1314                 if (i == freq_deltas.end()) {
    1315                     freq_deltas.insert(make_pair(tname, make_pair(-1, -termcount_diff(wdf))));
     1332                } else if (termlist.at_end()) {
     1333                    cmp = 1;
     1334                    new_tname = *term;
    13161335                } else {
    1317                     --i->second.first;
    1318                     i->second.second -= wdf;
     1336                    cmp = -1;
     1337                    old_tname = termlist.get_termname();
    13191338                }
    13201339
    1321                 // Remove did from tname's postlist
    1322                 map<string, map<docid, pair<char, termcount> > >::iterator j;
    1323                 j = mod_plists.find(tname);
    1324                 if (j == mod_plists.end()) {
    1325                     map<docid, pair<char, termcount> > m;
    1326                     j = mod_plists.insert(make_pair(tname, m)).first;
    1327                 }
     1340                if (cmp < 0) {
     1341                    // Term old_tname has been deleted.
     1342                    const string& tname = old_tname;
     1343                    termcount old_wdf = termlist.get_wdf();
     1344                    new_doclen -= old_wdf;
    13281345
    1329                 map<docid, pair<char, termcount> >::iterator k;
    1330                 k = j->second.find(did);
    1331                 if (k == j->second.end()) {
    1332                     j->second.insert(make_pair(did, make_pair('D', 0u)));
    1333                 } else {
    1334                     // Modifying a document we added/modified since the last flush.
    1335                     k->second = make_pair('D', 0u);
    1336                 }
     1346                    map<string, pair<termcount_diff, termcount_diff> >::iterator i;
     1347                    i = freq_deltas.find(tname);
     1348                    if (i == freq_deltas.end()) {
     1349                        freq_deltas.insert(make_pair(tname, make_pair(-1, -termcount_diff(old_wdf))));
     1350                    } else {
     1351                        --i->second.first;
     1352                        i->second.second -= old_wdf;
     1353                    }
    13371354
    1338                 term.skip_to(tname);
    1339                 if (term == document.termlist_end() || *term != tname) {
    13401355                    position_table.delete_positionlist(did, tname);
    1341                 }
    13421356
    1343                 termlist.next();
    1344             }
     1357                    // Remove did from tname's postlist
     1358                    map<string, map<docid, pair<char, termcount> > >::iterator j;
     1359                    j = mod_plists.find(tname);
     1360                    if (j == mod_plists.end()) {
     1361                        map<docid, pair<char, termcount> > m;
     1362                        j = mod_plists.insert(make_pair(tname, m)).first;
     1363                    }
    13451364
    1346             total_length -= termlist.get_doclength();
     1365                    map<docid, pair<char, termcount> >::iterator k;
     1366                    k = j->second.find(did);
     1367                    if (k == j->second.end()) {
     1368                        j->second.insert(make_pair(did, make_pair('D', 0u)));
     1369                    } else {
     1370                        // Modifying a document we added/modified since the last flush.
     1371                        k->second = make_pair('D', 0u);
     1372                    }
     1373                } else if (cmp != 0) {
     1374                    // Term new_tname as been added.
     1375                    const string& tname = new_tname;
     1376                    termcount new_wdf = term.get_wdf();
     1377                    new_doclen += new_wdf;
    13471378
    1348             flint_doclen_t new_doclen = 0;
    1349             for (term = document.termlist_begin();
    1350                  term != document.termlist_end(); ++term) {
    1351                 // Calculate the new document length
    1352                 termcount wdf = term.get_wdf();
    1353                 new_doclen += wdf;
     1379                    if (tname.size() > MAX_SAFE_TERM_LENGTH)
     1380                        throw Xapian::InvalidArgumentError("Term too long (> "STRINGIZE(MAX_SAFE_TERM_LENGTH)"): " + tname);
     1381                    map<string, pair<termcount_diff, termcount_diff> >::iterator i;
     1382                    i = freq_deltas.find(tname);
     1383                    if (i == freq_deltas.end()) {
     1384                        freq_deltas.insert(make_pair(tname, make_pair(1, termcount_diff(new_wdf))));
     1385                    } else {
     1386                        ++i->second.first;
     1387                        i->second.second += new_wdf;
     1388                    }
    13541389
    1355                 string tname = *term;
    1356                 if (tname.size() > MAX_SAFE_TERM_LENGTH)
    1357                     throw Xapian::InvalidArgumentError("Term too long (> "STRINGIZE(MAX_SAFE_TERM_LENGTH)"): " + tname);
    1358                 map<string, pair<termcount_diff, termcount_diff> >::iterator i;
    1359                 i = freq_deltas.find(tname);
    1360                 if (i == freq_deltas.end()) {
    1361                     freq_deltas.insert(make_pair(tname, make_pair(1, termcount_diff(wdf))));
    1362                 } else {
    1363                     ++i->second.first;
    1364                     i->second.second += wdf;
    1365                 }
     1390                    // Add did to tname's postlist
     1391                    map<string, map<docid, pair<char, termcount> > >::iterator j;
     1392                    j = mod_plists.find(tname);
     1393                    if (j == mod_plists.end()) {
     1394                        map<docid, pair<char, termcount> > m;
     1395                        j = mod_plists.insert(make_pair(tname, m)).first;
     1396                    }
     1397                    map<docid, pair<char, termcount> >::iterator k;
     1398                    k = j->second.find(did);
     1399                    if (k != j->second.end()) {
     1400                        Assert(k->second.first == 'D');
     1401                        k->second.first = 'M';
     1402                        k->second.second = new_wdf;
     1403                    } else {
     1404                        j->second.insert(make_pair(did, make_pair('A', new_wdf)));
     1405                    }
    13661406
    1367                 // Add did to tname's postlist
    1368                 map<string, map<docid, pair<char, termcount> > >::iterator j;
    1369                 j = mod_plists.find(tname);
    1370                 if (j == mod_plists.end()) {
    1371                     map<docid, pair<char, termcount> > m;
    1372                     j = mod_plists.insert(make_pair(tname, m)).first;
     1407                    PositionIterator it = term.positionlist_begin();
     1408                    PositionIterator it_end = term.positionlist_end();
     1409                    if (it != it_end) {
     1410                        position_table.set_positionlist(did, tname, it, it_end);
     1411                    } else {
     1412                        position_table.delete_positionlist(did, tname);
     1413                    }
     1414                } else if (cmp == 0) {
     1415                    // Term already exists: look for wdf and positionlist changes.
     1416                    termcount old_wdf = termlist.get_wdf();
     1417                    termcount new_wdf = term.get_wdf();
     1418                    if (old_wdf != new_wdf) {
     1419                        new_doclen += new_wdf - old_wdf;
     1420
     1421                        map<string, pair<termcount_diff, termcount_diff> >::iterator i;
     1422                        i = freq_deltas.find(new_tname);
     1423                        if (i == freq_deltas.end()) {
     1424                            freq_deltas.insert(make_pair(new_tname, make_pair(0, termcount_diff(new_wdf - old_wdf))));
     1425                        } else {
     1426                            i->second.second += new_wdf - old_wdf;
     1427                        }
     1428                    }
     1429
     1430                    if (!positionlists_equal(term, termlist)) {
     1431                        PositionIterator it = term.positionlist_begin();
     1432                        PositionIterator it_end = term.positionlist_end();
     1433                        if (it != it_end) {
     1434                            position_table.set_positionlist(did, new_tname, it, it_end);
     1435                        } else {
     1436                            position_table.delete_positionlist(did, new_tname);
     1437                        }
     1438                    }
    13731439                }
    1374                 map<docid, pair<char, termcount> >::iterator k;
    1375                 k = j->second.find(did);
    1376                 if (k != j->second.end()) {
    1377                     Assert(k->second.first == 'D');
    1378                     k->second.first = 'M';
    1379                     k->second.second = wdf;
    1380                 } else {
    1381                     j->second.insert(make_pair(did, make_pair('A', wdf)));
    1382                 }
    13831440
    1384                 PositionIterator it = term.positionlist_begin();
    1385                 PositionIterator it_end = term.positionlist_end();
    1386                 if (it != it_end) {
    1387                     position_table.set_positionlist(did, tname, it, it_end);
    1388                 } else {
    1389                     position_table.delete_positionlist(did, tname);
    1390                 }
     1441                if (termlist.at_end())
     1442                    ++term;
     1443                else if (term == term_end)
     1444                    termlist.next();
     1445                else {
     1446                    if (cmp >= 0)
     1447                        ++term;
     1448                    if (cmp <= 0)
     1449                        termlist.next();
     1450
     1451                }
    13911452            }
    13921453            LOGLINE(DB, "Calculated doclen for replacement document " << did << " as " << new_doclen);
    13931454