Fossil

Check-in [c0a3e9ff]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:When doing "fossil export" make sure the output is in strict topological orders, since Git hates timewarps.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: c0a3e9ff6fbe3b48bf3c3a31173b7f168758d6e6591eecdf31c267dbce907c95
User & Date: drh 2018-05-04 15:39:25
Context
2018-05-05
11:30
Update the built-in SQLite to the latest 3.24.0 alpha. check-in: 58a64102 user: drh tags: trunk
2018-05-04
15:39
When doing "fossil export" make sure the output is in strict topological orders, since Git hates timewarps. check-in: c0a3e9ff user: drh tags: trunk
13:52
Fix a harmless compiler warning in timeline.c. check-in: 8d1cb59f user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/export.c.

   598    598     }
   599    599     db_finalize(&q);
   600    600     db_finalize(&q2);
   601    601     db_finalize(&q3);
   602    602   
   603    603     /* Output the commit records.
   604    604     */
          605  +  topological_sort_checkins(0);
   605    606     db_prepare(&q,
   606    607       "SELECT strftime('%%s',mtime), objid, coalesce(ecomment,comment),"
   607    608       "       coalesce(euser,user),"
   608    609       "       (SELECT value FROM tagxref WHERE rid=objid AND tagid=%d)"
   609         -    "  FROM event"
   610         -    " WHERE type='ci' AND NOT EXISTS (SELECT 1 FROM oldcommit WHERE objid=rid)"
   611         -    " ORDER BY mtime ASC",
          610  +    "  FROM toponode, event"
          611  +    " WHERE toponode.tid=event.objid"
          612  +    "   AND event.type='ci'"
          613  +    "   AND NOT EXISTS (SELECT 1 FROM oldcommit WHERE toponode.tid=rid)"
          614  +    " ORDER BY toponode.tseq ASC",
   612    615       TAG_BRANCH
   613    616     );
   614    617     db_prepare(&q2, "INSERT INTO oldcommit VALUES (:rid)");
   615    618     while( db_step(&q)==SQLITE_ROW ){
   616    619       Stmt q4;
   617    620       const char *zSecondsSince1970 = db_column_text(&q, 0);
   618    621       int ckinId = db_column_int(&q, 1);
................................................................................
   621    624       const char *zBranch = db_column_text(&q, 4);
   622    625       char *zMark;
   623    626   
   624    627       bag_insert(&vers, ckinId);
   625    628       db_bind_int(&q2, ":rid", ckinId);
   626    629       db_step(&q2);
   627    630       db_reset(&q2);
   628         -    if( zBranch==0 || fossil_strcmp(zBranch, "trunk")==0 ) zBranch = gexport.zTrunkName;
          631  +    if( zBranch==0 || fossil_strcmp(zBranch, "trunk")==0 ){
          632  +      zBranch = gexport.zTrunkName;
          633  +    }
   629    634       zMark = mark_name_from_rid(ckinId, &unused_mark);
   630    635       printf("commit refs/heads/");
   631    636       print_ref(zBranch);
   632    637       printf("\nmark %s\n", zMark);
   633    638       free(zMark);
   634    639       printf("committer");
   635    640       print_person(zUser);
................................................................................
   735    740       if( ferror(f)!=0 || fclose(f)!=0 ){
   736    741         fossil_fatal("error while writing %s", markfile_out);
   737    742       }
   738    743     }
   739    744     bag_clear(&blobs);
   740    745     bag_clear(&vers);
   741    746   }
          747  +
          748  +/*
          749  +** Construct the temporary table toposort as follows:
          750  +**
          751  +**     CREATE TEMP TABLE toponode(
          752  +**        tid INTEGER PRIMARY KEY,   -- Check-in id
          753  +**        tseq INT                   -- integer total order on check-ins.
          754  +**     );
          755  +**
          756  +** This table contains all check-ins of the repository in topological
          757  +** order.  "Topological order" means that every parent check-in comes
          758  +** before all of its children.  Topological order is *almost* the same
          759  +** thing as "ORDER BY event.mtime".  Differences only arrise when there
          760  +** are timewarps.  In as much as Git hates timewarps, we have to compute
          761  +** a correct topological order when doing an export.
          762  +**
          763  +** Since mtime is a usually already nearly in topological order, the
          764  +** algorithm is to start with mtime, then make adjustments as necessary
          765  +** for timewarps.  This is not a great algorithm for the general case,
          766  +** but it is very fast for the overwhelmingly common case where there
          767  +** are few timewarps.
          768  +*/
          769  +int topological_sort_checkins(int bVerbose){
          770  +  int nChange = 0;
          771  +  Stmt q1;
          772  +  Stmt chng;
          773  +  db_multi_exec(
          774  +    "CREATE TEMP TABLE toponode(\n"
          775  +    "  tid INTEGER PRIMARY KEY,\n"
          776  +    "  tseq INT\n"
          777  +    ");\n"
          778  +    "INSERT INTO toponode(tid,tseq) "
          779  +    " SELECT objid, CAST(mtime*8640000 AS int) FROM event WHERE type='ci';\n"
          780  +    "CREATE TEMP TABLE topolink(\n"
          781  +    "  tparent INT,\n"
          782  +    "  tchild INT,\n"
          783  +    "  PRIMARY KEY(tparent,tchild)\n"
          784  +    ") WITHOUT ROWID;"
          785  +    "INSERT INTO topolink(tparent,tchild)"
          786  +    "  SELECT pid, cid FROM plink;\n"
          787  +    "CREATE INDEX topolink_child ON topolink(tchild);\n"
          788  +  );
          789  +
          790  +  /* Find a timewarp instance */
          791  +  db_prepare(&q1,
          792  +    "SELECT P.tid, P.tseq, C.tid, C.tseq\n"
          793  +    "  FROM toponode P, toponode C, topolink X\n"
          794  +    " WHERE X.tparent=P.tid\n"
          795  +    "   AND X.tchild=C.tid\n"
          796  +    "   AND P.tseq>=C.tseq;"
          797  +  );
          798  +
          799  +  /* Update the timestamp on :tid to have value :tseq */
          800  +  db_prepare(&chng,
          801  +    "UPDATE toponode SET tseq=:tseq WHERE tid=:tid"
          802  +  );
          803  +
          804  +  while( db_step(&q1)==SQLITE_ROW ){
          805  +    int iParent = db_column_int(&q1, 0);
          806  +    i64 iParentTime = db_column_int64(&q1, 1);
          807  +    int iChild = db_column_int(&q1, 2);
          808  +    i64 iChildTime = db_column_int64(&q1, 3);
          809  +    nChange++;
          810  +    if( nChange>10000 ){
          811  +      fossil_fatal("failed to fix all timewarps after 100000 attempts");
          812  +    }
          813  +    db_reset(&q1);
          814  +    db_bind_int64(&chng, ":tid", iChild);
          815  +    db_bind_int64(&chng, ":tseq", iParentTime+1);
          816  +    db_step(&chng);
          817  +    db_reset(&chng);
          818  +    if( bVerbose ){
          819  +      fossil_print("moving %d from %lld to %lld\n",
          820  +                   iChild, iChildTime, iParentTime+1);
          821  +    }
          822  +  }
          823  +
          824  +  db_finalize(&q1);
          825  +  db_finalize(&chng);
          826  +  return nChange;
          827  +}
          828  +
          829  +/*
          830  +** COMMAND: test-topological-sort
          831  +**
          832  +** Invoke the topological_sort_checkins() interface for testing
          833  +** purposes.
          834  +*/
          835  +void test_topological_sort(void){
          836  +  int n;
          837  +  db_find_and_open_repository(0, 0);
          838  +  n = topological_sort_checkins(1);
          839  +  fossil_print("%d reorderings required\n", n);
          840  +}