Check-in [95f5520a09]
Not logged in
Overview

SHA1 Hash:95f5520a09efb7698179f5123fbca8e3f33fbb39
Date: 2009-09-14 14:08:35
User: drh
Comment:Construct event records for tickets correctly even when the ticket change artifacts arrive out of order.
Timelines: ancestors | descendants | both | trunk
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified src/manifest.c from [9476d92cd1] to [3ac47cd0a7].

@@ -883,10 +883,109 @@
   }
   manifest_clear(&other);
 }
 
 /*
+** True if manifest_crosslink_begin() has been called but
+** manifest_crosslink_end() is still pending.
+*/
+static int manifest_crosslink_busy = 0;
+
+/*
+** Setup to do multiple manifest_crosslink() calls.
+** This is only required if processing ticket changes.
+*/
+void manifest_crosslink_begin(void){
+  assert( manifest_crosslink_busy==0 );
+  manifest_crosslink_busy = 1;
+  db_begin_transaction();
+  db_multi_exec("CREATE TEMP TABLE pending_tkt(uuid TEXT UNIQUE)");
+}
+
+/*
+** Finish up a sequence of manifest_crosslink calls.
+*/
+void manifest_crosslink_end(void){
+  Stmt q;
+  assert( manifest_crosslink_busy==1 );
+  db_prepare(&q, "SELECT uuid FROM pending_tkt");
+  while( db_step(&q)==SQLITE_ROW ){
+    const char *zUuid = db_column_text(&q, 0);
+    ticket_rebuild_entry(zUuid);
+  }
+  db_finalize(&q);
+  db_end_transaction(0);
+  manifest_crosslink_busy = 0;
+}
+
+/*
+** Make an entry in the event table for a ticket change artifact.
+*/
+void manifest_ticket_event(
+  int rid,                    /* Artifact ID of the change ticket artifact */
+  const Manifest *pManifest,  /* Parsed content of the artifact */
+  int isNew                   /* True if this is the first event */
+){
+  int i;
+  char *zTitle;
+  Blob comment;
+  char *zNewStatus = 0;
+  static char *zTitleExpr = 0;
+  static char *zStatusColumn = 0;
+  static int once = 1;
+
+  blob_zero(&comment);
+  if( once ){
+    once = 0;
+    zTitleExpr = db_get("ticket-title-expr", "title");
+    zStatusColumn = db_get("ticket-status-column", "status");
+  }
+  zTitle = db_text("unknown",
+    "SELECT %s FROM ticket WHERE tkt_uuid='%s'",
+    zTitleExpr, pManifest->zTicketUuid
+  );
+  if( !isNew ){
+    for(i=0; i<pManifest->nField; i++){
+      if( strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){
+        zNewStatus = pManifest->aField[i].zValue;
+      }
+    }
+    if( zNewStatus ){
+      blob_appendf(&comment, "%h ticket [%.10s]: <i>%h</i>",
+         zNewStatus, pManifest->zTicketUuid, zTitle
+      );
+      if( pManifest->nField>1 ){
+        blob_appendf(&comment, " plus %d other change%s",
+          pManifest->nField-1, pManifest->nField==2 ? "" : "s");
+      }
+    }else{
+      zNewStatus = db_text("unknown",
+         "SELECT %s FROM ticket WHERE tkt_uuid='%s'",
+         zStatusColumn, pManifest->zTicketUuid
+      );
+      blob_appendf(&comment, "Ticket [%.10s] <i>%h</i> status still %h with "
+           "%d other change%s",
+           pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField,
+           pManifest->nField==1 ? "" : "s"
+      );
+      free(zNewStatus);
+    }
+  }else{
+    blob_appendf(&comment, "New ticket [%.10s] <i>%h</i>.",
+      pManifest->zTicketUuid, zTitle
+    );
+  }
+  free(zTitle);
+  db_multi_exec(
+    "REPLACE INTO event(type,mtime,objid,user,comment)"
+    "VALUES('t',%.17g,%d,%Q,%Q)",
+    pManifest->rDate, rid, pManifest->zUser, blob_str(&comment)
+  );
+  blob_reset(&comment);
+}
+
+/*
 ** Scan artifact rid/pContent to see if it is a control artifact of
 ** any key:
 **
 **      *  Manifest
 **      *  Control
@@ -1024,72 +1123,18 @@
       TAG_COMMENT, rid
     );
     free(zComment);
   }
   if( m.type==CFTYPE_TICKET ){
-    int i;
-    char *zTitle;
     char *zTag;
-    Blob comment;
-    char *zNewStatus = 0;
-    static char *zTitleExpr = 0;
-    static char *zStatusColumn = 0;
-    static int once = 1;
-    int isNew;
 
-    isNew = ticket_insert(&m, 1, 1);
+    assert( manifest_crosslink_busy==1 );
     zTag = mprintf("tkt-%s", m.zTicketUuid);
     tag_insert(zTag, 1, 0, rid, m.rDate, rid);
     free(zTag);
-    blob_zero(&comment);
-    if( once ){
-      once = 0;
-      zTitleExpr = db_get("ticket-title-expr", "title");
-      zStatusColumn = db_get("ticket-status-column", "status");
-    }
-    zTitle = db_text("unknown",
-      "SELECT %s FROM ticket WHERE tkt_uuid='%s'",
-      zTitleExpr, m.zTicketUuid
-    );
-    if( !isNew ){
-      for(i=0; i<m.nField; i++){
-        if( strcmp(m.aField[i].zName, zStatusColumn)==0 ){
-          zNewStatus = m.aField[i].zValue;
-        }
-      }
-      if( zNewStatus ){
-        blob_appendf(&comment, "%h ticket [%.10s]: <i>%h</i>",
-           zNewStatus, m.zTicketUuid, zTitle
-        );
-        if( m.nField>1 ){
-          blob_appendf(&comment, " plus %d other change%s",
-            m.nField-1, m.nField==2 ? "" : "s");
-        }
-      }else{
-        zNewStatus = db_text("unknown",
-           "SELECT %s FROM ticket WHERE tkt_uuid='%s'",
-           zStatusColumn, m.zTicketUuid
-        );
-        blob_appendf(&comment, "Ticket [%.10s] <i>%h</i> status still %h with "
-             "%d other change%s",
-             m.zTicketUuid, zTitle, zNewStatus, m.nField,
-             m.nField==1 ? "" : "s"
-        );
-        free(zNewStatus);
-      }
-    }else{
-      blob_appendf(&comment, "New ticket [%.10s] <i>%h</i>.",
-        m.zTicketUuid, zTitle
-      );
-    }
-    free(zTitle);
-    db_multi_exec(
-      "REPLACE INTO event(type,mtime,objid,user,comment)"
-      "VALUES('t',%.17g,%d,%Q,%Q)",
-      m.rDate, rid, m.zUser, blob_str(&comment)
-    );
-    blob_reset(&comment);
+    db_multi_exec("INSERT OR IGNORE INTO pending_tkt VALUES(%Q)",
+                  m.zTicketUuid);
   }
   db_end_transaction(0);
   manifest_clear(&m);
   return 1;
 }

Modified src/rebuild.c from [fd43a695c4] to [cd57d5ccbc].

@@ -241,10 +241,11 @@
   db_prepare(&s,
      "SELECT rid, size FROM blob"
      " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
      "   AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid)"
   );
+  manifest_crosslink_begin();
   while( db_step(&s)==SQLITE_ROW ){
     int rid = db_column_int(&s, 0);
     int size = db_column_int(&s, 1);
     if( size>=0 ){
       Blob content;
@@ -270,10 +271,11 @@
       db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid);
       rebuild_step_done(rid);
     }
   }
   db_finalize(&s);
+  manifest_crosslink_end();
   rebuild_tag_trunk();
   if( ttyOutput ){
     printf("\n");
   }
   return errCnt;

Modified src/tag.c from [11a50e87e6] to [bc765b3a20].

@@ -142,11 +142,11 @@
 }
 
 /*
 ** Insert a tag into the database.
 */
