Merge branch 'master' of git.irl.cs.ucla.edu:ndn/chronoshare
diff --git a/scheduler/scheduler.cc b/scheduler/scheduler.cc
index e7630d2..225e484 100644
--- a/scheduler/scheduler.cc
+++ b/scheduler/scheduler.cc
@@ -82,13 +82,13 @@
 void
 Scheduler::shutdown()
 {
-  WriteLock lock(m_mutex);
-  if (m_running)
   {
-    event_base_loopbreak(m_base);
-    m_thread.join();
+    WriteLock lock(m_mutex);
     m_running = false;
   }
+  
+  event_base_loopbreak(m_base);
+  m_thread.join();
 }
 
 bool
diff --git a/src/action-item.proto b/src/action-item.proto
index 3218ef8..1008ba6 100644
--- a/src/action-item.proto
+++ b/src/action-item.proto
@@ -2,20 +2,21 @@
 {
   enum ActionType
   {
-    UPDATE = 0;
-    DELETE = 1;
+    UPDATE = 1;
+    DELETE = 2;
   }
-  required ActionType action = 3;
+  required ActionType action = 14;
 
-  required string filename = 4;
-  required uint64 version = 5;
-  required uint32 timestamp = 6;
+  required string filename = 1;
+  required uint64 version = 2;
+  required uint32 timestamp = 3;
+  optional uint64 seg_num = 4;
+  optional bytes  file_hash = 5;
 
-  optional bytes  file_hash = 7;
+  optional uint32 mtime = 6;
+  optional uint32 mode  = 7;
   // optional uint32 atime = 8;
-  optional uint32 mtime = 9;
-  // optional uint32 ctime = 10;
-  optional uint32 mode  = 11;
+  // optional uint32 ctime = 9;
 
   optional bytes  parent_device_name = 12;
   optional uint64 parent_seq_no = 13;
diff --git a/src/action-log.cc b/src/action-log.cc
index cc0d945..e15bbc6 100644
--- a/src/action-log.cc
+++ b/src/action-log.cc
@@ -85,7 +85,8 @@
 ActionLog::AddActionUpdate (const std::string &filename,
                             const Hash &hash,
                             time_t wtime,
-                            int mode)
+                            int mode,
+                            int seg_num)
 {
   sqlite3_exec (m_db, "BEGIN TRANSACTION;", 0,0,0);
   
@@ -102,7 +103,7 @@
   sqlite3_stmt *stmt;
   int res = sqlite3_prepare_v2 (m_db, "INSERT INTO ActionLog "
                                 "(device_id, seq_no, action, filename, version, action_timestamp, "
-                                "file_hash, file_atime, file_mtime, file_ctime, file_chmod, "
+                                "file_hash, file_atime, file_mtime, file_ctime, file_chmod, file_seg_num, "
                                 "parent_device_id, parent_seq_no, "
                                 "action_name, action_content_object) "
                                 "VALUES (?, ?, ?, ?, ?, datetime(?, 'unixepoch'),"
@@ -140,16 +141,17 @@
   sqlite3_bind_int64 (stmt, 9, wtime);
   // sqlite3_bind_int64 (stmt, 10, ctime); // NULL
   sqlite3_bind_int   (stmt, 11, mode);
+  sqlite3_bind_int   (stmt, 12, seg_num);
 
   if (parent_device_id > 0 && parent_seq_no > 0)
     {
-      sqlite3_bind_int64 (stmt, 12, parent_device_id);
-      sqlite3_bind_int64 (stmt, 13, parent_seq_no);
+      sqlite3_bind_int64 (stmt, 13, parent_device_id);
+      sqlite3_bind_int64 (stmt, 14, parent_seq_no);
     }
   else
     {
-      sqlite3_bind_null (stmt, 12);
       sqlite3_bind_null (stmt, 13);
+      sqlite3_bind_null (stmt, 14);
     }
   
   // missing part: creating ContentObject for the action !!!
@@ -164,6 +166,7 @@
   item.set_mtime (wtime);
   // item.set_ctime (ctime);
   item.set_mode (mode);
+  item.set_seg_num (seg_num);
 
   if (parent_device_id > 0 && parent_seq_no > 0)
     {
@@ -286,9 +289,9 @@
 {
   ActionLog *the = reinterpret_cast<ActionLog*> (sqlite3_user_data (context));
 
-  if (argc != 10)
+  if (argc != 11)
     {
-      sqlite3_result_error (context, "``apply_action'' expects 8 arguments", -1);
+      sqlite3_result_error (context, "``apply_action'' expects 11 arguments", -1);
       return;
     }
 
@@ -311,6 +314,7 @@
       time_t mtime = static_cast<time_t> (sqlite3_value_int64 (argv[7]));
       time_t ctime = static_cast<time_t> (sqlite3_value_int64 (argv[8]));
       int mode = sqlite3_value_int (argv[9]);
+      int seg_num = sqlite3_value_int (argv[10]);
 
       cout << "Update " << filename << " " << atime << " " << mtime << " " << ctime << " " << hash << endl;
 
@@ -323,6 +327,7 @@
                           "file_mtime=datetime(?, 'unixepoch'),"
                           "file_ctime=datetime(?, 'unixepoch'),"
                           "file_chmod=? "
+                          "file_seg_num=? "
                           "WHERE type=0 AND filename=?", -1, &stmt, 0);
 
       sqlite3_bind_int64 (stmt, 1, device_id);
@@ -332,7 +337,8 @@
       sqlite3_bind_int64 (stmt, 5, mtime);
       sqlite3_bind_int64 (stmt, 6, ctime);
       sqlite3_bind_int   (stmt, 7, mode);
-      sqlite3_bind_text  (stmt, 8, filename.c_str (), -1, SQLITE_TRANSIENT);
+      sqlite3_bind_int   (stmt, 8, seg_num);
+      sqlite3_bind_text  (stmt, 9, filename.c_str (), -1, SQLITE_TRANSIENT);
       
       sqlite3_step (stmt);
 
diff --git a/src/action-log.h b/src/action-log.h
index 7d778d8..ed7a76a 100644
--- a/src/action-log.h
+++ b/src/action-log.h
@@ -39,7 +39,8 @@
   AddActionUpdate (const std::string &filename,
                    const Hash &hash,
                    time_t wtime,
-                   int mode);
+                   int mode,
+                   int seg_num);
 
   void
   AddActionMove (const std::string &oldFile, const std::string &newFile);
diff --git a/src/db-helper.cc b/src/db-helper.cc
index 0e08612..82feb89 100644
--- a/src/db-helper.cc
+++ b/src/db-helper.cc
@@ -103,6 +103,7 @@
     file_mtime  TIMESTAMP,                                              \n\
     file_ctime  TIMESTAMP,                                              \n\
     file_chmod  INTEGER,                                                \n\
+    file_seg_num INTEGER, /* NULL if action is \"delete\" */            \n\
                                                                         \n\
     parent_device_id INTEGER,                                           \n\
     parent_seq_no    INTEGER,                                           \n\
@@ -143,7 +144,7 @@
                              NEW.device_id, NEW.seq_no,                 \
                              NEW.action,NEW.filename,NEW.file_hash,     \
                              strftime('%s', NEW.file_atime),strftime('%s', NEW.file_mtime),strftime('%s', NEW.file_ctime), \
-                             NEW.file_chmod); /* function that applies action and adds record the FileState */  \n \
+                             NEW.file_chmod, NEW.file_seg_num); /* function that applies action and adds record the FileState */  \n \
     END;                                                                \n\
                                                                         \n\
 CREATE TABLE FileState (                                                \n\
@@ -156,6 +157,7 @@
     file_mtime  TIMESTAMP,                                              \n\
     file_ctime  TIMESTAMP,                                              \n\
     file_chmod  INTEGER,                                                \n\
+    file_seg_num INTEGER,                                               \n\
                                                                         \n\
     PRIMARY KEY (type, filename)                                        \n\
 );                                                                      \n\
