[Unison-hackers] [unison-svn] r393 - trunk/src

vouillon@seas.upenn.edu vouillon at seas.upenn.edu
Wed Jan 6 16:20:15 EST 2010


Author: vouillon
Date: 2010-01-06 16:20:12 -0500 (Wed, 06 Jan 2010)
New Revision: 393

Added:
   trunk/src/fpcache.ml
   trunk/src/fpcache.mli
Modified:
   trunk/src/.depend
   trunk/src/Makefile.OCaml
   trunk/src/RECENTNEWS
   trunk/src/copy.ml
   trunk/src/mkProjectInfo.ml
   trunk/src/path.ml
   trunk/src/path.mli
   trunk/src/update.ml
   trunk/src/update.mli
Log:
* Implemented an on-disk file fingerprint cache to speed-up update
  detection after a crash: this way, Unison does not have do recompute
  all the file fingerprints from scratch.


Modified: trunk/src/.depend
===================================================================
--- trunk/src/.depend	2010-01-05 15:42:43 UTC (rev 392)
+++ trunk/src/.depend	2010-01-06 21:20:12 UTC (rev 393)
@@ -13,6 +13,7 @@
     lwt/lwt.cmi common.cmi 
 fileutil.cmi: 
 fingerprint.cmi: uutil.cmi path.cmi fspath.cmi 
+fpcache.cmi: 
 fs.cmi: system/system_intf.cmo fspath.cmi 
 fspath.cmi: system.cmi path.cmi name.cmi 
 globals.cmi: ubase/prefs.cmi pred.cmi path.cmi lwt/lwt.cmi common.cmi 
@@ -35,10 +36,10 @@
 transfer.cmi: uutil.cmi lwt/lwt.cmi bytearray.cmi 
 transport.cmi: uutil.cmi lwt/lwt.cmi common.cmi 
 tree.cmi: 
+ui.cmi: 
 uicommon.cmi: uutil.cmi ubase/prefs.cmi path.cmi lwt/lwt.cmi common.cmi 
+uigtk.cmi: uicommon.cmi 
 uigtk2.cmi: uicommon.cmi 
-uigtk.cmi: uicommon.cmi 
-ui.cmi: 
 uitext.cmi: uicommon.cmi 
 unicode.cmi: 
 update.cmi: uutil.cmi tree.cmi props.cmi path.cmi osx.cmi os.cmi name.cmi \
@@ -93,6 +94,12 @@
 fileutil.cmx: fileutil.cmi 
 fingerprint.cmo: uutil.cmi ubase/util.cmi fspath.cmi fs.cmi fingerprint.cmi 
 fingerprint.cmx: uutil.cmx ubase/util.cmx fspath.cmx fs.cmx fingerprint.cmi 
+fpcache.cmo: uutil.cmi ubase/util.cmi ubase/trace.cmi system.cmi \
+    ubase/safelist.cmi props.cmi path.cmi osx.cmi os.cmi fileinfo.cmi \
+    fpcache.cmi 
+fpcache.cmx: uutil.cmx ubase/util.cmx ubase/trace.cmx system.cmx \
+    ubase/safelist.cmx props.cmx path.cmx osx.cmx os.cmx fileinfo.cmx \
+    fpcache.cmi 
 fs.cmo: fspath.cmi fs.cmi 
 fs.cmx: fspath.cmx fs.cmi 
 fspath.cmo: uutil.cmi ubase/util.cmi system.cmi ubase/rx.cmi path.cmi \
@@ -105,10 +112,10 @@
 globals.cmx: ubase/util.cmx ubase/trace.cmx ubase/safelist.cmx remote.cmx \
     ubase/prefs.cmx pred.cmx path.cmx os.cmx name.cmx lwt/lwt_util.cmx \
     lwt/lwt_unix.cmx lwt/lwt.cmx common.cmx clroot.cmx globals.cmi 
+linkgtk.cmo: uigtk.cmi main.cmo 
+linkgtk.cmx: uigtk.cmx main.cmx 
 linkgtk2.cmo: uigtk2.cmi main.cmo 
 linkgtk2.cmx: uigtk2.cmx main.cmx 
