memory reduction
jw schultz
jw at pegasys.ws
Fri Feb 6 10:09:07 GMT 2004
On Thu, Feb 05, 2004 at 09:27:51PM -0800, jw schultz wrote:
> As those of you who watch CVS will be aware Wayne has been
> making progress in reducing memory requirements of rsync.
> Much of what he has done has been the product of discussions
> between he and myself that started a month ago with John Van
> Essen.
>
> Most recently Wayne has changed how the file_struct and its
> associated data are allocated, eliminating the string areas.
> Most of these changes have been small and relatively low
> impact although combining the allocation of the file_struct
> with the strings does impact the memory management of
> file_struct.
>
> Attached is a patch that implements the next step. It
> alters flist memory management and introduces a MM pool
> layer that reduces malloc overhead and allows destructors to
> actually release memory to the OS.
>
> The patch adds a couple of new files so use patch -p1
> and rerun ./configure after patching.
Here is an update of the patch to cope with patch conflicts
re CVS HEAD.
diff -rupNP --exclude-from cvs/.ignore cvs/Makefile.in pool2/Makefile.in
--- cvs/Makefile.in Tue Feb 3 16:34:24 2004
+++ pool2/Makefile.in Tue Feb 3 16:33:00 2004
@@ -27,7 +27,7 @@ VERSION=@VERSION@
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o \
- lib/permstring.o @LIBOBJS@
+ lib/permstring.o lib/pool_alloc.o @LIBOBJS@
ZLIBOBJ=zlib/deflate.o zlib/infblock.o zlib/infcodes.o zlib/inffast.o \
zlib/inflate.o zlib/inftrees.o zlib/infutil.o zlib/trees.o \
zlib/zutil.o zlib/adler32.o
diff -rupNP --exclude-from cvs/.ignore cvs/backup.c pool2/backup.c
--- cvs/backup.c Wed Feb 4 03:49:36 2004
+++ pool2/backup.c Wed Feb 4 22:11:26 2004
@@ -189,6 +189,7 @@ static int keep_backup(char *fname)
backup_dir[--backup_dir_len] = '\0';
if (verbose > 0)
rprintf(FINFO, "backup_dir is %s\n", backup_dir);
+
initialised = 1;
}
@@ -199,7 +200,7 @@ static int keep_backup(char *fname)
if (do_stat(fname, &st)) return 1;
#endif
- file = make_file(fname, NO_EXCLUDES);
+ file = make_file(fname, NULL, NO_EXCLUDES);
/* the file could have disappeared */
if (!file) return 1;
@@ -282,7 +283,7 @@ static int keep_backup(char *fname)
}
}
set_perms(keep_name, file, NULL, 0);
- free_file(file, FREE_STRUCT);
+ free(file);
if (verbose > 1)
rprintf(FINFO, "keep_backup %s -> %s\n", fname, keep_name);
diff -rupNP --exclude-from cvs/.ignore cvs/batch.c pool2/batch.c
--- cvs/batch.c Fri Feb 6 01:54:56 2004
+++ pool2/batch.c Fri Feb 6 02:00:58 2004
@@ -136,9 +136,7 @@ struct file_list *create_flist_from_batc
exit_cleanup(1);
}
- batch_flist = new(struct file_list);
- if (!batch_flist)
- out_of_memory("create_flist_from_batch");
+ batch_flist = flist_new(WITH_HLINK, "create_flist_from_batch");
save_read = stats.total_read;
save_pv = protocol_version;
@@ -150,9 +148,9 @@ struct file_list *create_flist_from_batc
for (i = 0; (flags = read_byte(f)) != 0; i++) {
if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS))
flags |= read_byte(f) << 8;
- receive_file_entry(&batch_flist->files[i], flags, f);
+ receive_file_entry(&batch_flist->files[i], flags, batch_flist, f);
}
- receive_file_entry(NULL, 0, 0); /* Signal that we're done. */
+ receive_file_entry(NULL, 0, NULL, 0); /* Signal that we're done. */
protocol_version = save_pv;
stats.total_read = save_read;
diff -rupNP --exclude-from cvs/.ignore cvs/flist.c pool2/flist.c
--- cvs/flist.c Fri Feb 6 01:55:41 2004
+++ pool2/flist.c Fri Feb 6 02:00:59 2004
@@ -76,7 +76,6 @@ static unsigned int min_file_struct_len;
static void clean_flist(struct file_list *flist, int strip_root, int no_dups);
static void output_flist(struct file_list *flist);
-
void init_flist(void)
{
struct file_struct f;
@@ -507,7 +506,8 @@ void send_file_entry(struct file_struct
-void receive_file_entry(struct file_struct **fptr, unsigned short flags, int f)
+void receive_file_entry(struct file_struct **fptr, unsigned short flags,
+ struct file_list *flist, int f)
{
static time_t modtime;
static mode_t mode;
@@ -624,12 +624,12 @@ void receive_file_entry(struct file_stru
idev_len = 0;
sum_len = always_checksum && S_ISREG(mode) ? MD4_SUM_LENGTH : 0;
- file_struct_len = idev_len? sizeof file[0] : min_file_struct_len;
+ file_struct_len = min_file_struct_len;
alloc_len = file_struct_len + dirname_len + basename_len
- + linkname_len + sum_len + idev_len;
- if (!(bp = new_array(char, alloc_len)))
- out_of_memory("receive_file_entry");
+ + linkname_len + sum_len;
+ bp = pool_alloc(flist->file_pool, alloc_len, "receive_file_entry");
+
file = *fptr = (struct file_struct *)bp;
memset(bp, 0, min_file_struct_len);
bp += file_struct_len;
@@ -642,9 +642,9 @@ void receive_file_entry(struct file_stru
file->gid = gid;
#if SUPPORT_HARD_LINKS
- if (idev_len) {
- file->link_u.idev = (struct idev *)bp;
- bp += idev_len;
+ if (idev_len && flist->hlink_pool) {
+ file->link_u.idev = pool_talloc(flist->hlink_pool,
+ struct idev, 1, "inode_table");
}
#endif
@@ -676,15 +676,19 @@ void receive_file_entry(struct file_stru
#if SUPPORT_HARD_LINKS
if (idev_len) {
+ INO64_T inode;
if (protocol_version < 26) {
dev = read_int(f);
- file->F_INODE = read_int(f);
+ inode = read_int(f);
} else {
if (!(flags & XMIT_SAME_DEV))
dev = read_longint(f);
- file->F_INODE = read_longint(f);
+ inode = read_longint(f);
+ }
+ if (flist->hlink_pool) {
+ file->F_INODE = inode;
+ file->F_DEV = dev;
}
- file->F_DEV = dev;
}
#endif
@@ -728,7 +732,8 @@ void receive_file_entry(struct file_stru
* statting directories if we're not recursing, but this is not a very
* important case. Some systems may not have d_type.
**/
-struct file_struct *make_file(char *fname, int exclude_level)
+struct file_struct *make_file(char *fname,
+ struct file_list *flist, int exclude_level)
{
static char *lastdir;
static int lastdir_len = -1;
@@ -742,6 +747,7 @@ struct file_struct *make_file(char *fnam
char *basename, *dirname, *bp;
unsigned short flags = 0;
+
if (strlcpy(thisname, fname, sizeof thisname)
>= sizeof thisname - flist_dir_len) {
rprintf(FINFO, "skipping overly long name: %s\n", fname);
@@ -838,12 +844,18 @@ struct file_struct *make_file(char *fnam
idev_len = 0;
sum_len = always_checksum && S_ISREG(st.st_mode) ? MD4_SUM_LENGTH : 0;
- file_struct_len = idev_len? sizeof file[0] : min_file_struct_len;
+ file_struct_len = min_file_struct_len;
alloc_len = file_struct_len + dirname_len + basename_len
- + linkname_len + sum_len + idev_len;
- if (!(bp = new_array(char, alloc_len)))
- out_of_memory("receive_file_entry");
+ + linkname_len + sum_len;
+ if (flist) {
+ bp = pool_alloc(flist->file_pool, alloc_len,
+ "receive_file_entry");
+ } else {
+ if (!(bp = new_array(char, alloc_len)))
+ out_of_memory("receive_file_entry");
+ }
+
file = (struct file_struct *)bp;
memset(bp, 0, min_file_struct_len);
bp += file_struct_len;
@@ -856,9 +868,9 @@ struct file_struct *make_file(char *fnam
file->gid = st.st_gid;
#if SUPPORT_HARD_LINKS
- if (idev_len) {
- file->link_u.idev = (struct idev *)bp;
- bp += idev_len;
+ if (idev_len && flist && flist->hlink_pool) {
+ file->link_u.idev = pool_talloc(flist->hlink_pool,
+ struct idev, 1, "inode_table");
file->F_DEV = st.st_dev;
file->F_INODE = st.st_ino;
}
@@ -913,9 +925,8 @@ void send_file_name(int f, struct file_l
extern int delete_excluded;
/* f is set to -1 when calculating deletion file list */
- file = make_file(fname,
- f == -1 && delete_excluded? SERVER_EXCLUDES
- : ALL_EXCLUDES);
+ file = make_file(fname, flist,
+ f == -1 && delete_excluded? SERVER_EXCLUDES : ALL_EXCLUDES);
if (!file)
return;
@@ -1034,9 +1045,12 @@ struct file_list *send_file_list(int f,
start_write = stats.total_written;
- flist = flist_new();
+ flist = flist_new(f == -1 ? WITHOUT_HLINK : WITH_HLINK,
+ "send_file_list");
if (f != -1) {
+ flist->hlink_pool = pool_create(128 * 1024,
+ sizeof (struct idev), out_of_memory, POOL_INTERN);
io_start_buffering_out(f);
if (filesfrom_fd >= 0) {
if (argv[0] && !push_dir(argv[0])) {
@@ -1185,6 +1199,12 @@ struct file_list *send_file_list(int f,
finish_filelist_progress(flist);
}
+ if (flist->hlink_pool)
+ {
+ pool_destroy(flist->hlink_pool);
+ flist->hlink_pool = NULL;
+ }
+
clean_flist(flist, 0, 0);
if (f != -1) {
@@ -1224,10 +1244,10 @@ struct file_list *recv_file_list(int f)
start_read = stats.total_read;
- flist = new(struct file_list);
- if (!flist)
- goto oom;
+ flist = flist_new(WITH_HLINK, "recv_file_list");
+ flist->hlink_pool = pool_create(128 * 1024, sizeof (struct idev),
+ out_of_memory, POOL_INTERN);
flist->count = 0;
flist->malloced = 1000;
flist->files = new_array(struct file_struct *, flist->malloced);
@@ -1242,7 +1262,7 @@ struct file_list *recv_file_list(int f)
if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS))
flags |= read_byte(f) << 8;
- receive_file_entry(&flist->files[i], flags, f);
+ receive_file_entry(&flist->files[i], flags, flist, f);
if (S_ISREG(flist->files[i]->mode))
stats.total_size += flist->files[i]->length;
@@ -1256,7 +1276,7 @@ struct file_list *recv_file_list(int f)
f_name(flist->files[i]));
}
}
- receive_file_entry(NULL, 0, 0); /* Signal that we're done. */
+ receive_file_entry(NULL, 0, NULL, 0); /* Signal that we're done. */
if (verbose > 2)
rprintf(FINFO, "received %d names\n", flist->count);
@@ -1345,34 +1365,42 @@ int flist_find(struct file_list *flist,
return -1;
}
-
/*
- * Free up any resources a file_struct has allocated, and optionally free
- * it up as well.
+ * Free up any resources a file_struct has allocated
+ * and clear the file.
*/
-void free_file(struct file_struct *file, int free_the_struct)
+void clear_file(int i, struct file_list *flist)
{
- if (free_the_struct)
- free(file);
- else
- memset(file, 0, min_file_struct_len);
+ if (flist->hlink_pool && flist->files[i]->link_u.idev)
+ pool_free(flist->hlink_pool, 0, flist->files[i]->link_u.idev);
+ memset(flist->files[i], 0, min_file_struct_len);
}
/*
* allocate a new file list
*/
-struct file_list *flist_new(void)
+struct file_list *flist_new(int with_hlink, char *msg)
{
struct file_list *flist;
flist = new(struct file_list);
if (!flist)
- out_of_memory("send_file_list");
+ out_of_memory(msg);
- flist->count = 0;
- flist->malloced = 0;
- flist->files = NULL;
+ memset(flist, 0, sizeof (struct file_list));
+
+ if (!(flist->file_pool = pool_create(FILE_EXTENT, 0,
+ out_of_memory, POOL_INTERN)))
+ out_of_memory(msg);
+
+#if SUPPORT_HARD_LINKS
+ if (with_hlink && preserve_hard_links) {
+ if (!(flist->hlink_pool = pool_create(HLINK_EXTENT, 0,
+ out_of_memory, POOL_INTERN)))
+ out_of_memory(msg);
+ }
+#endif
return flist;
}
@@ -1382,9 +1410,8 @@ struct file_list *flist_new(void)
*/
void flist_free(struct file_list *flist)
{
- int i;
- for (i = 1; i < flist->count; i++)
- free_file(flist->files[i], FREE_STRUCT);
+ pool_destroy(flist->file_pool);
+ pool_destroy(flist->hlink_pool);
free(flist->files);
free(flist);
}
@@ -1424,7 +1451,8 @@ static void clean_flist(struct file_list
* else deletions will mysteriously fail with -R). */
if (flist->files[i]->flags & FLAG_TOP_DIR)
flist->files[prev_i]->flags |= FLAG_TOP_DIR;
- free_file(flist->files[i], CLEAR_STRUCT);
+
+ clear_file(i, flist);
} else
prev_i = i;
}
Binary files cvs/getgroups and pool2/getgroups differ
diff -rupNP --exclude-from cvs/.ignore cvs/hlink.c pool2/hlink.c
--- cvs/hlink.c Mon Feb 2 22:21:19 2004
+++ pool2/hlink.c Wed Feb 4 01:35:49 2004
@@ -46,26 +46,41 @@ int hlink_count;
/* Analyze the data in the hlink_list[], remove items that aren't multiply
* linked, and replace the dev+inode data with the hlindex+next linked list. */
-static void link_idev_data(void)
+static void link_idev_data(struct file_list *flist)
{
struct file_struct *head;
int from, to, start;
+ alloc_pool_t hlink_pool;
+ alloc_pool_t idev_pool = flist->hlink_pool;
+
+ hlink_pool = pool_create(128 * 1024, sizeof (struct hlink),
+ out_of_memory, POOL_INTERN);
+
for (from = to = 0; from < hlink_count; from++) {
start = from;
head = hlink_list[start];
while (from < hlink_count-1
&& LINKED(hlink_list[from], hlink_list[from+1])) {
+ pool_free(idev_pool, 0, hlink_list[from]->link_u.idev);
+ hlink_list[from]->link_u.links = pool_talloc(hlink_pool,
+ struct hlink, 1, "hlink_list");
+
hlink_list[from]->F_HLINDEX = to;
hlink_list[from]->F_NEXT = hlink_list[from+1];
from++;
}
if (from > start) {
+ pool_free(idev_pool, 0, hlink_list[from]->link_u.idev);
+ hlink_list[from]->link_u.links = pool_talloc(hlink_pool,
+ struct hlink, 1, "hlink_list");
+
hlink_list[from]->F_HLINDEX = to;
hlink_list[from]->F_NEXT = head;
hlink_list[from]->flags |= FLAG_HLINK_EOL;
hlink_list[to++] = head;
} else {
+ pool_free(idev_pool, 0, head->link_u.idev);
head->link_u.idev = NULL;
}
}
@@ -73,12 +88,16 @@ static void link_idev_data(void)
if (!to) {
free(hlink_list);
hlink_list = NULL;
+ pool_destroy(hlink_pool);
+ hlink_pool = NULL;
} else {
hlink_count = to;
if (!(hlink_list = realloc_array(hlink_list,
struct file_struct *, hlink_count)))
out_of_memory("init_hard_links");
}
+ flist->hlink_pool = hlink_pool;
+ pool_destroy(idev_pool);
}
#endif
@@ -109,7 +128,7 @@ void init_hard_links(struct file_list *f
free(hlink_list);
hlink_list = NULL;
} else
- link_idev_data();
+ link_idev_data(flist);
#endif
}
diff -rupNP --exclude-from cvs/.ignore cvs/lib/pool_alloc.3 pool2/lib/pool_alloc.3
--- cvs/lib/pool_alloc.3 Wed Dec 31 16:00:00 1969
+++ pool2/lib/pool_alloc.3 Tue Feb 3 16:30:24 2004
@@ -0,0 +1,199 @@
+.ds d \-\^\-
+.ds o \fR[\fP
+.ds c \fR]\fP
+.ds | \fR|\fP
+.de D
+\\.B \*d\\$1
+..
+.de DI
+\\.BI \*d\\$1 \\$2
+..
+.de DR
+\\.BR \*d\\$1 \\$2
+..
+.de Di
+\\.BI \*d\\$1 " \\$2"
+..
+.de Db
+\\.B \*d\\$1 " \\$2"
+..
+.de Df
+\\.B \*d\*ono\*c\\$1
+..
+.de See
+See \fB\\$1\fP for details.
+..
+.de SeeIn
+See \fB\\$1\fP in \fB\\$2\fP for details.
+..
+.TH POOL_ALLOC 3
+.SH NAME
+pool_alloc, pool_free, pool_talloc, pool_tfree, pool_create, pool_destroy
+\- Allocate and free memory in managed allocation pools.
+.SH SYNOPSIS
+.B #include "pool_alloc.h"
+
+\fBstruct alloc_pool *pool_create(size_t \fIsize\fB, size_t \fIquantum\fB, void (*\fIbomb\fB)(char *), int \fIflags\fB);
+
+\fBvoid pool_destroy(struct alloc_pool *\fIpool\fB);
+
+\fBvoid *pool_alloc(struct alloc_pool *\fIpool\fB, size_t \fIsize\fB, char *\fImsg\fB);
+
+\fBvoid pool_free(struct alloc_pool *\fIpool\fB, sise_t \fIsize\fB, void *\fIaddr\fB);
+
+\fBvoid *pool_talloc(struct alloc_pool *\fIpool\fB, \fItype\fB), int \fIcount\fB, char *\fImsg\fB);
+
+\fBvoid pool_tfree(struct alloc_pool *\fIpool\fB, \fItype\fB, int \fIcount\fB, void *\fIaddr\fB);
+.SH DESCRIPTION
+.P
+The pool allocation routines use
+.B malloc()
+for underlying memory management.
+What allocation pools do is cause
+memory within a given pool to be in large contigious blocks
+(called extents) that when freed will be reusable. Unlike
+.B malloc()
+the allocations are not managed individually.
+Instead each extent tracks the total free memory within the
+extent. Each extent can either be used to allocate memory
+or to manage the freeing of memory within that extent.
+When an extent has less free memory than a given
+allocation request or when the first request to free
+memory within that extent is received the extent ceases to
+be used for allocation.
+.P
+This form of memory management is suited to large numbers of small
+related allocations that are held for a while
+and then freed as a group.
+Because the
+underlying allocations are done in large contigious extents
+when an extent is freed it releases a large enough
+contigious block of memory to be useful to subsequent
+.B malloc()
+and
+.B pool_alloc()
+calls even if allocations from other pools or from
+.B malloc()
+are made between allocations from a given pool.
+.P
+.B pool_create()
+Creates an allocation pool for subsequent calls to the pool
+allocation functions.
+When an extent is created for allocations it will be
+.I size
+bytes.
+Allocations from the pool have their sizes rounded up to a
+multiple of
+.I quantum
+bytes in length.
+Specifying
+.B 0
+for
+.I quantum
+Will produce a quantum that should meet maximal allignment
+on most platforms.
+If the
+.B POOL_QALIGN
+.I flag
+is set allocations will be aligned to addresses that are a
+multiple of
+.IR quantum .
+If the
+.B POOL_CLEAR
+.I flag
+is set all allocations from the pool will be zero filled.
+.P
+.B pool_destroy()
+destroys an allocation pool and frees all memory allocated
+in that pool.
+.P
+.B pool_alloc()
+allocates
+.I size
+bytes from the specified
+.IR pool .
+If
+.I size
+is
+.B 0
+.I quantum
+bytes will be freed.
+If the requested memory cannot be allocated
+.B pool_alloc()
+will call
+.I bomb()
+function, if defined, with
+.I msg
+as it's sole argument and
+.B NULL
+will be returned.
+.P
+.B pool_free()
+frees
+.I size
+bytes pointed to by
+.I addr
+previously allocated in the specified
+.IR pool .
+The memory freed within an extent will not be reusable until
+all of the memory in that extent has been freed but
+depending on the order in which the
+allocations are freed some extents may be released for reuse
+while others are still in use.
+If
+.I size
+is
+.B 0
+.I quantum
+bytes will be freed.
+If
+.I addr
+is
+.B 0
+no memory will be freed but subsequent allocations will come
+from a new extent.
+.P
+.B pool_talloc()
+is a macro that take a
+.I type
+and
+.I count
+instead of
+.I size
+and will cast the return value to the correct type.
+.P
+.B pool_tfree
+is a macro to free memory previously allocated in the
+specified
+.IR pool .
+.SH RETURN VALUE
+.B pool_create()
+returns a pointer to
+.BR "struct alloc_pool" .
+.P
+.B pool_alloc()
+and
+.B pool_talloc()
+return pointers to the allocated memory,
+or NULL if the request fails.
+For each extent so long as no allocations are smaller than varaible
+allignment requirements this pointer will be suitably
+alligned for any kind of variable.
+The return type of
+.B pool_alloc()
+will normally require casting to the desired type but
+.B pool_talloc()
+will returns a pointer of the requested
+.IR type .
+.P
+.BR pool_free() ,
+.B pool_tfree()
+and
+.B pool_destroy()
+return no value.
+.SH SEE ALSO
+.nf
+malloc(3)
+.SH AUTHOR
+pool_alloc was created by J.W. Schultz of Pegasystems Technologies.
+.SH BUGS AND ISSUES
diff -rupNP --exclude-from cvs/.ignore cvs/lib/pool_alloc.c pool2/lib/pool_alloc.c
--- cvs/lib/pool_alloc.c Wed Dec 31 16:00:00 1969
+++ pool2/lib/pool_alloc.c Thu Feb 5 19:28:58 2004
@@ -0,0 +1,311 @@
+#include "rsync.h"
+
+#define POOL_DEF_EXTENT (32 * 1024)
+
+struct alloc_pool
+{
+ size_t size; /* extent size */
+ size_t quantum; /* allocation quantum */
+ struct pool_extent *live; /* current extent for
+ * allocations */
+ struct pool_extent *free; /* unfreed extent list */
+ void (*bomb)();
+ /* function to call if
+ * malloc fails */
+ int flags;
+
+ /* statistical data */
+ unsigned long e_created; /* extents created */
+ unsigned long e_freed; /* extents detroyed */
+ uint64 n_allocated; /* calls to alloc */
+ uint64 n_freed; /* calls to free */
+ uint64 b_allocated; /* cum. bytes allocated */
+ uint64 b_freed; /* cum. bytes freed */
+};
+
+struct pool_extent
+{
+ void *start; /* starting address */
+ size_t free; /* free bytecount */
+ size_t bound; /* bytes bound by padding,
+ * overhead and freed */
+ struct pool_extent *next;
+};
+
+#define MINALIGN (sizeof (void *))
+
+alloc_pool_t
+pool_create(size_t size, size_t quantum,
+ void (*bomb)(char *), int flags)
+{
+ struct alloc_pool *pool;
+
+ if (!(pool = (struct alloc_pool*) malloc(sizeof (struct alloc_pool))))
+ return pool;
+ memset(pool, 0, sizeof (struct alloc_pool));
+
+ pool->size = size /* round extent size to min alignment reqs */
+ ? (size + MINALIGN - 1) & ~(MINALIGN - 1)
+ : POOL_DEF_EXTENT;
+ pool->quantum = quantum ? quantum : MINALIGN;
+ pool->live = NULL;
+ pool->free = NULL;
+ pool->bomb = bomb;
+ pool->flags = flags;
+
+ return pool;
+}
+
+void
+pool_destroy(alloc_pool_t p)
+{
+ struct alloc_pool *pool = (struct alloc_pool *) p;
+ struct pool_extent *cur, *next;
+
+ if (!pool)
+ return;
+
+ if(pool->live)
+ {
+ cur = pool->live;
+ free(cur->start);
+ if (!(pool->flags & (POOL_INTERN | POOL_APPEND)))
+ free(cur);
+ }
+ cur = pool->free;
+ while(cur)
+ {
+ next = cur->next;
+ free(cur->start);
+ if (!(pool->flags & (POOL_INTERN | POOL_APPEND)))
+ free(cur);
+ cur = next;
+ }
+ free(pool);
+}
+
+void *pool_alloc(alloc_pool_t p, size_t len, char *bomb)
+{
+ struct alloc_pool *pool = (struct alloc_pool *) p;
+ if (!pool)
+ return NULL;
+
+ if(!len)
+ len = pool->quantum;
+ else if (pool->quantum > 1 && len % pool->quantum)
+ len += pool->quantum - len % pool->quantum;
+
+ if (len > pool->size)
+ goto bomb;
+
+ if (!pool->live || len > pool->live->free)
+ {
+ void *start;
+ size_t free;
+ size_t bound;
+ size_t sqew;
+ size_t asize;
+
+ if (pool->live)
+ {
+ pool->live->next = pool->free;
+ pool->free = pool->live;
+ }
+
+ free = pool->size;
+ bound = 0;
+
+ asize = pool->size;
+ if (pool->flags & POOL_APPEND)
+ asize += sizeof (struct pool_extent);
+
+ if(!(start = (void *) malloc(asize)))
+ goto bomb;
+
+ if (pool->flags & POOL_CLEAR)
+ memset(start, 0, asize);
+
+ if (pool->flags & POOL_INTERN)
+ {
+ bound = sizeof (struct pool_extent);
+ free -= sizeof (struct pool_extent);
+ pool->live = start + free;
+ }
+ else if (pool->flags & POOL_APPEND)
+ {
+ pool->live = start + free;
+ }
+ else if(!(pool->live = (struct pool_extent *) malloc(sizeof (struct pool_extent))))
+ {
+ goto bomb;
+ }
+ if(pool->flags & POOL_QALIGN && pool->quantum > 1
+ && (sqew = (size_t)(start + free) % pool->quantum))
+ {
+ bound += sqew;
+ free -= sqew;
+ }
+ pool->live->start = start;
+ pool->live->free = free;
+ pool->live->bound = bound;
+ pool->live->next = NULL;
+
+ pool->e_created++;
+ }
+
+ pool->n_allocated++;
+ pool->b_allocated += len;
+
+ pool->live->free -= len;
+
+ return pool->live->start + pool->live->free;
+
+bomb:
+ if (pool->bomb)
+ (*pool->bomb)(bomb);
+ return NULL;
+}
+
+void
+pool_free(alloc_pool_t p, size_t len, void *addr)
+{
+ struct alloc_pool *pool = (struct alloc_pool *) p;
+ struct pool_extent *cur, *next;
+ struct pool_extent *prev = NULL;
+
+ if (!pool)
+ return;
+
+ if(!len)
+ len = pool->quantum;
+ else if (pool->quantum > 1 && len % pool->quantum)
+ len += pool->quantum - len % pool->quantum;
+
+ if (!addr && pool->live)
+ {
+ pool->live->next = pool->free;
+ pool->free = pool->live;
+ pool->live = NULL;
+ return;
+ }
+ pool->n_freed++;
+ pool->b_freed += len;
+
+ cur = pool->live;
+ if (cur
+ && addr >= cur->start
+ && addr < cur->start + pool->size)
+ {
+ if (addr == cur->start + cur->free)
+ {
+ if (pool->flags & POOL_CLEAR)
+ memset(addr, 0, len);
+ pool->b_freed += len;
+ } else {
+ cur->bound += len;
+ }
+ if (cur->free + cur->bound >= pool->size)
+ {
+ size_t sqew;
+
+ cur->free = pool->size;
+ cur->bound = 0;
+ if (pool->flags & POOL_INTERN)
+ {
+ cur->bound = sizeof (struct pool_extent);
+ cur->free -= sizeof (struct pool_extent);
+ }
+ if(pool->flags & POOL_QALIGN && pool->quantum > 1
+ && (sqew = (size_t)(cur->start + cur->free) % pool->quantum))
+ {
+ cur->bound += sqew;
+ cur->free -= sqew;
+ }
+ }
+ return;
+ }
+ cur = pool->free;
+ while(cur)
+ {
+ next = cur->next;
+ if (addr >= cur->start
+ && addr < cur->start + pool->size)
+ break;
+ prev = cur;
+ cur = next;
+ }
+ if (!cur)
+ return;
+
+ if (cur != pool->free)
+ {
+ prev->next = cur->next;
+ cur->next = pool->free;
+ pool->free = cur;
+ }
+ cur->bound += len;
+
+ if (cur->free + cur->bound >= pool->size)
+ {
+ pool->free = cur->next;
+
+ free(cur->start);
+ if (!(pool->flags & (POOL_INTERN | POOL_APPEND)))
+ free(cur);
+ pool->e_freed++;
+ }
+ return;
+}
+
+#define FDPRINT(label, value) \
+ snprintf(buf, BUFSIZ, label, value); \
+ write(fd, buf, strlen(buf));
+
+#define FDEXTSTAT(ext) \
+ snprintf(buf, BUFSIZ, " %12ld %5ld\n", \
+ (long) ext->free, \
+ (long) ext->bound); \
+ write(fd, buf, strlen(buf));
+
+void
+pool_stats(alloc_pool_t p, int fd, int summarize)
+{
+ struct alloc_pool *pool = (struct alloc_pool *) p;
+ struct pool_extent *cur;
+ char buf[BUFSIZ];
+
+ if (!pool)
+ return;
+
+ FDPRINT(" Extent size: %12ld\n", (long) pool->size)
+ FDPRINT(" Alloc quantum: %12ld\n", (long) pool->quantum)
+ FDPRINT(" Extents created: %12ld\n", pool->e_created)
+ FDPRINT(" Extents freed: %12ld\n", pool->e_freed)
+ FDPRINT(" Alloc count: %12.0f\n", (double) pool->n_allocated)
+ FDPRINT(" Free Count: %12.0f\n", (double) pool->n_freed)
+ FDPRINT(" Alloc bytes: %12.0f\n", (double) pool->b_allocated)
+ FDPRINT(" Free bytes: %12.0f\n", (double) pool->b_freed)
+
+ if (summarize)
+ return;
+
+ if (!pool->live && !pool->free)
+ return;
+
+ write(fd, "\n", 1);
+
+ if (pool->live)
+ {
+ FDEXTSTAT(pool->live)
+ }
+ strcpy(buf, " FREE BOUND\n");
+ write(fd, buf, strlen(buf));
+
+ cur = pool->free;
+ while(cur)
+ {
+ FDEXTSTAT(cur)
+ cur = cur->next;
+ }
+}
+
diff -rupNP --exclude-from cvs/.ignore cvs/lib/pool_alloc.h pool2/lib/pool_alloc.h
--- cvs/lib/pool_alloc.h Wed Dec 31 16:00:00 1969
+++ pool2/lib/pool_alloc.h Tue Feb 3 16:30:24 2004
@@ -0,0 +1,20 @@
+#include <stddef.h>
+
+#define POOL_CLEAR (1<<0) /* zero fill allocations */
+#define POOL_QALIGN (1<<1) /* align data to quanta */
+#define POOL_INTERN (1<<2) /* Allocate extent structures */
+#define POOL_APPEND (1<<3) /* or appended to extent data */
+
+typedef void *alloc_pool_t;
+
+alloc_pool_t pool_create(size_t size, size_t quantum, void (*bomb)(char *), int flags);
+void pool_destroy(alloc_pool_t pool);
+void *pool_alloc(alloc_pool_t pool, size_t size, char *bomb);
+void pool_free(alloc_pool_t pool, size_t size, void *addr);
+
+#define pool_talloc(pool, type, count, bomb) \
+ ((type *)pool_alloc(pool, sizeof(type) * count, bomb))
+
+#define pool_tfree(pool, type, count, addr) \
+ (pool_free(pool, sizeof(type) * count, addr))
+
diff -rupNP --exclude-from cvs/.ignore cvs/proto.h pool2/proto.h
--- cvs/proto.h Fri Feb 6 01:55:48 2004
+++ pool2/proto.h Fri Feb 6 02:01:00 2004
@@ -74,16 +74,18 @@ int readlink_stat(const char *path, STRU
int link_stat(const char *path, STRUCT_STAT * buffer);
void flist_expand(struct file_list *flist);
void send_file_entry(struct file_struct *file, int f, unsigned short base_flags);
-void receive_file_entry(struct file_struct **fptr, unsigned short flags, int f);
-struct file_struct *make_file(char *fname, int exclude_level);
+void receive_file_entry(struct file_struct **fptr, unsigned short flags,
+ struct file_list *flist, int f);
+struct file_struct *make_file(char *fname,
+ struct file_list *flist, int exclude_level);
void send_file_name(int f, struct file_list *flist, char *fname,
int recursive, unsigned short base_flags);
struct file_list *send_file_list(int f, int argc, char *argv[]);
struct file_list *recv_file_list(int f);
int file_compare(struct file_struct **file1, struct file_struct **file2);
int flist_find(struct file_list *flist, struct file_struct *f);
-void free_file(struct file_struct *file, int free_the_struct);
-struct file_list *flist_new(void);
+void clear_file(int i, struct file_list *flist);
+struct file_list *flist_new(int with_hlink, char *msg);
void flist_free(struct file_list *flist);
int f_name_cmp(struct file_struct *f1, struct file_struct *f2);
char *f_name_to(struct file_struct *f, char *fbuf);
diff -rupNP --exclude-from cvs/.ignore cvs/receiver.c pool2/receiver.c
--- cvs/receiver.c Wed Feb 4 03:49:36 2004
+++ pool2/receiver.c Wed Feb 4 03:08:45 2004
@@ -305,6 +305,12 @@ int recv_files(int f_in,struct file_list
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
}
+ if (flist->hlink_pool)
+ {
+ pool_destroy(flist->hlink_pool);
+ flist->hlink_pool = NULL;
+ }
+
while (1) {
cleanup_disable();
diff -rupNP --exclude-from cvs/.ignore cvs/rsync.h pool2/rsync.h
--- cvs/rsync.h Fri Feb 6 01:13:58 2004
+++ pool2/rsync.h Fri Feb 6 02:02:23 2004
@@ -112,8 +112,12 @@
#define FULL_FLUSH 1
#define NORMAL_FLUSH 0
-#define CLEAR_STRUCT 0
-#define FREE_STRUCT 1
+#if HAVE_LINK
+#define WITH_HLINK 1
+#else
+#define WITH_HLINK 0
+#endif
+#define WITHOUT_HLINK 0
/* Log-message categories. FLOG is only used on the daemon side to
* output messages to the log file. */
@@ -254,6 +258,7 @@ enum msgcode {
#include <assert.h>
+#include "lib/pool_alloc.h"
#define BOOL int
@@ -434,19 +439,25 @@ struct file_struct {
*/
#define FLIST_START (32 * 1024)
#define FLIST_LINEAR (FLIST_START * 512)
+/*
+ * Extent size for allocation pools A minimum size of 128KB
+ * is needed to mmap them so that freeing will release the
+ * space to the OS.
+ *
+ * Larger sizes reduce leftover fragments and speed free calls
+ * (when they happen) Smaller sizes increase the chance of
+ * freed allocations freeing whole extents.
+ */
-struct string_area {
- char *base;
- char *end;
- char *current;
- struct string_area *next;
-};
+#define FILE_EXTENT (256 * 1024)
+#define HLINK_EXTENT (128 * 1024)
struct file_list {
int count;
int malloced;
+ alloc_pool_t file_pool;
+ alloc_pool_t hlink_pool;
struct file_struct **files;
- struct string_area *string_area;
};
struct sum_buf {
Binary files cvs/t_unsafe and pool2/t_unsafe differ
Binary files cvs/tls and pool2/tls differ
Binary files cvs/trimslash and pool2/trimslash differ
Binary files cvs/wildtest and pool2/wildtest differ
More information about the rsync
mailing list