commit d576755380080653a385ac474b34b082396fca66
Author: Oswald Buddenhagen <o...@kde.org>
Date:   Sun Aug 26 13:36:12 2012 +0200

    use a hash table for message => sync record lookup
    
    this removes the pathological O(<number of sync records> * <number of
    new messages>) case at the cost of being a bit more cpu-intensive (but
    O(<number of all messages>)) for old messages.

 src/isync.h |    2 +
 src/sync.c  |   57 +++++++++++++++++++++++++++++---------------------
 src/util.c  |   18 ++++++++++++++++
 3 files changed, 53 insertions(+), 24 deletions(-)

diff --git a/src/isync.h b/src/isync.h
index efb365a..a60e468 100644
--- a/src/isync.h
+++ b/src/isync.h
@@ -442,6 +442,8 @@ void sort_ints( int *arr, int len );
 void arc4_init( void );
 unsigned char arc4_getbyte( void );
 
+int bucketsForSize( int size );
+
 #ifdef HAVE_SYS_POLL_H
 # include <sys/poll.h>
 #else
diff --git a/src/sync.c b/src/sync.c
index 45fc2cc..d9be535 100644
--- a/src/sync.c
+++ b/src/sync.c
@@ -146,7 +146,7 @@ typedef struct {
        channel_conf_t *chan;
        store_t *ctx[2];
        driver_t *drv[2];
-       int state[2], ref_count, ret, lfd;
+       int state[2], ref_count, nsrecs, ret, lfd;
        int new_total[2], new_done[2];
        int flags_total[2], flags_done[2];
        int trash_total[2], trash_done[2];
@@ -754,6 +754,7 @@ box_selected( int sts, void *aux )
                        srec->next = 0;
                        *svars->srecadd = srec;
                        svars->srecadd = &srec->next;
+                       svars->nsrecs++;
                }
                fclose( jfp );
        } else {
@@ -817,6 +818,7 @@ box_selected( int sts, void *aux )
                                        srec->next = 0;
                                        *svars->srecadd = srec;
                                        svars->srecadd = &srec->next;
+                                       svars->nsrecs++;
                                } else {
                                        for (nsrec = srec; srec; srec = 
srec->next)
                                                if (srec->uid[M] == t1 && 
srec->uid[S] == t2)
@@ -1001,6 +1003,11 @@ typedef struct {
        int aflags, dflags;
 } flag_vars_t;
 
+typedef struct {
+       int uid;
+       sync_rec_t *srec;
+} sync_rec_map_t;
+
 static void flags_set_del( int sts, void *aux );
 static void flags_set_sync( int sts, void *aux );
 static void flags_set_sync_p2( sync_vars_t *svars, sync_rec_t *srec, int t );
@@ -1013,13 +1020,14 @@ static void
 box_loaded( int sts, void *aux )
 {
        DECL_SVARS;
-       sync_rec_t *srec, *nsrec = 0;
+       sync_rec_t *srec;
+       sync_rec_map_t *srecmap;
        message_t *tmsg;
        copy_vars_t *cv;
        flag_vars_t *fv;
-       const char *diag;
        int uid, minwuid, *mexcs, nmexcs, rmexcs, no[2], del[2], todel, t1, t2;
        int sflags, nflags, aflags, dflags, nex;
+       unsigned hashsz, idx;
        char fbuf[16]; /* enlarge when support for keywords is added */
 
        if (check_ret( sts, aux ))
@@ -1035,13 +1043,20 @@ box_loaded( int sts, void *aux )
        }
        Fprintf( svars->jfp, "%c %d\n", "{}"[t], svars->ctx[t]->uidnext );
 
-       /*
-        * Mapping tmsg -> srec (this variant) is dog slow for new messages.
-        * Mapping srec -> tmsg is dog slow for deleted messages.
-        * One solution would be using binary search on an index array.
-        * msgs are already sorted by UID, srecs would have to be sorted by 
uid[t].
-        */
        debug( "matching messages on %s against sync records\n", str_ms[t] );
+       hashsz = bucketsForSize( svars->nsrecs * 3 );
+       srecmap = nfcalloc( hashsz * sizeof(*srecmap) );
+       for (srec = svars->srecs; srec; srec = srec->next) {
+               if (srec->status & S_DEAD)
+                       continue;
+               uid = srec->uid[t];
+               idx = (unsigned)((unsigned)uid * 1103515245U) % hashsz;
+               while (srecmap[idx].uid)
+                       if (++idx == hashsz)
+                               idx = 0;
+               srecmap[idx].uid = uid;
+               srecmap[idx].srec = srec;
+       }
        for (tmsg = svars->ctx[t]->msgs; tmsg; tmsg = tmsg->next) {
                if (tmsg->srec) /* found by TUID */
                        continue;
@@ -1050,21 +1065,14 @@ box_loaded( int sts, void *aux )
                        make_flags( tmsg->flags, fbuf );
                        printf( svars->ctx[t]->opts & OPEN_SIZE ? "  message 
%5d, %-4s, %6lu: " : "  message %5d, %-4s: ", uid, fbuf, tmsg->size );
                }
-               for (srec = nsrec; srec; srec = srec->next) {
-                       if (srec->status & S_DEAD)
-                               continue;
-                       if (srec->uid[t] == uid) {
-                               diag = srec == nsrec ? "adjacently" : "after 
gap";
-                               goto found;
-                       }
-               }
-               for (srec = svars->srecs; srec != nsrec; srec = srec->next) {
-                       if (srec->status & S_DEAD)
-                               continue;
-                       if (srec->uid[t] == uid) {
-                               diag = "after reset";
+               idx = (unsigned)((unsigned)uid * 1103515245U) % hashsz;
+               while (srecmap[idx].uid) {
+                       if (srecmap[idx].uid == uid) {
+                               srec = srecmap[idx].srec;
                                goto found;
                        }
+                       if (++idx == hashsz)
+                               idx = 0;
                }
                tmsg->srec = 0;
                debug( "new\n" );
@@ -1072,9 +1080,9 @@ box_loaded( int sts, void *aux )
          found:
                tmsg->srec = srec;
                srec->msg[t] = tmsg;
-               nsrec = srec->next;
-               debug( "pairs %5d %s\n", srec->uid[1-t], diag );
+               debug( "pairs %5d\n", srec->uid[1-t] );
        }
+       free( srecmap );
 
        if ((t == S) && svars->smaxxuid) {
                debug( "preparing master selection - max expired slave uid is 
%d\n", svars->smaxxuid );
@@ -1164,6 +1172,7 @@ box_loaded( int sts, void *aux )
                                                srec->next = 0;
                                                *svars->srecadd = srec;
                                                svars->srecadd = &srec->next;
+                                               svars->nsrecs++;
                                                srec->status = S_DONE;
                                                srec->flags = 0;
                                                srec->tuid[0] = 0;
diff --git a/src/util.c b/src/util.c
index c6a4a00..d3c6804 100644
--- a/src/util.c
+++ b/src/util.c
@@ -475,6 +475,24 @@ arc4_getbyte( void )
        return rs.s[(si + sj) & 0xff];
 }
 
+static const unsigned char prime_deltas[] = {
+    0,  0,  1,  3,  1,  5,  3,  3,  1,  9,  7,  5,  3,  9, 25,  3,
+    1, 21,  3, 21,  7, 15,  9,  5,  3, 29, 15,  0,  0,  0,  0,  0
+};
+
+int
+bucketsForSize( int size )
+{
+       int base = 4, bits = 2;
+
+       for (;;) {
+               int prime = base + prime_deltas[bits];
+               if (prime >= size)
+                       return prime;
+               base <<= 1;
+               bits++;
+       }
+}
 
 #ifdef HAVE_SYS_POLL_H
 static struct pollfd *pollfds;

------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
isync-devel mailing list
isync-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/isync-devel

Reply via email to