Changeset 026eb88


Ignore:
Timestamp:
03/19/10 14:33:17 (11 years ago)
Author:
Perry Lorier <perry@…>
Branches:
4.0.1-hotfixes, cachetimestamps, develop, dpdk-ndag, etsilive, getfragoff, help, libtrace4, master, ndag_format, pfring, rc-4.0.1, rc-4.0.2, rc-4.0.3, rc-4.0.4, ringdecrementfix, ringperformance, ringtimestampfixes
Children:
2b4316b
Parents:
d99c759
Message:

Make sure we write in multiples of 4k to keep O_DIRECT happy

File:
1 edited

Legend:

Unmodified
Added
Removed
  • lib/iow-stdio.c

    r29d4438 r026eb88  
    3737#include <sys/types.h>
    3838#include <sys/stat.h>
     39#include <sys/uio.h>
    3940#include <fcntl.h>
    4041#include <stdlib.h>
    4142#include <unistd.h>
    4243#include <string.h>
     44#include <assert.h>
    4345
    4446/* Libtrace IO module implementing a standard IO writer, i.e. no decompression
    4547 */
    4648
     49enum { MIN_WRITE_SIZE = 4096 };
     50
    4751struct stdiow_t {
     52        char buffer[MIN_WRITE_SIZE];
     53        int offset;
    4854        int fd;
    4955};
     
    5258
    5359#define DATA(iow) ((struct stdiow_t *)((iow)->data))
     60
     61static int safe_open(const char *filename)
     62{
     63        int fd;
     64/* Try opening with O_DIRECT */
     65#ifdef O_DIRECT
     66        fd = open(filename,
     67                O_WRONLY
     68                |O_CREAT
     69                |O_TRUNC
     70                |(force_directio_write?O_DIRECT:0),
     71                0666);
     72        if (fd != -1)
     73                return fd;
     74#endif
     75/* If that failed (or we don't support O_DIRECT) try opening without */
     76        fd = open(filename,
     77                O_WRONLY
     78                |O_CREAT
     79                |O_TRUNC,
     80                0666);
     81        if (fd != -1)
     82                return fd;
     83        return fd;
     84}
    5485
    5586iow_t *stdio_wopen(const char *filename)
     
    6192        if (strcmp(filename,"-") == 0)
    6293                DATA(iow)->fd = 1; /* STDOUT */
    63         else
    64                 DATA(iow)->fd = open(filename,
    65                                 O_WRONLY
    66                                 |O_CREAT
    67                                 |O_TRUNC
    68                                 |(force_directio_write?O_DIRECT:0),
    69                                 0666);
     94        else {
     95                DATA(iow)->fd = safe_open(filename);
     96        }
    7097
    7198        if (DATA(iow)->fd == -1) {
     
    74101        }
    75102
     103        DATA(iow)->offset = 0;
     104
    76105        return iow;
    77106}
    78107
     108#define min(a,b) ((a)<(b) ? (a) : (b))
     109#define max(a,b) ((a)>(b) ? (a) : (b))
     110/* Round A Down to the nearest multiple of B */
     111#define rounddown(a,b) ((a)-((a)%b)
     112
     113/* When doing directio (O_DIRECT) we need to make sure that we write multiples of MIN_WRITE_SIZE.
     114 * So we accumulate data into DATA(iow)->buffer, and write it out when we get at least MIN_WRITE_SIZE.
     115 *
     116 * Since most writes are likely to be larger than MIN_WRITE_SIZE optimise for that case.
     117 */
    79118static off_t stdio_wwrite(iow_t *iow, const char *buffer, off_t len)
    80119{
    81         return write(DATA(iow)->fd,buffer,len);
     120        struct iovec iov[2];
     121        int err;
     122        /* Round down size to the nearest multiple of MIN_WRITE_SIZE */
     123
     124        assert(len >= 0);
     125       
     126        if (DATA(iow)->offset + len >= MIN_WRITE_SIZE) {
     127                int amount;
     128                iov[0].iov_base = DATA(iow)->buffer;
     129                iov[0].iov_len = DATA(iow)->offset;
     130                iov[1].iov_base = (void*)buffer; /* cast away constness, which is safe here */
     131                iov[1].iov_len = len - (DATA(iow)->offset+len) % MIN_WRITE_SIZE;
     132                err=writev(DATA(iow)->fd, iov, 2);
     133                if (err==-1)
     134                        return -1;
     135                /* Drop off "err" bytes from the beginning of the buffers */
     136                amount = min(DATA(iow)->offset, err);
     137                DATA(iow)->offset -= amount;
     138                err -= amount;
     139                buffer += err;
     140                len -= err;
     141        }
     142
     143        /* Make sure we're not going to overflow the buffer.  The above writev should assure
     144         * that this is true
     145         */
     146        assert(DATA(iow)->offset + len <= MIN_WRITE_SIZE);
     147        assert(len >= 0);
     148
     149        /* Copy the remainder into the buffer to write next time. */
     150        memcpy(DATA(iow)->buffer + DATA(iow)->offset, buffer, len);
     151        DATA(iow)->offset += len;
     152
     153        return len;
    82154}
    83155
    84156static void stdio_wclose(iow_t *iow)
    85157{
     158        long err;
     159        /* Now, there might be some non multiple of the direct filesize left over, if so turn off
     160         * O_DIRECT and write the final chunk.
     161         */
     162#ifdef O_DIRECT
     163        err=fcntl(DATA(iow)->fd, F_GETFL);
     164        if (err != -1 && (err & O_DIRECT) != 0) {
     165                fcntl(DATA(iow)->fd,F_SETFL, err & ~O_DIRECT);
     166        }
     167        write(DATA(iow)->fd, DATA(iow)->buffer, DATA(iow)->offset);
     168        DATA(iow)->offset = 0;
     169#endif
    86170        close(DATA(iow)->fd);
    87171        free(iow->data);
Note: See TracChangeset for help on using the changeset viewer.