-void tag_insert(
+int tag_insert(
   const char *zTag,        /* Name of the tag (w/o the "+" or "-" prefix */
   int tagtype,             /* 0:cancel  1:singleton  2:propagated */
   const char *zValue,      /* Value if the tag is really a property */
   int srcId,               /* Artifact that contains this tag */
   double mtime,            /* Timestamp.  Use default if <=0.0 */
@@ -170,11 +170,11 @@
   db_bind_double(&s, ":mtime", mtime);
   rc = db_step(&s);
   db_finalize(&s);
   if( rc==SQLITE_ROW ){
     /* Another entry that is more recent already exists.  Do nothing */
-    return;
+    return tagid;
   }
   db_prepare(&s,
     "REPLACE INTO tagxref(tagid,tagtype,srcId,origid,value,mtime,rid)"
     " VALUES(%d,%d,%d,%d,%Q,:mtime,%d)",
     tagid, tagtype, srcId, rid, zValue, rid
@@ -208,10 +208,11 @@
                   zValue, rid);
   }
   if( tagtype==0 || tagtype==2 ){
     tag_propagate(rid, tagid, tagtype, rid, zValue, mtime);
   }
+  return tagid;
 }
 
 
 /*
 ** COMMAND: test-tag

Modified src/tkt.c from [53e4b94cc8] to [bc233f791c].

@@ -197,11 +197,11 @@
 ** work of trying to create it.
 **
 ** Return TRUE if a new TICKET entry was created and FALSE if an
 ** existing entry was revised.
 */
