# # patch "cvs_sync.cc" # from [a8c9f9c9b16162f891803e3b692f8784727c4975] # to [2464d951fb80346171e624491eba30d71dbc0d74] # # patch "piece_table.cc" # from [53950e7fe2e4a2cf12bcecd3e75280ed36209c94] # to [8bb9dfd41386acc9d24c8ead00505113754c2e56] # # patch "piece_table.hh" # from [beb63ff93407222a2e23a24d16780b02dd267dba] # to [72c9cc30b6b72cafa50e1b93672e7cb550009445] # ======================================================================== --- cvs_sync.cc a8c9f9c9b16162f891803e3b692f8784727c4975 +++ cvs_sync.cc 2464d951fb80346171e624491eba30d71dbc0d74 @@ -14,6 +14,7 @@ #include #include #include "stringtok.hh" +#include "piece_table.hh" #ifdef WIN32 #define sleep(x) _sleep(x) @@ -24,39 +25,8 @@ // since the piece methods in rcs_import depend on rcs_file I cannot reuse them // I rely on string handling reference counting (which is not that bad IIRC) // -> investigate under which conditions a string gets copied -namespace cvs_sync -{ static std::string const cvs_cert_name="cvs-revisions"; -struct -piece -{ - piece(string::size_type p, string::size_type l, const std::string &_s) : - pos(p), len(l), s(_s) {} - string::size_type pos; - string::size_type len; - string s; - const string operator*() const - { return s.substr(pos,len); } -}; - - -static void -index_deltatext(std::string const & dt, vector & pieces); -static void -process_one_hunk(vector< piece > const & source, - vector< piece > & dest, - vector< piece >::const_iterator & i, - int & cursor); -static void -build_string(vector const & pieces, string & out); -static void -construct_version(vector< piece > const & source_lines, - vector< piece > & dest_lines, - string const & deltatext); - -} - using namespace cvs_sync; bool file_state::operator<(const file_state &b) const @@ -80,103 +50,6 @@ (s.author==e.author && s.log_msg<=e.changelog))); } -static void -cvs_sync::process_one_hunk(vector< piece > const & source, - vector< piece > & dest, - vector< piece >::const_iterator & i, - int & cursor) -{ - string directive = **i; - assert(directive.size() > 1); - ++i; - - try - { - char code; - int pos, len; - if (sscanf(directive.c_str(), " %c %d %d", &code, &pos, &len) != 3) - throw oops("illformed directive '" + directive + "'"); - - if (code == 'a') - { - // 'ax y' means "copy from source to dest until cursor == x, then - // copy y lines from delta, leaving cursor where it is" - while (cursor < pos) - dest.push_back(source.at(cursor++)); - I(cursor == pos); - while (len--) - dest.push_back(*i++); - } - else if (code == 'd') - { - // 'dx y' means "copy from source to dest until cursor == x-1, - // then increment cursor by y, ignoring those y lines" - while (cursor < (pos - 1)) - dest.push_back(source.at(cursor++)); - I(cursor == pos - 1); - cursor += len; - } - else - E(false,F("unknown directive '%s'\n") % directive); - } - catch (std::out_of_range & oor) - { - E(false, F("out_of_range while processing '%s' with source.size() == %d and cursor == %d") - % directive % source.size() % cursor); - } -} - -static void -cvs_sync::build_string(vector const & pieces, string & out) -{ - out.clear(); - out.reserve(pieces.size() * 60); - for(vector::const_iterator i = pieces.begin(); - i != pieces.end(); ++i) - out.append(i->s, i->pos, i->len); -} - -static void -cvs_sync::index_deltatext(std::string const & dt, vector & pieces) -{ - pieces.clear(); - pieces.reserve(dt.size() / 30); - string::size_type begin = 0; - string::size_type end = dt.find('\n'); - while(end != string::npos) - { - // nb: the piece includes the '\n' - pieces.push_back(piece(begin, (end - begin) + 1, dt)); - begin = end + 1; - end = dt.find('\n', begin); - } - if (begin != dt.size()) - { - // the text didn't end with '\n', so neither does the piece - end = dt.size(); - pieces.push_back(piece(begin, end - begin, dt)); - } -} - -static void -cvs_sync::construct_version(vector< piece > const & source_lines, - vector< piece > & dest_lines, - string const & deltatext) -{ - dest_lines.clear(); - dest_lines.reserve(source_lines.size()); - - vector deltalines; - index_deltatext(deltatext, deltalines); - - int cursor = 0; - for (vector::const_iterator i = deltalines.begin(); - i != deltalines.end(); ) - process_one_hunk(source_lines, dest_lines, i, cursor); - while (cursor < static_cast(source_lines.size())) - dest_lines.push_back(source_lines[cursor++]); -} - /* supported by the woody version: Root Valid-responses valid-requests Repository Directory Max-dotdot Static-directory Sticky Checkin-prog Update-prog Entry Kopt Checkin-time @@ -479,9 +352,9 @@ } } -static void apply_delta(vector &contents, const std::string &patch) -{ vector after; - construct_version(contents,after,patch); +static void apply_delta(piece::piece_table &contents, const std::string &patch) +{ piece::piece_table after; + piece::apply_diff(contents,after,patch); std::swap(contents,after); } @@ -622,10 +495,11 @@ { W(F("update time %ld and log time %ld disagree\n") % u.mod_time % s2->since_when); } std::string old_contents=contents; - { std::vector file_contents; - index_deltatext(contents,file_contents); + { piece::piece_table file_contents; + piece::index_deltatext(contents,file_contents); apply_delta(file_contents, u.patch); - build_string(file_contents, contents); + piece::build_string(file_contents, contents); + piece::reset(); } // check md5 Botan::MD5 hash; @@ -1448,16 +1322,16 @@ ++(*cert_ticker); cvs_edge e(i->inner().ident,app); - std::vector pieces; + piece::piece_table pieces; // in Zeilen aufteilen - index_deltatext(cvs_revisions(),pieces); + piece::index_deltatext(cvs_revisions(),pieces); I(!pieces.empty()); manifest_id mid; app.db.get_revision_manifest(i->inner().ident,mid); manifest_map manifest; app.db.get_manifest(mid,manifest); // manifest; - std::vector::const_iterator p=pieces.begin()+1; + piece::piece_table::const_iterator p=pieces.begin()+1; if ((**p)[0]=='+') // this is a delta encoded manifest { hexenc h=(**p).substr(1,40); // remember to omit the trailing \n e.delta_base=revision_id(h); @@ -1502,6 +1376,7 @@ e.xfiles.insert(std::make_pair(path,cfs)); } } + piece::reset(); revision_lookup[e.revision]=edges.insert(e).first; } else L(F("cvs cert %s ignored (!=%s)") % cvs_revisions % needed_cert); @@ -1930,10 +1805,10 @@ app.db.get_var(key,value); } catch (logic_error &e) { return; } std::map sd; - std::vector pieces; + piece::piece_table pieces; std::string value_s=value(); - index_deltatext(value_s,pieces); - for (std::vector::const_iterator p=pieces.begin();p!=pieces.end();++p) + piece::index_deltatext(value_s,pieces); + for (piece::piece_table::const_iterator p=pieces.begin();p!=pieces.end();++p) { std::string line=**p; MM(line); I(!line.empty()); @@ -1943,5 +1818,6 @@ line.erase(line.size()-1,1); sd[line.substr(0,tab)]=line.substr(tab+1); } + piece::reset(); SetServerDir(sd); } ======================================================================== --- piece_table.cc 53950e7fe2e4a2cf12bcecd3e75280ed36209c94 +++ piece_table.cc 8bb9dfd41386acc9d24c8ead00505113754c2e56 @@ -65,7 +65,6 @@ } } - static void process_one_hunk(piece::piece_table const & source, piece::piece_table & dest, @@ -81,7 +80,7 @@ char code; int pos, len; if (sscanf(directive.c_str(), " %c %d %d", &code, &pos, &len) != 3) - throw oops("illformed directive '" + directive + "'"); + E(false, F("illformed directive '%s'\n") % directive); if (code == 'a') { @@ -102,16 +101,13 @@ I(cursor == pos - 1); cursor += len; } - else - throw oops("unknown directive '" + directive + "'"); + else + E(false,F("unknown directive '%s'\n") % directive); } catch (std::out_of_range & oor) { - throw oops("std::out_of_range while processing " + directive - + " with source.size() == " - + boost::lexical_cast(source.size()) - + " and cursor == " - + boost::lexical_cast(cursor)); + E(false, F("out_of_range while processing '%s' with source.size() == %d and cursor == %d") + % directive % source.size() % cursor); } } @@ -134,3 +130,20 @@ dest_lines.push_back(source_lines[cursor++]); } +void +piece::reset() +{ + global_pieces.reset(); +} + +void +piece::index_deltatext(std::string const & dt, piece_table & pieces) +{ + global_pieces.index_deltatext(dt,pieces); +} + +void +piece::build_string(piece_table const & pieces, std::string & out) +{ + global_pieces.build_string(pieces, out); +} ======================================================================== --- piece_table.hh beb63ff93407222a2e23a24d16780b02dd267dba +++ piece_table.hh 72c9cc30b6b72cafa50e1b93672e7cb550009445 @@ -10,6 +10,11 @@ // piece table stuff +/* + * this code efficiently constructs a new revision of a file by breaking + * it into lines and applying a rcs diff + */ + struct piece { @@ -31,6 +36,7 @@ piece_table & dest_lines, std::string const & deltatext); + // free allocated storage (invalidates all existing pieces) static void reset(); };