Removed the old version of the hashtable functions and updated
[rsync/rsync.git] / hlink.c
diff --git a/hlink.c b/hlink.c
index f52c0ed..a758693 100644 (file)
--- a/hlink.c
+++ b/hlink.c
@@ -7,8 +7,9 @@
  * Copyright (C) 2004-2007 Wayne Davison
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * 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
@@ -16,8 +17,7 @@
  * 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ * with this program; if not, visit the http://fsf.org website.
  */
 
 #include "rsync.h"
@@ -34,156 +34,38 @@ extern int stdout_format_has_i;
 extern int maybe_ATTRS_REPORT;
 extern char *basis_dir[];
 extern struct file_list *cur_flist;
+#ifdef ICONV_OPTION
+extern int ic_ndx;
+#endif
 
 #ifdef SUPPORT_HARD_LINKS
 
-#define HASH_LOAD_LIMIT(size) ((size)*3/4)
-#define FPTR(i) (cur_flist->files[i])
-
-struct ihash_table {
-       int32 size;
-       int32 entries;
-       struct idev_node *buckets;
-} *dev_tbl;
-
-static struct idev_node *ihash_node(struct ihash_table *tbl, int64 key);
-
 /* Starting with protocol 30, we use a simple hashtable on the sending side
  * for hashing the st_dev and st_ino info.  The receiving side gets told
  * (via flags and a "group index") which items are hard-linked together, so
  * we can avoid the pool of dev+inode data. */
 
-static struct ihash_table *ihash_create(int size)
-{
-       struct ihash_table *tbl;
-
-       /* Pick a power of 2 that can hold the requested size. */
-       if (size & (size-1) || size < 16) {
-               int req = size;
-               size = 16;
-               while (size < req)
-                       size *= 2;
-       }
-
-       if (!(tbl = new(struct ihash_table))
-        || !(tbl->buckets = new_array(struct idev_node, size)))
-               out_of_memory("ihash_create");
-       memset(tbl->buckets, 0, size * sizeof tbl->buckets[0]);
-       tbl->size = size;
-       tbl->entries = 0;
-
-       return tbl;
-}
-
-static void ihash_destroy(struct ihash_table *tbl)
-{
-       free(tbl->buckets);
-       free(tbl);
-}
+struct hashtable *dev_tbl;
 
 void init_hard_links(void)
 {
-       dev_tbl = ihash_create(16);
+       dev_tbl = hashtable_create(16, SIZEOF_INT64 == 8);
 }
 
-static void expand_ihash(struct ihash_table *tbl)
+struct ht_int64_node *idev_find(int64 dev, int64 ino)
 {
-       struct idev_node *old_buckets = tbl->buckets;
-       int size = tbl->size * 2;
-       int i;
-
-       if (!(tbl->buckets = new_array(struct idev_node, size)))
-               out_of_memory("ihash_create");
-       memset(tbl->buckets, 0, size * sizeof (struct idev_node));
-       tbl->size = size;
-       tbl->entries = 0;
-
-       for (i = size / 2; i-- > 0; ) {
-               int64 key = old_buckets[i].key;
-               if (key == 0)
-                       continue;
-               ihash_node(tbl, key)->data = old_buckets[i].data;
-       }
-
-       free(old_buckets);
-}
-
-/* This returns the node for the indicated key, either newly created,
- * or already existing. */
-static struct idev_node *ihash_node(struct ihash_table *tbl, int64 key)
-{
-       uint32 bkt;
-
-       if (tbl->entries > HASH_LOAD_LIMIT(tbl->size))
-               expand_ihash(tbl);
-
-#if SIZEOF_INT64 < 8
-       /* Based on Jenkins One-at-a-time hash. */
-       {
-               uchar *keyp = (uchar*)&key;
-               int i;
-
-               for (bkt = 0, i = 0; i < SIZEOF_INT64; i++) {
-                       bkt += keyp[i];
-                       bkt += (bkt << 10);
-                       bkt ^= (bkt >> 6);
-               }
-               bkt += (bkt << 3);
-               bkt ^= (bkt >> 11);
-               bkt += (bkt << 15);
-       }
-#else
-#define rot(x,k) (((x)<<(k)) ^ ((x)>>(32-(k))))
-       /* Based on Jenkins hashword() from lookup3.c. */
-       {
-               uint32 a, b, c;
-
-               /* Set up the internal state */
-               a = b = c = 0xdeadbeef + (8 << 2);
-
-               b += (uint32)(key >> 32);
-               a += (uint32)key;
-               c ^= b; c -= rot(b, 14);
-               a ^= c; a -= rot(c, 11);
-               b ^= a; b -= rot(a, 25);
-               c ^= b; c -= rot(b, 16);
-               a ^= c; a -= rot(c, 4);
-               b ^= a; b -= rot(a, 14);
-               c ^= b; c -= rot(b, 24);
-               bkt = c;
-       }
-#endif
-
-       /* If it already exists, return it. */
-       while (1) {
-               bkt &= tbl->size - 1;
-               if (tbl->buckets[bkt].key == key)
-                       return &tbl->buckets[bkt];
-               if (tbl->buckets[bkt].key == 0)
-                       break;
-               bkt++;
-       }
-
-       /* Otherwise, take over this empty spot and then return it. */
-       tbl->buckets[bkt].key = key;
-       tbl->entries++;
-       return &tbl->buckets[bkt];
-}
-
-struct idev_node *idev_node(int64 dev, int64 ino)
-{
-       static struct idev_node *dev_node = NULL;
-       struct ihash_table *tbl;
+       static struct ht_int64_node *dev_node = NULL;
+       struct hashtable *tbl;
 
        if (!dev_node || dev_node->key != dev) {
                /* We keep a separate hash table of inodes for every device. */
-               dev_node = ihash_node(dev_tbl, dev);
+               dev_node = hashtable_find(dev_tbl, dev, 1);
                if (!(tbl = dev_node->data))
-                       tbl = dev_node->data = ihash_create(512);
+                       tbl = dev_node->data = hashtable_create(512, SIZEOF_INT64 == 8);
        } else
                tbl = dev_node->data;
 
-       return ihash_node(tbl, ino);
+       return hashtable_find(tbl, ino, 1);
 }
 
 void idev_destroy(void)