-linkgtk.cmo: uigtk.cmi main.cmo 
-linkgtk.cmx: uigtk.cmx main.cmx 
 linktext.cmo: uitext.cmi main.cmo 
 linktext.cmx: uitext.cmx main.cmx 
 lock.cmo: ubase/util.cmi system.cmi lock.cmi 
@@ -213,6 +220,16 @@
     recon.cmx props.cmx ubase/prefs.cmx path.cmx osx.cmx os.cmx name.cmx \
     lwt/lwt_unix.cmx lwt/lwt.cmx globals.cmx fspath.cmx files.cmx \
     fileinfo.cmx common.cmx clroot.cmx case.cmx uicommon.cmi 
+uigtk.cmo: uutil.cmi ubase/util.cmi update.cmi uitext.cmi uicommon.cmi \
+    transport.cmi ubase/trace.cmi system.cmi strings.cmi sortri.cmi \
+    ubase/safelist.cmi remote.cmi recon.cmi ubase/prefs.cmi pixmaps.cmo \
+    path.cmi os.cmi lwt/lwt_util.cmi lwt/lwt_unix.cmi lwt/lwt.cmi globals.cmi \
+    files.cmi common.cmi clroot.cmi uigtk.cmi 
+uigtk.cmx: uutil.cmx ubase/util.cmx update.cmx uitext.cmx uicommon.cmx \
+    transport.cmx ubase/trace.cmx system.cmx strings.cmx sortri.cmx \
+    ubase/safelist.cmx remote.cmx recon.cmx ubase/prefs.cmx pixmaps.cmx \
+    path.cmx os.cmx lwt/lwt_util.cmx lwt/lwt_unix.cmx lwt/lwt.cmx globals.cmx \
+    files.cmx common.cmx clroot.cmx uigtk.cmi 
 uigtk2.cmo: uutil.cmi ubase/util.cmi update.cmi unicode.cmi uitext.cmi \
     uicommon.cmi transport.cmi ubase/trace.cmi system.cmi strings.cmi \
     sortri.cmi ubase/safelist.cmi remote.cmi recon.cmi ubase/prefs.cmi \
@@ -223,16 +240,6 @@
     sortri.cmx ubase/safelist.cmx remote.cmx recon.cmx ubase/prefs.cmx \
     pixmaps.cmx path.cmx os.cmx lwt/lwt_util.cmx lwt/lwt_unix.cmx lwt/lwt.cmx \
     globals.cmx files.cmx common.cmx clroot.cmx case.cmx uigtk2.cmi 
-uigtk.cmo: uutil.cmi ubase/util.cmi update.cmi uitext.cmi uicommon.cmi \
-    transport.cmi ubase/trace.cmi system.cmi strings.cmi sortri.cmi \
-    ubase/safelist.cmi remote.cmi recon.cmi ubase/prefs.cmi pixmaps.cmo \
-    path.cmi os.cmi lwt/lwt_util.cmi lwt/lwt_unix.cmi lwt/lwt.cmi globals.cmi \
-    files.cmi common.cmi clroot.cmi uigtk.cmi 
-uigtk.cmx: uutil.cmx ubase/util.cmx update.cmx uitext.cmx uicommon.cmx \
-    transport.cmx ubase/trace.cmx system.cmx strings.cmx sortri.cmx \
-    ubase/safelist.cmx remote.cmx recon.cmx ubase/prefs.cmx pixmaps.cmx \
-    path.cmx os.cmx lwt/lwt_util.cmx lwt/lwt_unix.cmx lwt/lwt.cmx globals.cmx \
-    files.cmx common.cmx clroot.cmx uigtk.cmi 
 uimacbridge.cmo: xferhint.cmi uutil.cmi ubase/util.cmi update.cmi \
     uicommon.cmi transport.cmi ubase/trace.cmi terminal.cmi system.cmi \
     stasher.cmi ubase/safelist.cmi remote.cmi recon.cmi ubase/prefs.cmi \
@@ -271,12 +278,12 @@
     system.cmi ubase/safelist.cmi remote.cmi props.cmi ubase/proplist.cmi \
     ubase/prefs.cmi pred.cmi path.cmi osx.cmi os.cmi name.cmi ubase/myMap.cmi \
     lwt/lwt_unix.cmi lwt/lwt.cmi lock.cmi globals.cmi fspath.cmi fs.cmi \
