summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changes2
-rw-r--r--eio.c93
-rw-r--r--eio.h2
3 files changed, 82 insertions, 15 deletions
diff --git a/Changes b/Changes
index 37aedc9..88919c3 100644
--- a/Changes
+++ b/Changes
@@ -8,6 +8,8 @@ TODO: maybe add mincore support? available on at leats darwin, solaris, linux, f
and possibly filetype, can sort in various ways.
- readdir: stop immediately when cancelled, do
not continue reading the directory.
+ - fix return value of eio_sendfile_sync.
+ - include sys/mman.h for msync.
- added EIO_STACKSIZE.
- added msync, mtouch support (untested).
- added sync_file_range (untested).
diff --git a/eio.c b/eio.c
index cef46a3..9a41023 100644
--- a/eio.c
+++ b/eio.c
@@ -75,6 +75,7 @@
# include "config.h"
# include <sys/time.h>
# include <sys/select.h>
+# include <sys/mman.h>
# include <unistd.h>
# include <utime.h>
# include <signal.h>
@@ -991,14 +992,78 @@ eio__sendfile (int ofd, int ifd, off_t offset, size_t count, etp_worker *self)
return res;
}
-static int
-eio_dent_cmp (const void *a_, const void *b_)
+static signed char
+eio_dent_cmp (const eio_dirent *a, const eio_dirent *b)
{
- const eio_dirent *a = (const eio_dirent *)a_;
- const eio_dirent *b = (const eio_dirent *)b_;
+ return b->score - a->score ? b->score - a->score /* works because our signed char is always 0..100 */
+ : a->inode < b->inode ? -1 : a->inode > b->inode ? 1 : 0;
+}
+
+#define EIO_QSORT_CUTOFF 20 /* quite high, but performs well on many filesystems */
+
+static void
+eio_dent_sort (eio_dirent *dents, int size)
+{
+ /* should be good for 2**31 entries */
+ struct rng { int l, r; } rng [32];
+ int i, j;
+
+ i = 0;
+ rng[0].l = 0;
+ rng[0].r = size;
+
+ while (expect_true (i >= 0))
+ {
+ int L = rng [i].l;
+ int R = rng [i].r - 1;
+
+ if (expect_false (L + EIO_QSORT_CUTOFF < R))
+ {
+ eio_dirent piv = dents [L];
+
+ while (L < R)
+ {
+ while (eio_dent_cmp (&dents [R], &piv) >= 0 && L < R)
+ --R;
+
+ if (L < R)
+ dents [L++] = dents [R];
+
+ while (eio_dent_cmp (&dents [L], &piv) <= 0 && L < R)
+ ++L;
+
+ if (L < R)
+ dents [R--] = dents [L];
+ }
- return (int)b->score - (int)a->score ? (int)b->score - (int)a->score
- : a->inode < b->inode ? -1 : a->inode > b->inode ? 1 : 0; /* int might be < ino_t */
+ dents [L] = piv;
+
+ ++i;
+ rng [i].l = L + 1;
+ rng [i].r = rng [i - 1].r;
+ rng [i - 1].r = L;
+
+ if (rng [i].r - rng [i].l > rng [i - 1].r - rng [i - 1].l)
+ {
+ struct rng t;
+
+ t = rng [i]; rng [i] = rng [i - 1]; rng [i - 1] = t;
+ }
+ }
+ else
+ --i;
+ }
+
+ /* use a simple insertion sort at the end */
+ for (i = 1; i < size; ++i)
+ {
+ eio_dirent value = dents [i];
+
+ for (j = i - 1; j >= 0 && eio_dent_cmp (&dents [j], &value) > 0; --j)
+ dents [j + 1] = dents [j];
+
+ dents [j + 1] = value;
+ }
}
/* read a full directory */
@@ -1007,7 +1072,7 @@ eio__scandir (eio_req *req, etp_worker *self)
{
DIR *dirp;
EIO_STRUCT_DIRENT *entp;
- unsigned char *name, *names;
+ char *name, *names;
int namesalloc = 4096;
int namesoffs = 0;
int flags = req->int1;
@@ -1053,10 +1118,7 @@ eio__scandir (eio_req *req, etp_worker *self)
if (flags & EIO_READDIR_STAT_ORDER
|| !(~flags & (EIO_READDIR_DIRS_FIRST | EIO_READDIR_FOUND_UNKNOWN)))
- {
- /* pray your qsort doesn't use quicksort */
- qsort (dents, dentoffs, sizeof (*dents), eio_dent_cmp); /* score depends of DIRS_FIRST */
- }
+ eio_dent_sort (dents, dentoffs); /* score depends of DIRS_FIRST */
else if (flags & EIO_READDIR_DIRS_FIRST)
{
/* in this case, all is known, and we just put dirs first and sort them */
@@ -1064,7 +1126,7 @@ eio__scandir (eio_req *req, etp_worker *self)
eio_dirent *dir = dents;
/* now move dirs to the front, and non-dirs to the back */
- /* by walkign from both sides and swapping if necessary */
+ /* by walking from both sides and swapping if necessary */
while (ent > dir)
{
if (dir->type == DT_DIR)
@@ -1085,7 +1147,7 @@ eio__scandir (eio_req *req, etp_worker *self)
}
/* now sort the dirs only */
- qsort (dents, dir - dents, sizeof (*dents), eio_dent_cmp);
+ eio_dent_sort (dents, dir - dents);
}
/* only provide the names array unless DENTS is specified */
@@ -1750,12 +1812,15 @@ void eio_grp_add (eio_req *grp, eio_req *req)
ssize_t eio_sendfile_sync (int ofd, int ifd, off_t offset, size_t count)
{
etp_worker wrk;
+ ssize_t ret;
wrk.dbuf = 0;
- eio__sendfile (ofd, ifd, offset, count, &wrk);
+ ret = eio__sendfile (ofd, ifd, offset, count, &wrk);
if (wrk.dbuf)
free (wrk.dbuf);
+
+ return ret;
}
diff --git a/eio.h b/eio.h
index 0b8625f..126b091 100644
--- a/eio.h
+++ b/eio.h
@@ -99,7 +99,7 @@ struct eio_dirent {
ino_t inode;
unsigned short namelen;
unsigned char type;
- unsigned char score; /* internal use */
+ signed char score; /* internal use */
/* 0-4 bytes padding */
};