Reimplement growing and shrinking of messages vector.
authorChris Hanson <org/chris-hanson/cph>
Tue, 16 May 2000 22:07:38 +0000 (22:07 +0000)
committerChris Hanson <org/chris-hanson/cph>
Tue, 16 May 2000 22:07:38 +0000 (22:07 +0000)
v7/src/imail/imail-imap.scm

index 6fd7d2a7b7a77e704f1c1357e9f18ae352be4b29..67b59bab55eab4d88d4d817c3c980255dbdb8884 100644 (file)
@@ -1,6 +1,6 @@
 ;;; -*-Scheme-*-
 ;;;
-;;; $Id: imail-imap.scm,v 1.46 2000/05/16 18:59:42 cph Exp $
+;;; $Id: imail-imap.scm,v 1.47 2000/05/16 22:07:38 cph Exp $
 ;;;
 ;;; Copyright (c) 1999-2000 Massachusetts Institute of Technology
 ;;;
      (set-imap-folder-unseen! folder #f)
      (set-imap-folder-messages-synchronized?! folder #f)
      (set-imap-folder-n-messages! folder 0)
-     (set-imap-folder-messages! folder '#()))))
+     (set-imap-folder-messages! folder (initial-messages)))))
 
 (define (new-imap-folder-uidvalidity! folder uidvalidity)
   (without-interrupts
       (vector-set! v index (make-imap-message folder index)))))
 
 (define (read-message-headers! folder start)
-  ((imail-message-wrapper "Reading message headers")
-   (lambda ()
-     (imap:command:fetch-range (imap-folder-connection folder)
-                              start
-                              (folder-length folder)
-                              imap-header-keywords))))
-
+  (if (imap-folder-uidvalidity folder)
+      ((imail-message-wrapper "Reading message headers")
+       (lambda ()
+        (imap:command:fetch-range (imap-folder-connection folder)
+                                  start
+                                  (folder-length folder)
+                                  imap-header-keywords)))))
+\f
 (define (remove-imap-folder-message folder index)
   (without-interrupts
    (lambda ()
        (let ((n (fix:- n 1)))
         (vector-set! v n #f)
         (set-imap-folder-n-messages! folder n)
-        (if (fix:> (vector-length v) 16)
-            (let ((l (fix:quotient (vector-length v) 2)))
-              (if (fix:<= n l)
-                  (set-imap-folder-messages!
-                   folder
-                   (vector-head v (fix:max l 16))))))))))
+        (let ((new-length (compute-messages-length v n)))
+          (if new-length
+              (set-imap-folder-messages! folder
+                                         (vector-head v new-length))))))))
   (folder-modified! folder))