diff --git a/src/sync-core.cc b/src/sync-core.cc
index c64ce90..9e5d0f4 100644
--- a/src/sync-core.cc
+++ b/src/sync-core.cc
@@ -331,7 +331,8 @@
   // find the actuall difference and invoke callback on the actual difference
   HashPtr oldHash = m_rootHash;
   m_rootHash = m_log->RememberStateInStateLog();
-  SyncStateMsgPtr diff = m_log->FindStateDifferences(*oldHash, *m_rootHash);
+  // get diff with both new SeqNo and old SeqNo
+  SyncStateMsgPtr diff = m_log->FindStateDifferences(*oldHash, *m_rootHash, true);
 
   if (diff->state_size() > 0)
   {
diff --git a/src/sync-log.cc b/src/sync-log.cc
index 1e17957..eb421a9 100644
--- a/src/sync-log.cc
+++ b/src/sync-log.cc
@@ -304,13 +304,13 @@
 }
 
 SyncStateMsgPtr
-SyncLog::FindStateDifferences (const std::string &oldHash, const std::string &newHash)
+SyncLog::FindStateDifferences (const std::string &oldHash, const std::string &newHash, bool includeOldSeq)
 {
-  return FindStateDifferences (*Hash::FromString (oldHash), *Hash::FromString (newHash));
+  return FindStateDifferences (*Hash::FromString (oldHash), *Hash::FromString (newHash), includeOldSeq);
 }
 
 SyncStateMsgPtr