-int ticket_insert(Manifest *p, int createFlag, int checkTime){
+int ticket_insert(const Manifest *p, int createFlag, int checkTime){
   Blob sql;
   Stmt q;
   int i;
   const char *zSep;
   int rc = 0;
@@ -264,10 +264,11 @@
   while( db_step(&q)==SQLITE_ROW ){
     int rid = db_column_int(&q, 0);
     content_get(rid, &content);
     manifest_parse(&manifest, &content);
     ticket_insert(&manifest, createFlag, 0);
+    manifest_ticket_event(rid, &manifest, createFlag);
     manifest_clear(&manifest);
     createFlag = 0;
   }
   db_finalize(&q);
 }
@@ -456,11 +457,13 @@
   }else{
     rid = content_put(&tktchng, 0, 0);
     if( rid==0 ){
       fossil_panic("trouble committing ticket: %s", g.zErrMsg);
     }
+    manifest_crosslink_begin();
     manifest_crosslink(rid, &tktchng);
+    manifest_crosslink_end();
   }
   return TH_RETURN;
 }
 
 
@@ -690,11 +693,12 @@
       char zUuid[12];
       memcpy(zUuid, zChngUuid, 10);
       zUuid[10] = 0;
       @
       @ Ticket change
-      @ [<a href="%s(g.zTop)/artifact/%T(zChngUuid)">%s(zUuid)</a>]</a> by
+      @ [<a href="%s(g.zTop)/artifact/%T(zChngUuid)">%s(zUuid)</a>]</a>
+      @ (rid %d(rid)) by
       hyperlink_to_user(m.zUser,zDate," on");
       hyperlink_to_date(zDate, ":");
       free(zDate);
       ticket_output_change_artifact(&m);
     }

Modified src/xfer.c from [5dff3de1ae] to [5bb8ce2dae].

@@ -580,10 +580,11 @@
 
   db_begin_transaction();
   db_multi_exec(
      "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
   );
+  manifest_crosslink_begin();
   while( blob_line(xfer.pIn, &xfer.line) ){
     if( blob_buffer(&xfer.line)[0]=='#' ) continue;
     xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
 
     /*   file UUID SIZE \n CONTENT
@@ -831,10 +832,11 @@
     send_unclustered(&xfer);
   }
   if( recvConfig ){
     configure_finalize_receive();
   }
+  manifest_crosslink_end();
   db_end_transaction(0);
 }
 
 /*
 ** COMMAND: test-xfer
@@ -946,10 +948,11 @@
   }
   if( pushFlag ){
     blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
     nCard++;
   }
+  manifest_crosslink_begin();
   printf(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas");
 
   while( go ){
     int newPhantom = 0;
     char *zRandomness;
@@ -1228,7 +1231,8 @@
   printf("Total network traffic: %d bytes sent, %d bytes received\n",
          nSent, nRcvd);
   transport_close();
   socket_global_shutdown();
   db_multi_exec("DROP TABLE onremote");
+  manifest_crosslink_end();
   db_end_transaction(0);
 }