@@ -191,17 +73,18 @@ void idev_destroy(void)
        int i;
 
        for (i = 0; i < dev_tbl->size; i++) {
-               if (dev_tbl->buckets[i].data)
-                       ihash_destroy(dev_tbl->buckets[i].data);
+               struct ht_int32_node *node = HT_NODE(dev_tbl, dev_tbl->nodes, i);
+               if (node->data)
+                       hashtable_destroy(node->data);
        }
 
-       ihash_destroy(dev_tbl);
+       hashtable_destroy(dev_tbl);
 }
 
 static int hlink_compare_gnum(int *int1, int *int2)
 {
-       struct file_struct *f1 = FPTR(*int1);
-       struct file_struct *f2 = FPTR(*int2);
+       struct file_struct *f1 = cur_flist->sorted[*int1];
+       struct file_struct *f2 = cur_flist->sorted[*int2];
        int32 gnum1 = F_HL_GNUM(f1);
        int32 gnum2 = F_HL_GNUM(f2);
 
@@ -221,17 +104,24 @@ static void match_gnums(int32 *ndx_list, int ndx_count)
             (int (*)()) hlink_compare_gnum);
 
        for (from = 0; from < ndx_count; from++) {
-               for (file = FPTR(ndx_list[from]), gnum = F_HL_GNUM(file), prev = -1;
+               for (file = cur_flist->sorted[ndx_list[from]], gnum = F_HL_GNUM(file), prev = -1;
                     from < ndx_count-1;
-                    file = file_next, gnum = gnum_next, prev = ndx_list[from++])
+                    file = file_next, gnum = gnum_next, from++) /*SHARED ITERATOR*/
                {
-                       file_next = FPTR(ndx_list[from+1]);
+                       file_next = cur_flist->sorted[ndx_list[from+1]];
                        gnum_next = F_HL_GNUM(file_next);
                        if (gnum != gnum_next)
                                break;
                        if (prev < 0)
                                file->flags |= FLAG_HLINK_FIRST;
                        F_HL_PREV(file) = prev;
+                       /* The linked list must use raw ndx values. */
+#ifdef ICONV_OPTION
+                       if (ic_ndx)
+                               prev = F_NDX(file);
+                       else
+#endif
+                               prev = ndx_list[from];
                }
                if (prev < 0)
                        file->flags &= ~FLAG_HLINKED;
@@ -251,11 +141,11 @@ void match_hard_links(void)
        int i, ndx_count = 0;
        int32 *ndx_list;
 
-       if (!(ndx_list = new_array(int32, cur_flist->count)))
+       if (!(ndx_list = new_array(int32, cur_flist->used)))
                out_of_memory("match_hard_links");
 
-       for (i = 0; i < cur_flist->count; i++) {
-               if (F_IS_HLINKED(FPTR(i)))
+       for (i = 0; i < cur_flist->used; i++) {
+               if (F_IS_HLINKED(cur_flist->sorted[i]))
                        ndx_list[ndx_count++] = i;
        }
 
@@ -317,7 +207,7 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
        STRUCT_STAT prev_st;
        char prev_name[MAXPATHLEN], altbuf[MAXPATHLEN], *realname;
        int alt_dest, prev_ndx = F_HL_PREV(file);
-       struct file_struct *prev_file = FPTR(prev_ndx);
+       struct file_struct *prev_file = cur_flist->files[prev_ndx];
 
        /* Is the previous link is not complete yet? */
        if (!(prev_file->flags & FLAG_HLINK_DONE)) {
@@ -338,7 +228,7 @@ int hard_link_check(struct file_struct *file, int ndx, const char *fname,
        if (!(prev_file->flags & FLAG_HLINK_FIRST)) {
                /* The previous previous will be marked with FIRST. */
                prev_ndx = F_HL_PREV(prev_file);
-               prev_file = FPTR(prev_ndx);
+               prev_file = cur_flist->files[prev_ndx];
                /* Update our previous pointer to point to the first. */
                F_HL_PREV(file) = prev_ndx;
        }
@@ -475,7 +365,7 @@ void finish_hard_link(struct file_struct *file, const char *fname,
 
        while ((ndx = prev_ndx) >= 0) {
                int val;
-               file = FPTR(ndx);
+               file = cur_flist->files[ndx];
                file->flags = (file->flags & ~FLAG_HLINK_FIRST) | FLAG_HLINK_DONE;
                prev_ndx = F_HL_PREV(file);
                prev_name = f_name(file, NULL);