Permalink
Browse files

Avoid excessive network requests in npc_gets

Previous implementation of npc_gets was throwning away and re-reading
any characters after a \n.  Fix this so excess data is buffered in
the fid (as with readdir).

There was really no need for npc_closedir ().  Drop it and move buffer
cleanup to npc_clunk ().

This speeds up diodshowmount on test system with 1032 entries
in /proc/connections from 0.146s to 0.026s (real).
  • Loading branch information...
garlick committed May 22, 2012
1 parent ce612d1 commit c289f62c91cb067d8784dcdcb62704e98128d9fd
Showing with 104 additions and 63 deletions.
  1. +3 −1 libnpclient/fid.c
  2. +4 −10 libnpclient/npclient.h
  3. +73 −20 libnpclient/read.c
  4. +18 −26 libnpclient/readdir.c
  5. +2 −2 tests/misc/tnpsrv2.c
  6. +3 −3 utils/diodls.c
  7. +1 −1 utils/diodshowmount.c
View
@@ -54,7 +54,7 @@ npc_fid_alloc(Npcfsys *fs)
ret->fid = npc_get_id(fs->fidpool);
ret->offset = 0;
ret->iounit = 0;
- ret->dbuf = NULL;
+ ret->buf = NULL;
fs->incref(fs);
return ret;
@@ -64,6 +64,8 @@ void
npc_fid_free(Npcfid *fid)
{
if (fid) {
+ if (fid->buf)
+ free (fid->buf);
npc_put_id(fid->fsys->fidpool, fid->fid);
fid->fsys->decref(fid->fsys);
free(fid);
View
@@ -32,10 +32,10 @@ struct Npcfid {
Npcfsys* fsys;
u32 fid;
u64 offset;
- char *dbuf; /* packed p9_dirents */
- int dbuf_size; /* size of 'dbuf' buffer */
- int dbuf_len; /* length of 'dbuf' filled */
- int dbuf_used; /* amount of 'dbuf' used */
+ char *buf; /* packed p9_dirents or gets buffer */
+ int buf_size; /* size of 'buf' buffer */
+ int buf_len; /* length of 'buf' filled (readdir_r) */
+ int buf_used; /* amount of 'buf' used (readdir_r)*/
};
typedef int (*AuthFun)(Npcfid *afid, u32 uid);
@@ -260,12 +260,6 @@ int npc_remove_bypath (Npcfid *root, char *path);
*/
Npcfid *npc_opendir (Npcfid *root, char *path);
-/* Tell the server to forget about 'fid' with a CLUNK request,
- * and free internal data structures associated with readdir.
- * Return 0 on success, -1 on error (retrieve with np_rerror ()).
- */
-int npc_closedir (Npcfid *fid);
-
/* Read a directory entry from directory 'fid' that was opened with
* npc_opendir(). Entry points to dirent storage allocated by the caller.
* Like readdir_r, returns 0 on success (>0) errno on failure.
View
@@ -149,31 +149,84 @@ npc_aget(Npcfid *root, char *path)
return NULL;
}
+static int
+_buf_save (Npcfid *fid, char *buf, int len)
+{
+ if (fid->buf) {
+ if (!(fid->buf = realloc (fid->buf, fid->buf_size + len)))
+ goto nomem;
+ memcpy (fid->buf + fid->buf_size, buf, len);
+ fid->buf_size += len;
+ } else {
+ if (!(fid->buf = malloc (len)))
+ goto nomem;
+ memcpy (fid->buf, buf, len);
+ fid->buf_size = len;
+ }
+ return 0;
+nomem:
+ np_uerror (ENOMEM);
+ return -1;
+}
+
+static int
+_buf_restore (Npcfid *fid, char *buf, int len)
+{
+ int ret = 0;
+
+ if (fid->buf) {
+ ret = len > fid->buf_size ? fid->buf_size : len;
+ memcpy (buf, fid->buf, ret);
+ if (fid->buf_size > ret) {
+ memmove (fid->buf, fid->buf + ret, fid->buf_size - ret);
+ fid->buf_size -= ret;
+ } else {
+ free (fid->buf);
+ fid->buf = NULL;
+ fid->buf_size = 0;
+ }
+ }
+ return ret;
+}
+
+static char *
+_strnchr (char *s, char c, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if (s[i] == c)
+ return &s[i];
+ return NULL;
+}
-/* FIXME: embed a buffer in Npcfid like stdio.
- * Rewinding the file after each read is inefficient.
- */
char *
npc_gets(Npcfid *fid, char *buf, u32 count)
{
- int n, done = 0;
- char *p;
+ int n = 0, done = 0, extra = 0;
+ char *nlp = NULL;
- while (done < count) {
- n = npc_pread (fid, buf + done,
- count - done - 1, fid->offset + done);
- if (n < 0)
- return NULL;
- if (n == 0)
- break;
- done += n;
- buf[done] = '\0';
- if ((p = strchr (buf, '\n'))) {
- *p = '\0';
- done = strlen (buf) + 1;
- break;
+ n = _buf_restore (fid, buf, count - 1);
+ while (done < count && !nlp) {
+ if (done > 0 || n == 0) {
+ n = npc_read (fid, buf + done, count - done - 1);
+ if (n < 0)
+ goto error;
+ if (n == 0)
+ break;
}
+ nlp = _strnchr (buf + done, '\n', n);
+ done += n;
+ }
+ if (nlp) {
+ *nlp = '\0';
+ extra = done - (nlp - buf) - 1;
+ if (extra > 0 && _buf_save (fid, nlp + 1, extra) < 0)
+ goto error;
+ done = nlp - buf;
}
- fid->offset += done;
- return (done > 0 ? buf : NULL);
+ buf[done] = '\0';
+ return done > 0 ? buf : NULL;
+error:
+ return NULL;
}
View
@@ -69,17 +69,6 @@ npc_readdir (Npcfid *fid, u64 offset, char *data, u32 count)
return ret;
}
-int
-npc_closedir (Npcfid *fid)
-{
- if (fid->dbuf) {
- free (fid->dbuf);
- fid->dbuf = NULL;
- }
-
- return npc_clunk (fid);
-}
-
Npcfid *
npc_opendir (Npcfid *root, char *path)
{
@@ -93,15 +82,15 @@ npc_opendir (Npcfid *root, char *path)
np_uerror (ENOTDIR);
goto error;
}
- fid->dbuf_size = root->fsys->msize - P9_IOHDRSZ;
- if (!(fid->dbuf = malloc (fid->dbuf_size))) {
- (void)npc_closedir (fid);
+ fid->buf_size = root->fsys->msize - P9_IOHDRSZ;
+ if (!(fid->buf = malloc (fid->buf_size))) {
+ (void)npc_clunk (fid);
np_uerror (ENOMEM);
fid = NULL;
}
fid->offset = 0;
- fid->dbuf_len = 0;
- fid->dbuf_used = 0;
+ fid->buf_len = 0;
+ fid->buf_used = 0;
}
return fid;
error:
@@ -122,29 +111,32 @@ npc_readdir_r (Npcfid *fid, struct dirent *entry, struct dirent **result)
u8 type;
int res;
- if (fid->dbuf_used >= fid->dbuf_len) {
- fid->dbuf_len = npc_readdir (fid, fid->offset, fid->dbuf,
- fid->dbuf_size);
- if (fid->dbuf_len < 0)
+ if (!fid->buf) /* not opened with npc_opendir */
+ return EINVAL;
+
+ if (fid->buf_used >= fid->buf_len) {
+ fid->buf_len = npc_readdir (fid, fid->offset, fid->buf,
+ fid->buf_size);
+ if (fid->buf_len < 0)
return np_rerror ();
- if (fid->dbuf_len == 0) { /* EOF */
+ if (fid->buf_len == 0) { /* EOF */
*result = NULL;
return 0;
}
- fid->dbuf_used = 0;
+ fid->buf_used = 0;
}
res = np_deserialize_p9dirent (&qid, &offset, &type,
entry->d_name, dname_size,
- (u8 *)fid->dbuf + fid->dbuf_used,
- fid->dbuf_len - fid->dbuf_used);
+ (u8 *)fid->buf + fid->buf_used,
+ fid->buf_len - fid->buf_used);
if (res == 0)
return EIO;
entry->d_off = offset;
entry->d_type = type;
entry->d_ino = qid.path;
//entry->d_reclen
fid->offset = offset;
- fid->dbuf_used += res;
+ fid->buf_used += res;
*result = entry;
return 0;
}
@@ -153,7 +145,7 @@ void
npc_seekdir (Npcfid *fid, long offset)
{
fid->offset = offset;
- fid->dbuf_used = fid->dbuf_len; /* force a 9p readdir call */
+ fid->buf_used = fid->buf_len; /* force a 9p readdir call */
}
long
View
@@ -173,8 +173,8 @@ main (int argc, char *argv[])
msg ("readdir found fewer than expected files: %d", i);
/* close the directory */
- if (npc_closedir (dir) < 0)
- errn (np_rerror (), "npc_closedir foo");
+ if (npc_clunk (dir) < 0)
+ errn (np_rerror (), "npc_clunk foo");
}
/* remove files (implicit clunk) */
View
@@ -255,16 +255,16 @@ lsdir (int i, int count, Npcfid *root, int lopt, char *path)
printf ("%s\n", dp->d_name);
}
} while (dp != NULL);
- if (npc_closedir (dir) < 0) {
- errn (np_rerror (), "npc_closedir: %s", path);
+ if (npc_clunk (dir) < 0) {
+ errn (np_rerror (), "npc_clunk: %s", path);
goto error;
}
if (count > 1 && i < count - 1)
printf ("\n");
return 0;
error:
if (dir)
- (void)npc_closedir (dir);
+ (void)npc_clunk (dir);
return -1;
}
View
@@ -146,7 +146,7 @@ main (int argc, char *argv[])
if (!(hl = hostlist_create (NULL)))
err_exit ("hostlist_create");
- while (npc_gets (fid, buf, sizeof(buf))) { // inefficient (fix libnpclient)
+ while (npc_gets (fid, buf, sizeof(buf))) {
if ((p = strchr (buf, ' ')))
*p = '\0';
if (!lopt && (p = strchr (buf, '.')))

0 comments on commit c289f62

Please sign in to comment.