-    fingerprint.cmi fileinfo.cmi common.cmi case.cmi update.cmi 
+    fpcache.cmi fingerprint.cmi fileinfo.cmi common.cmi case.cmi update.cmi 
 update.cmx: xferhint.cmx uutil.cmx ubase/util.cmx tree.cmx ubase/trace.cmx \
     system.cmx ubase/safelist.cmx remote.cmx props.cmx ubase/proplist.cmx \
     ubase/prefs.cmx pred.cmx path.cmx osx.cmx os.cmx name.cmx ubase/myMap.cmx \
     lwt/lwt_unix.cmx lwt/lwt.cmx lock.cmx globals.cmx fspath.cmx fs.cmx \
-    fingerprint.cmx fileinfo.cmx common.cmx case.cmx update.cmi 
+    fpcache.cmx fingerprint.cmx fileinfo.cmx common.cmx case.cmx update.cmi 
 uutil.cmo: ubase/util.cmi ubase/trace.cmi ubase/projectInfo.cmo uutil.cmi 
 uutil.cmx: ubase/util.cmx ubase/trace.cmx ubase/projectInfo.cmx uutil.cmi 
 xferhint.cmo: ubase/util.cmi ubase/trace.cmi ubase/prefs.cmi path.cmi os.cmi \

Modified: trunk/src/Makefile.OCaml
===================================================================
--- trunk/src/Makefile.OCaml	2010-01-05 15:42:43 UTC (rev 392)
+++ trunk/src/Makefile.OCaml	2010-01-06 21:20:12 UTC (rev 393)
@@ -214,7 +214,7 @@
           props.cmo fileinfo.cmo os.cmo lock.cmo clroot.cmo common.cmo \
           tree.cmo checksum.cmo terminal.cmo \
           transfer.cmo xferhint.cmo remote.cmo globals.cmo \
-          update.cmo copy.cmo stasher.cmo \
+          fpcache.cmo update.cmo copy.cmo stasher.cmo \
 	  files.cmo sortri.cmo recon.cmo transport.cmo \
           strings.cmo uicommon.cmo uitext.cmo test.cmo
 

Modified: trunk/src/RECENTNEWS
===================================================================
--- trunk/src/RECENTNEWS	2010-01-05 15:42:43 UTC (rev 392)
+++ trunk/src/RECENTNEWS	2010-01-06 21:20:12 UTC (rev 393)
@@ -1,3 +1,10 @@
+CHANGES FROM VERSION 2.38.5
+
+* Implemented an on-disk file fingerprint cache to speed-up update
+  detection after a crash: this way, Unison does not have do recompute
+  all the file fingerprints from scratch.
+
+-------------------------------
 CHANGES FROM VERSION 2.38.0
 
 * Roll back a previous "fix" for a permission-setting issue and

Modified: trunk/src/copy.ml
===================================================================
--- trunk/src/copy.ml	2010-01-05 15:42:43 UTC (rev 392)
+++ trunk/src/copy.ml	2010-01-06 21:20:12 UTC (rev 393)
@@ -55,7 +55,7 @@
   let dataClearlyUnchanged =
     not clearlyModified
     && Props.same_time info.Fileinfo.desc archDesc
-    && not (Update.excelFile pathFrom)
+    && not (Fpcache.excelFile pathFrom)
     && match archStamp with
          Some (Fileinfo.InodeStamp inode) -> info.Fileinfo.inode = inode
        | Some (Fileinfo.CtimeStamp ctime) -> true