-SyncLog::FindStateDifferences (const Hash &oldHash, const Hash &newHash)
+SyncLog::FindStateDifferences (const Hash &oldHash, const Hash &newHash, bool includeOldSeq)
 {
   sqlite3_stmt *stmt;
 
@@ -370,6 +370,7 @@
     {
       SyncState *state = msg->add_state ();
 
+      // set name
       state->set_name (reinterpret_cast<const char*> (sqlite3_column_blob (stmt, 0)), sqlite3_column_bytes (stmt, 0));
 
       // locator is optional, so must check if it is null
@@ -378,6 +379,23 @@
         state->set_locator (reinterpret_cast<const char*> (sqlite3_column_blob (stmt, 1)), sqlite3_column_bytes (stmt, 1));
       }
 
+      // set old seq
+      if (includeOldSeq)
+      {
+        if (sqlite3_column_type (stmt, 2) == SQLITE_NULL)
+        {
+          // old seq is zero; we always have an initial action of zero seq
+          // other's do not need to fetch this action
+          state->set_old_seq(0);
+        }
+        else
+        {
+          sqlite3_int64 oldSeqNo = sqlite3_column_int64 (stmt, 2);
+          state->set_old_seq(oldSeqNo);
+        }
+      }
+
+      // set new seq
       if (sqlite3_column_type (stmt, 3) == SQLITE_NULL)
         {
         state->set_type (SyncState::DELETE);
diff --git a/src/sync-log.h b/src/sync-log.h
index aed3bce..549d759 100644
--- a/src/sync-log.h
+++ b/src/sync-log.h
@@ -69,10 +69,10 @@
 
   // How difference is exposed will be determined later by the actual protocol
   SyncStateMsgPtr
-  FindStateDifferences (const std::string &oldHash, const std::string &newHash);
+  FindStateDifferences (const std::string &oldHash, const std::string &newHash, bool includeOldSeq = false);
 
   SyncStateMsgPtr
-  FindStateDifferences (const Hash &oldHash, const Hash &newHash);  
+  FindStateDifferences (const Hash &oldHash, const Hash &newHash, bool includeOldSeq = false);  
 
   //-------- only used in test -----------------
   sqlite3_int64
diff --git a/src/sync-state.proto b/src/sync-state.proto
index 26095e1..410726b 100644
--- a/src/sync-state.proto
+++ b/src/sync-state.proto
@@ -11,6 +11,7 @@
 
   optional uint64 seq = 3;
   optional bytes locator = 4;
+  optional uint64 old_seq = 5;
 }
 
 message SyncStateMsg
diff --git a/test/test-sync-core.cc b/test/test-sync-core.cc
index 1fbe4e6..354e2b4 100644
--- a/test/test-sync-core.cc
+++ b/test/test-sync-core.cc
@@ -13,6 +13,19 @@
 void callback(const SyncStateMsgPtr &msg)
 {
   BOOST_CHECK(msg->state_size() > 0);
+  int size = msg->state_size();
+  int index = 0;
+  while (index < size)
+  {
+    SyncState state = msg->state(index);
+    BOOST_CHECK(state.has_old_seq());
+    BOOST_CHECK(state.old_seq() >= 0);
+    if (state.seq() != 0)
+    {
+      BOOST_CHECK(state.old_seq() != state.seq()); 
+    }
+    index++;
+  }
 }
 
 void checkRoots(const HashPtr &root1, const HashPtr &root2)