about summary refs log tree commit homepage
path: root/trywrite.c
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2013-01-17 01:11:04 +0000
committerEric Wong <normalperson@yhbt.net>2013-01-17 01:28:59 +0000
commit14e0684507c06439ee9c7a731fd6ca90b7b9adcb (patch)
treeca804fbdee3981c192a527c2102b203ddc82cd94 /trywrite.c
parent37026af96dec638aa850d604003bf7218d90037d (diff)
downloadcmogstored-14e0684507c06439ee9c7a731fd6ca90b7b9adcb.tar.gz
This saves several setsockopt() syscalls and reduces system
CPU usage.
Diffstat (limited to 'trywrite.c')
-rw-r--r--trywrite.c54
1 files changed, 52 insertions, 2 deletions
diff --git a/trywrite.c b/trywrite.c
index ab89296..c53d538 100644
--- a/trywrite.c
+++ b/trywrite.c
@@ -10,7 +10,7 @@ struct mog_wbuf {
         unsigned char buf[FLEXIBLE_ARRAY_MEMBER];
 };
 
-static void * wbuf_new(size_t total, struct iovec *iov, int iovcnt)
+static void * wbuf_newv(size_t total, struct iovec *iov, int iovcnt)
 {
         struct mog_wbuf *wbuf = xmalloc(sizeof(struct mog_wbuf) + total);
         void *dst = wbuf->buf;
@@ -25,6 +25,16 @@ static void * wbuf_new(size_t total, struct iovec *iov, int iovcnt)
         return wbuf;
 }
 
+static void * wbuf_new(void *buf, size_t len)
+{
+        struct iovec iov;
+
+        iov.iov_base = buf;
+        iov.iov_len = len;
+
+        return wbuf_newv(len, &iov, 1);
+}
+
 enum mog_write_state mog_tryflush(int fd, struct mog_wbuf **x)
 {
         struct mog_wbuf *wbuf = *x;
@@ -82,7 +92,7 @@ retry:
                 return NULL;
         } else if (w < 0) {
                 switch (errno) {
-                case_EAGAIN: return wbuf_new(total, iov, iovcnt);
+                case_EAGAIN: return wbuf_newv(total, iov, iovcnt);
                 case EINTR: goto retry;
                 }
                 return MOG_WR_ERROR;
@@ -117,3 +127,43 @@ retry:
                 goto retry;
         }
 }
+
+/*
+ * returns
+ * - NULL on full write
+ * - MOG_WR_ERROR on error (and sets errno)
+ * - address to a new mog_wbuf with unbuffered contents on partial write
+ */
+void * mog_trysend(int fd, void *buf, size_t len, off_t more)
+{
+        if (MOG_MSG_MORE) {
+                int flags = more > 0 ? MSG_MORE : 0;
+
+                while (len > 0) {
+                        ssize_t w = send(fd, buf, len, flags);
+
+                        if (w == (ssize_t)len)
+                                return NULL; /* all done */
+
+                        if (w < 0) {
+                                switch (errno) {
+                                case_EAGAIN: return wbuf_new(buf, len);
+                                case EINTR: continue;
+                                }
+                                return MOG_WR_ERROR;
+                        } else {
+                                buf = (char *)buf + w;
+                                len -= w;
+                        }
+                }
+
+                return NULL;
+        } else {
+                struct iovec iov;
+
+                iov.iov_base = buf;
+                iov.iov_len = len;
+
+                return mog_trywritev(fd, &iov, 1);
+        }
+}