-\f
-;;; This needs explanation.  There are two basic cases.
+
+(define (initial-messages)
+  (make-vector 64 #f))
+
+(define (compute-messages-length v count)
+  (let ((old-length (vector-length v))
+       (min-length 64))
+    (if (> count old-length)
+       (let loop ((n (* old-length 2)))
+         (if (<= count n)
+             n
+             (loop (* n 2))))
+       (and (> old-length min-length)
+            (<= count (quotient old-length 2))
+            (let loop ((n (quotient old-length 2)))
+              (let ((n/2 (quotient n 2)))
+                (if (or (> count n/2) (= n min-length))
+                    n
+                    (loop n/2))))))))
+
+;;; SET-IMAP-FOLDER-LENGTH! needs explanation.  There are two basic
+;;; cases.
 
 ;;; In the first case, our folder is synchronized with the server,
 ;;; meaning that our folder has the same length and UIDs as the
 ;;; we must have everything in a consistent (if nonoptimal) state
 ;;; while reading.  If the read finishes, we can do the match/replace
 ;;; operation atomically.
-
+\f
 (define (set-imap-folder-length! folder count)
   (if (or (imap-folder-messages-synchronized? folder)
          (= 0 (imap-folder-n-messages folder)))
-      (read-message-headers!
-       folder
-       (without-interrupts
-       (lambda ()
-         (let ((v (imap-folder-messages folder))
-               (n (imap-folder-n-messages folder)))
-           (if (not (> count n))
-               (error "EXISTS response decreased folder length:" folder))
-           (if (> count (vector-length v))
-               (set-imap-folder-messages! folder (vector-grow v count #f)))
-           (set-imap-folder-n-messages! folder count)
-           (fill-messages-vector! folder n)
-           (folder-modified! folder)
-           n))))
+      (let ((n
+            (without-interrupts
+             (lambda ()
+               (let ((v (imap-folder-messages folder))
+                     (n (imap-folder-n-messages folder)))
+                 (cond ((> count n)
+                        (let ((new-length (compute-messages-length v count)))
+                          (if new-length
+                              (set-imap-folder-messages!
+                               folder
+                               (vector-grow v new-length #f))))
+                        (set-imap-folder-n-messages! folder count)
+                        (fill-messages-vector! folder n)
+                        (folder-modified! folder)
+                        n)
+                       ((< count n)
+                        (error "EXISTS response decreased folder length:"
+                               folder))
+                       (else #f)))))))
+       (if n
+           (read-message-headers! folder n)))
       (let ((v.n
             (without-interrupts
              (lambda ()
                (let ((v (imap-folder-messages folder))
                      (n (imap-folder-n-messages folder)))
                  (set-imap-folder-n-messages! folder count)
-                 (set-imap-folder-messages! folder (make-vector count #f))
+                 (set-imap-folder-messages!
+                  folder
+                  (make-vector (or (compute-messages-length v count)
+                                   (vector-length v))
+                               #f))
                  (fill-messages-vector! folder 0)
                  (set-imap-folder-messages-synchronized?! folder #t)
                  (folder-modified! folder)
           (imap:command:fetch-all (imap-folder-connection folder) '(UID))))
        (without-interrupts
         (lambda ()
-          (let ((v* (imap-folder-messages folder))
+          (let ((v (car v.n))
+                (n (cdr v.n))
+                (v* (imap-folder-messages folder))
                 (n* (imap-folder-n-messages folder)))
             (let loop ((i 0) (i* 0))
-              (if (and (fix:< i (cdr v.n)) (fix:< i* n*))
-                  (let ((m (vector-ref (car v.n) i))
+              (if (and (fix:< i n) (fix:< i* n*))
+                  (let ((m (vector-ref v i))
                         (m* (vector-ref v* i*)))
-                    (cond ((= (imap-message-uid m) (imap-message-uid m*))
-                           ;; Flags might have been updated while
-                           ;; reading the UIDs.
-                           (if (%message-flags-initialized? m*)
-                               (%set-message-flags! m (message-flags m*)))
-                           (detach-message! m*)
-                           (attach-message! m folder i*)
-                           (vector-set! v* i* m)
-                           (loop (fix:+ i 1) (fix:+ i* 1)))
-                          ((< (imap-message-uid m) (imap-message-uid m*))
-                           (loop (fix:+ i 1) i*))
-                          (else
-                           (loop i (fix:+ i* 1))))))))
+                    (if (= (imap-message-uid m) (imap-message-uid m*))
+                        (begin
+                          ;; Flags might have been updated while
+                          ;; reading the UIDs.
+                          (if (%message-flags-initialized? m*)
+                              (%set-message-flags! m (message-flags m*)))
+                          (detach-message! m*)
+                          (attach-message! m folder i*)
+                          (vector-set! v* i* m)
+                          (loop (fix:+ i 1) (fix:+ i* 1)))
+                        (loop (fix:+ i 1) i*))))))
           (folder-modified! folder))))))
 \f
 ;;;; Message datatype
                  (newline port)))))
         (imap:response:preauth? response))
        ((imap:response:exists? response)
-        (let ((count (imap:response:exists-count response))
-              (folder (imap-connection-folder connection)))
-          (if (not (and (imap-folder-messages-synchronized? folder)
-                        (= count (folder-length folder))))
-              (set-imap-folder-length! folder count)))
+        (set-imap-folder-length! (imap-connection-folder connection)
+                                 (imap:response:exists-count response))
         #f)
        ((imap:response:expunge? response)
         (let ((folder (imap-connection-folder connection)))