Added: trunk/src/fpcache.ml
===================================================================
--- trunk/src/fpcache.ml	                        (rev 0)
+++ trunk/src/fpcache.ml	2010-01-06 21:20:12 UTC (rev 393)
@@ -0,0 +1,251 @@
+(* Unison file synchronizer: src/fpcache.ml *)
+(* Copyright 1999-2010, Benjamin C. Pierce
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*)
+
+let debug = Trace.debug "fpcache"
+
+(* In-memory cache *)
+
+module PathTbl =
+  Hashtbl.Make
+    (struct
+       type t = string
+       let equal (s1 : string) (s2 : string) = s1 = s2
+       let hash = Hashtbl.hash
+     end)
+
+let tbl = PathTbl.create 101
+
+(* Information for writing to the on-disk cache *)
+
+type entry = int * string * (Fileinfo.t * Os.fullfingerprint)
+
+type state =
+  { oc : out_channel;
+    mutable count : int;
+    mutable size : Uutil.Filesize.t;
+    mutable last : string;
+    mutable queue : entry list }
+
+let state = ref None
+
+(****)
+
+(* Path compression and decompression (use delta from previous path for
+   compression) *)
+
+let decompress st i path =
+  let l = String.length path in
+  let s = String.create (l + i) in
+  String.blit !st 0 s 0 i;
+  String.blit path 0 s i l;
+  st := s;
+  s
+
+let compress state path =
+  let s = state.last in
+  let p = Path.toString path in
+  let l = String.length s in
+  let i = ref 0 in
+  while !i < l && p.[!i] = s.[!i] do incr i done;
+  state.last <- p;
+  (!i, String.sub p !i (String.length p - !i))
+
+(*****)
+
+(* Read and write a chunk of file fingerprints from the cache *)
+
+let read st ic =
+  (* I/O errors are dealt with at a higher level *)
+  let fp1 = Digest.input ic in
+  let fp2 = Digest.input ic in
+  let headerSize = Marshal.header_size in
+  let header = String.create headerSize in
+  really_input ic header 0 headerSize;
+  if fp1 <> Digest.string header then begin
+    debug (fun () -> Util.msg "bad header checksum\n");
+    raise End_of_file
+  end;
+  let dataSize = Marshal.data_size header 0 in
+  let s = String.create (headerSize + dataSize) in
+  String.blit header 0 s 0 headerSize;
+  really_input ic s headerSize dataSize;
+  if fp2 <> Digest.string s then begin
+    debug (fun () -> Util.msg "bad chunk checksum\n");
+    raise End_of_file
+  end;
+  let q : entry list = Marshal.from_string s 0 in
+  debug (fun () -> Util.msg "read chunk of %d files\n" (List.length q));
+  List.iter (fun (l, p, i) -> PathTbl.add tbl (decompress st l p) i) q
+
+let closeOut st =
+  state := None;
+  try
+    close_out st.oc
+  with Sys_error error ->
+    debug (fun () -> Util.msg "error in closing cache file: %s\n" error)
+
+let write state =
+  let q = Safelist.rev state.queue in
+  let s = Marshal.to_string q [Marshal.No_sharing] in
+  let fp1 = Digest.substring s 0 Marshal.header_size in
+  let fp2 = Digest.string s in
+  begin try
+    Digest.output state.oc fp1; Digest.output state.oc fp2;
+    output_string state.oc s; flush state.oc
+  with Sys_error error ->
+    debug (fun () -> Util.msg "error in writing to cache file: %s\n" error);
+    closeOut state
+  end;
+  state.count <- 0;
+  state.size <- Uutil.Filesize.zero;
+  state.queue <- []
+
+(****)
+
+(* Start and finish dealing with the cache *)
+
+let finish () =
+  PathTbl.clear tbl;
+  match !state with
+    Some st -> if st.queue <> [] then write st;
+               closeOut st
+  | None    -> ()
+
+let magic = "Unison fingerprint cache format 1"
+
+let init fastCheck fspath =
+  finish ();
+  if fastCheck then begin
+    begin try
+      let ic = System.open_in_bin fspath in
+      begin try
+        let header = input_line ic in
+        if header <> magic then raise (Sys_error "wrong header");
+        let st = ref "" in
+        while true do read st ic done
+      with
+        Sys_error error ->
+          debug (fun () -> Util.msg "error in loading cache file %s: %s\n"
+                             (System.fspathToDebugString fspath) error)
+      | End_of_file ->
+          ()
+      end;
+      begin try
+        close_in ic
+      with Sys_error error ->
+        debug (fun () -> Util.msg "error in closing cache file %s: %s\n"
+                             (System.fspathToDebugString fspath) error)
+      end;
+    with Sys_error error ->
+      debug (fun () -> Util.msg "could not open cache file %s: %s\n"
+                         (System.fspathToDebugString fspath) error)
+    end;
+    begin try
+      debug (fun () -> Util.msg "opening cache file %s for output\n"
+                         (System.fspathToDebugString fspath));
+      let oc =
+        System.open_out_gen
+          [Open_wronly; Open_creat; Open_trunc; Open_binary] 0o600 fspath in
+      output_string oc magic; output_string oc "\n"; flush oc;
+      state :=
+        Some { oc = oc; count = 0; size = Uutil.Filesize.zero;
+               last = ""; queue = [] }
+    with Sys_error error ->
+      debug (fun () -> Util.msg "could not open cache file %s: %s\n"
+                         (System.fspathToDebugString fspath) error)
+    end
+  end
+
+(****)
+
+(* Enqueue a fingerprint to be written to disk. *)
+
+let maxCount = 5000
+let maxSize = Uutil.Filesize.ofInt (100 * 1024 * 1024)
+
+let save path res =
+  match !state with
+    None ->
+      ()
+  | Some state ->
+      let (info, _) = res in
+      let l = Props.length info.Fileinfo.desc in
+      state.size <- Uutil.Filesize.add state.size l;
+      state.count <- state.count + 1;
+      let (l, s) = compress state path in
+      state.queue <- (l, s, res) :: state.queue;
+      if state.count > maxCount || state.size > maxSize then write state
+
+(****)
+
+(* Check whether a fingerprint is in the in-memory cache and store it
+   to the on-disk cache in any case. *)
+
+(* HACK: we disable fastcheck for Excel (and MPP) files, as Excel
+   sometimes modifies a file without updating the time stamp. *)
+let excelFile path =
+  let s = Path.toString path in
+     Util.endswith s ".xls"
+  || Util.endswith s ".mpp"
+
+let dataClearlyUnchanged fastCheck path info desc stamp =
+  fastCheck
+    &&
+  Props.same_time info.Fileinfo.desc desc
+    &&
+  Props.length info.Fileinfo.desc = Props.length desc
+    &&
+  not (excelFile path)
+    &&
+  match stamp with
+    Fileinfo.InodeStamp inode ->
+      info.Fileinfo.inode = inode
+  | Fileinfo.CtimeStamp ctime ->
+      (* BCP [Apr 07]: This doesn't work -- ctimes are unreliable
+                       under windows.  :-(
+         info.Fileinfo.ctime = ctime *)
+      true
+
+let ressClearlyUnchanged fastCheck info ress dataClearlyUnchanged =
+  fastCheck
+    &&
+  Osx.ressUnchanged ress info.Fileinfo.osX.Osx.ressInfo
+    None dataClearlyUnchanged
+
+let clearlyUnchanged fastCheck path newInfo oldInfo =
+  let du =
+    dataClearlyUnchanged fastCheck path newInfo
+      oldInfo.Fileinfo.desc (Fileinfo.stamp oldInfo)
+  in
+  du && ressClearlyUnchanged fastCheck newInfo (Fileinfo.ressStamp oldInfo) du
+
+let fingerprint fastCheck currfspath path info optDig =
+  let res =
+    try
+      let (oldInfo, _) as res = PathTbl.find tbl (Path.toString path) in
+      if not (clearlyUnchanged fastCheck path info oldInfo) then
+        raise Not_found;
+      debug (fun () -> Util.msg "cache hit for path %s\n"
+                         (Path.toDebugString path));
+      res
+    with Not_found ->
+      debug (fun () -> Util.msg "cache miss for path %s\n"
+                         (Path.toDebugString path));
+      Os.safeFingerprint currfspath path info optDig
+  in
+  save path res;
+  res

Added: trunk/src/fpcache.mli
===================================================================
--- trunk/src/fpcache.mli	                        (rev 0)
+++ trunk/src/fpcache.mli	2010-01-06 21:20:12 UTC (rev 393)
@@ -0,0 +1,20 @@
+(* Unison file synchronizer: src/fpcache.mli *)
+(* Copyright 1999-2010, Benjamin C. Pierce (see COPYING for details) *)
+
+(* Initialize the cache *)
+val init : bool -> System.fspath -> unit
+
+(* Close the cache file and clear the in-memory cache *)
+val finish : unit -> unit
+
+(* Get the fingerprint of a file, possibly from the cache *)
+val fingerprint :
+  bool -> Fspath.t -> Path.local -> Fileinfo.t -> Os.fullfingerprint option ->
+  Fileinfo.t * Os.fullfingerprint
+
+val dataClearlyUnchanged :
+  bool -> Path.local -> Fileinfo.t -> Props.t -> Fileinfo.stamp -> bool
+val ressClearlyUnchanged :
+  bool -> Fileinfo.t -> 'a Osx.ressInfo -> bool -> bool
+(* Is that a file for which fast checking is disabled? *)
+val excelFile : Path.local -> bool

Modified: trunk/src/mkProjectInfo.ml
===================================================================
--- trunk/src/mkProjectInfo.ml	2010-01-05 15:42:43 UTC (rev 392)
+++ trunk/src/mkProjectInfo.ml	2010-01-06 21:20:12 UTC (rev 393)
@@ -65,7 +65,7 @@
   Str.matched_group 1 str;;
 let extract_int re str = int_of_string (extract_str re str);;
 
-let revisionString = "$Rev: 388$";;
+let revisionString = "$Rev: 393$";;
 let pointVersion = if String.length revisionString > 5
 then Scanf.sscanf revisionString "$Rev: %d " (fun x -> x) - pointVersionOrigin
 else (* Determining the pointVersionOrigin in bzr is kind of tricky:
@@ -87,7 +87,3 @@
 Printf.printf "VERSION=%d.%d.%d\n" majorVersion minorVersion pointVersion;;
 Printf.printf "NAME=%s\n" projectName;;
 
-
-
-
-

Modified: trunk/src/path.ml
===================================================================
--- trunk/src/path.ml	2010-01-05 15:42:43 UTC (rev 392)
+++ trunk/src/path.ml	2010-01-06 21:20:12 UTC (rev 393)
@@ -192,6 +192,7 @@
 
 (* No need to perform case normalization on local paths *)
 let hash p = Hashtbl.hash p
+let equal (p1 : local) (p2 : local) = p1 = p2
 
 (* Pref controlling whether symlinks are followed. *)
 let followPred = Pred.create "follow"

Modified: trunk/src/path.mli
===================================================================
--- trunk/src/path.mli	2010-01-05 15:42:43 UTC (rev 392)
+++ trunk/src/path.mli	2010-01-06 21:20:12 UTC (rev 393)
@@ -31,6 +31,7 @@
 val addPrefixToFinalName : local -> string -> local
 
 val compare : t -> t -> int
+val equal : local -> local -> bool
 val hash : local -> int
 
 val followLink : local -> bool

Modified: trunk/src/update.ml
===================================================================
--- trunk/src/update.ml	2010-01-05 15:42:43 UTC (rev 392)
+++ trunk/src/update.ml	2010-01-06 21:20:12 UTC (rev 393)
@@ -165,7 +165,7 @@
 (* ----- *)
 
 (* The status of an archive *)
-type archiveVersion = MainArch | NewArch | ScratchArch | Lock
+type archiveVersion = MainArch | NewArch | ScratchArch | Lock | FPCache
 
 let showArchiveName =
   Prefs.createBool "showarchive" false
@@ -201,7 +201,8 @@
 let archiveName fspath (v: archiveVersion): string * string =
   let n = archiveHash fspath in
   let temp = match v with
-    MainArch -> "ar" | NewArch -> "tm" | ScratchArch -> "sc" | Lock -> "lk"
+    MainArch -> "ar" | NewArch -> "tm" | ScratchArch -> "sc"
+  | Lock     -> "lk" | FPCache   -> "fp"
   in
   (Printf.sprintf "%s%s" temp n,
    thisRootsGlobalName fspath)
@@ -1191,13 +1192,6 @@
              oldInfoOf archive)
   end
 
-(* HACK: we disable fastcheck for Excel (and MPP) files on Windows, as Excel
-   sometimes modifies a file without updating the time stamp. *)
-let excelFile path =
-  let s = Path.toString path in
-     Util.endswith s ".xls"
-  || Util.endswith s ".mpp"
-
 (* Check whether a file has changed has changed, by comparing its digest and
    properties against [archDesc], [archDig], and [archStamp].
    Returns a pair (optArch, ui) where [optArch] is *not* None when the file remains
@@ -1226,27 +1220,10 @@
              (Uutil.Filesize.toString  (Props.length info.Fileinfo.desc));
            Util.msg "\n");
   let dataClearlyUnchanged =
-    fastCheck
-      &&
-    Props.same_time info.Fileinfo.desc archDesc
-      &&
-    Props.length info.Fileinfo.desc = Props.length archDesc
-      &&
-    not (excelFile path)
-      &&
-    match archStamp with
-      Fileinfo.InodeStamp inode ->
-        info.Fileinfo.inode = inode
-    | Fileinfo.CtimeStamp ctime ->
-        (* BCP [Apr 07]: This doesn't work -- ctimes are unreliable
-                         under windows.  :-(  
-           info.Fileinfo.ctime = ctime *)
-        true in
+    Fpcache.dataClearlyUnchanged fastCheck path info archDesc archStamp in
   let ressClearlyUnchanged =
-    fastCheck
-      &&
-    Osx.ressUnchanged archRess info.Fileinfo.osX.Osx.ressInfo
-      None dataClearlyUnchanged in
+    Fpcache.ressClearlyUnchanged fastCheck info archRess dataClearlyUnchanged
+  in
   if dataClearlyUnchanged && ressClearlyUnchanged then begin
     Xferhint.insertEntry currfspath path archDig;
     None, checkPropChange info archive archDesc
@@ -1254,7 +1231,7 @@
     debugverbose (fun() -> Util.msg "  Double-check possibly updated file\n");
     showStatusAddLength info;
     let (info, newDigest) =
-      Os.safeFingerprint currfspath path info
+      Fpcache.fingerprint fastCheck currfspath path info
         (if dataClearlyUnchanged then Some archDig else None) in
     Xferhint.insertEntry currfspath path newDigest;
     debug (fun() -> Util.msg "  archive digest = %s   current digest = %s\n"
@@ -1492,7 +1469,9 @@
         None,
         begin
           showStatusAddLength info;
-          let (info, dig) = Os.safeFingerprint currfspath path info None in
+          let (info, dig) =
+            Fpcache.fingerprint
+              fastCheckInfos.fastCheck currfspath path info None in
           Xferhint.insertEntry currfspath path dig;
           Updates (File (info.Fileinfo.desc,
                          ContentsUpdated (dig, Fileinfo.stamp info,
@@ -1582,8 +1561,12 @@
           dirFastCheck = useFastChecking () && Util.osType = `Unix;
           dirStamp = dirStamp }
       in
+      let (cacheFilename, _) = archiveName fspath FPCache in
+      let cacheFile = Os.fileInUnisonDir cacheFilename in
+      Fpcache.init fastCheckInfos.fastCheck cacheFile;
       let (arch, ui) =
         buildUpdateRec archive fspath here fastCheckInfos in
+      Fpcache.finish ();
       (begin match arch with
          None      -> archive
        | Some arch -> arch
@@ -2067,7 +2050,7 @@
     &&
   Props.length desc = Props.length oldDesc
     &&
-  not (excelFile path)
+  not (Fpcache.excelFile path)
     &&
   Osx.ressUnchanged oldRess ress None true
 

Modified: trunk/src/update.mli
===================================================================
--- trunk/src/update.mli	2010-01-05 15:42:43 UTC (rev 392)
+++ trunk/src/update.mli	2010-01-06 21:20:12 UTC (rev 393)
@@ -64,9 +64,6 @@
 (* Are we checking fast, or carefully? *)
 val useFastChecking : unit -> bool
 
-(* Is that a file for which fast checking is disabled? *)
-val excelFile : Path.local -> bool
-
 (* Print the archive to the current formatter (see Format) *)
 val showArchive: archive -> unit
 



More information about the Unison-hackers mailing list