sdisk_unix.cpp

00001 /* -*- mode:C++; c-basic-offset:4 -*-
00002      Shore-MT -- Multi-threaded port of the SHORE storage manager
00003    
00004                        Copyright (c) 2007-2009
00005       Data Intensive Applications and Systems Labaratory (DIAS)
00006                Ecole Polytechnique Federale de Lausanne
00007    
00008                          All Rights Reserved.
00009    
00010    Permission to use, copy, modify and distribute this software and
00011    its documentation is hereby granted, provided that both the
00012    copyright notice and this permission notice appear in all copies of
00013    the software, derivative works or modified versions, and any
00014    portions thereof, and that both notices appear in supporting
00015    documentation.
00016    
00017    This code is distributed in the hope that it will be useful, but
00018    WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS
00020    DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
00021    RESULTING FROM THE USE OF THIS SOFTWARE.
00022 */
00023 
00024 /*<std-header orig-src='shore'>
00025 
00026  $Id: sdisk_unix.cpp,v 1.23 2010/05/26 01:21:29 nhall Exp $
00027 
00028 SHORE -- Scalable Heterogeneous Object REpository
00029 
00030 Copyright (c) 1994-99 Computer Sciences Department, University of
00031                       Wisconsin -- Madison
00032 All Rights Reserved.
00033 
00034 Permission to use, copy, modify and distribute this software and its
00035 documentation is hereby granted, provided that both the copyright
00036 notice and this permission notice appear in all copies of the
00037 software, derivative works or modified versions, and any portions
00038 thereof, and that both notices appear in supporting documentation.
00039 
00040 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
00041 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
00042 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
00043 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
00044 
00045 This software was developed with support by the Advanced Research
00046 Project Agency, ARPA order number 018 (formerly 8230), monitored by
00047 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
00048 Further funding for this work was provided by DARPA through
00049 Rome Research Laboratory Contract No. F30602-97-2-0247.
00050 
00051 */
00052 
00053 #include "w_defines.h"
00054 
00055 /*  -- do not edit anything above this line --   </std-header>*/
00056 
00057 /**\cond skip */
00058 /*
00059  *   NewThreads I/O is Copyright 1995, 1996, 1997, 1998 by:
00060  *
00061  *    Josef Burger    <bolo@cs.wisc.edu>
00062  *
00063  *   All Rights Reserved.
00064  *
00065  *   NewThreads I/O may be freely used as long as credit is given
00066  *   to the above author(s) and the above copyright is maintained.
00067  */
00068 
00069 #if defined(linux) && !defined(_GNU_SOURCE)
00070 /*
00071  *  XXX this done to make O_DIRECT available as an I/O choice.
00072  *  Unfortunately, it needs to pollute the other headers, otw
00073  *  the features will be set and access won't be possible
00074  */
00075 #define _GNU_SOURCE
00076 #endif
00077 
00078 #include <w.h>
00079 #include <sthread.h>
00080 #include <sdisk.h>
00081 #include <sdisk_unix.h>
00082 
00083 #ifdef EXPENSIVE_STATS
00084 #include <stime.h>
00085 #endif
00086 
00087 #include <sthread_stats.h>
00088 extern class sthread_stats SthreadStats;
00089 
00090 #include "os_fcntl.h"
00091 #include <cerrno>
00092 #include <sys/stat.h>
00093 
00094 #include <sys/uio.h>
00095 
00096 #define    HAVE_IO_VECTOR
00097 
00098 // TODO deal with these HAVE_IO* 
00099 // TODO : is vector i/o ok with pthreads?
00100 
00101 #include <os_interface.h>
00102 
00103 
00104 const int stBADFD = sthread_base_t::stBADFD;
00105 const int stINVAL = sthread_base_t::stINVAL;
00106 
00107 
00108 int    sdisk_unix_t::convert_flags(int sflags)
00109 {
00110     int    flags = 0;
00111 
00112     /* 1 of n */
00113     switch (modeBits(sflags)) {
00114     case OPEN_RDWR:
00115         flags |= O_RDWR;
00116         break;
00117     case OPEN_WRONLY:
00118         flags |= O_WRONLY;
00119         break;
00120     case OPEN_RDONLY:
00121         flags |= O_RDONLY;
00122         break;
00123     }
00124 
00125     /* m of n */
00126     /* could make a data driven flag conversion, :-) */
00127     if (hasOption(sflags, OPEN_CREATE))
00128         flags |= O_CREAT;
00129     if (hasOption(sflags, OPEN_TRUNC))
00130         flags |= O_TRUNC;
00131     if (hasOption(sflags, OPEN_EXCL))
00132         flags |= O_EXCL;
00133 #ifdef O_SYNC
00134     if (hasOption(sflags, OPEN_SYNC))
00135         flags |= O_SYNC;
00136 #endif
00137     if (hasOption(sflags, OPEN_APPEND))
00138         flags |= O_APPEND;
00139 #ifdef O_DIRECT
00140     /*
00141      * From the open man page:
00142      *      O_DIRECT
00143               Try to minimize cache effects of the I/O to and from this  file.
00144               In  general  this  will degrade performance, but it is useful in
00145               special situations, such  as  when  applications  do  their  own
00146               caching.   File I/O is done directly to/from user space buffers.
00147               The I/O is synchronous, i.e., at the completion of a read(2)  or
00148               write(2),  data  is  guaranteed to have been transferred.  Under
00149               Linux 2.4 transfer sizes, and the alignment of user  buffer  and
00150               file  offset  must all be multiples of the logical block size of
00151               the file system. Under Linux 2.6 alignment must  fit  the  block
00152               size of the device.
00153     */
00154     if (hasOption(sflags, OPEN_RAW))
00155         flags |= O_DIRECT;
00156 #endif
00157 
00158     return flags;
00159 }
00160 
00161 
00162 sdisk_unix_t::~sdisk_unix_t()
00163 {
00164     if (_fd != FD_NONE)
00165         W_COERCE(close());
00166 }
00167 
00168 
00169 w_rc_t    sdisk_unix_t::make(const char *name, int flags, int mode,
00170                sdisk_t *&disk)
00171 {
00172     sdisk_unix_t    *ud;
00173     w_rc_t        e;
00174 
00175     disk = 0;    /* default value*/
00176     
00177     ud = new sdisk_unix_t(name);
00178     if (!ud)
00179         return RC(fcOUTOFMEMORY);
00180 
00181     e = ud->open(name, flags, mode);
00182     if (e.is_error()) {
00183         delete ud;
00184         return e;
00185     }
00186 
00187     disk = ud;
00188     return RCOK;
00189 }
00190 
00191 
00192 w_rc_t    sdisk_unix_t::open(const char *name, int flags, int mode)
00193 {
00194     if (_fd != FD_NONE)
00195         return RC(stBADFD);    /* XXX in use */
00196 
00197     _fd = ::os_open(name, convert_flags(flags), mode);
00198     if (_fd == -1) {
00199         w_rc_t rc = RC(fcOS);
00200         RC_APPEND_MSG(rc, << "Offending file: " << name);
00201         return rc;
00202     }
00203 
00204     return RCOK;
00205 }
00206 
00207 w_rc_t    sdisk_unix_t::close()
00208 {
00209     if (_fd == FD_NONE)
00210         return RC(stBADFD);    /* XXX closed */
00211 
00212     int    n;
00213 
00214     n = ::os_close(_fd);
00215     if (n == -1)
00216         return RC(fcOS);
00217 
00218     _fd = FD_NONE;
00219     return RCOK;
00220 }
00221 
00222 
00223 
00224 
00225 w_rc_t    sdisk_unix_t::read(void *buf, int count, int &done)
00226 {
00227     if (_fd == FD_NONE)
00228         return RC(stBADFD);
00229 
00230     int    n;
00231 
00232     INC_STH_STATS(num_io);
00233 
00234     n = ::os_read(_fd, buf, count);
00235     if (n == -1)
00236         return RC(fcOS);
00237 
00238     done = n;
00239 
00240     return RCOK;
00241 }
00242 
00243 w_rc_t    sdisk_unix_t::write(const void *buf, int count, int &done)
00244 {
00245     if (_fd == FD_NONE)
00246         return RC(stBADFD);
00247 
00248     int    n;
00249 
00250     INC_STH_STATS(num_io);
00251 
00252     n = ::os_write(_fd, buf, count);
00253     if (n == -1)
00254         return RC(fcOS);
00255 
00256 #if defined(USING_VALGRIND)
00257     if(RUNNING_ON_VALGRIND)
00258     {
00259         check_valgrind_errors(__LINE__, __FILE__);
00260     }
00261 #endif
00262 
00263     done = n;
00264 
00265     return RCOK;
00266 }
00267 
00268 #ifdef HAVE_IO_VECTOR
00269 w_rc_t    sdisk_unix_t::readv(const iovec_t *iov, int iovcnt, int &done)
00270 {
00271     if (_fd == FD_NONE)
00272         return RC(stBADFD);
00273 
00274     int    n;
00275 
00276     INC_STH_STATS(num_io);
00277 
00278 #ifdef IOVEC_MISMATCH
00279     {
00280         struct iovec _iov[sthread_t::iovec_max];
00281         for (int i = 0; i < iovcnt; i++) {
00282             _iov[i].iov_base = (char *) iov[i].iov_base;
00283             _iov[i].iov_len = iov[i].iov_len;
00284         }
00285         n = ::os_readv(_fd, _iov, iovcnt);
00286     }
00287 #else
00288     n = ::os_readv(_fd, (const struct iovec *)iov, iovcnt);
00289 #endif
00290     if (n == -1)
00291         return RC(fcOS);
00292 
00293     done = n;
00294 
00295     return RCOK;
00296 }
00297 
00298 w_rc_t    sdisk_unix_t::writev(const iovec_t *iov, int iovcnt, int &done)
00299 {
00300     if (_fd == FD_NONE)
00301         return RC(stBADFD);
00302 
00303     int    n;
00304 
00305     INC_STH_STATS(num_io);
00306 
00307 #ifdef IOVEC_MISMATCH
00308     {
00309         struct iovec _iov[sthread_t::iovec_max];
00310         for (int i = 0; i < iovcnt; i++) {
00311             _iov[i].iov_base = (char *) iov[i].iov_base;
00312             _iov[i].iov_len = iov[i].iov_len;
00313         }
00314         n = ::os_writev(_fd, _iov, iovcnt);
00315     }
00316 #else
00317     n = ::os_writev(_fd, (const struct iovec *)iov, iovcnt);
00318 #endif
00319     if (n == -1)
00320         return RC(fcOS);
00321 
00322 #if defined(USING_VALGRIND)
00323     if(RUNNING_ON_VALGRIND)
00324     {
00325         check_valgrind_errors(__LINE__, __FILE__);
00326     }
00327 #endif
00328 
00329     done = n;
00330 
00331     return RCOK;
00332 }
00333 #endif
00334 
00335 w_rc_t    sdisk_unix_t::pread(void *buf, int count, fileoff_t pos, int &done)
00336 {
00337     if (_fd == FD_NONE)
00338         return RC(stBADFD);
00339 
00340     int    n;
00341 
00342     INC_STH_STATS(num_io);
00343 
00344     n = ::os_pread(_fd, buf, count, pos);
00345     if (n == -1)
00346         return RC(fcOS);
00347 
00348     done = n;
00349 
00350     return RCOK;
00351 }
00352 
00353 
00354 w_rc_t    sdisk_unix_t::pwrite(const void *buf, int count, fileoff_t pos,
00355                 int &done)
00356 {
00357     if (_fd == FD_NONE)
00358         return RC(stBADFD);
00359 
00360     int    n;
00361 
00362     INC_STH_STATS(num_io);
00363 
00364     n = ::os_pwrite(_fd, buf, count, pos);
00365     if (n == -1)
00366         return RC(fcOS);
00367 #if defined(USING_VALGRIND)
00368     if(RUNNING_ON_VALGRIND)
00369     {
00370         check_valgrind_errors(__LINE__, __FILE__);
00371     }
00372 #endif
00373 
00374     done = n;
00375 
00376     return RCOK;
00377 }
00378 
00379 w_rc_t    sdisk_unix_t::seek(fileoff_t pos, int origin, fileoff_t &newpos)
00380 {
00381     if (_fd == FD_NONE)
00382         return RC(stBADFD);
00383 
00384     switch (origin) {
00385     case SEEK_AT_SET:
00386         origin = SEEK_SET;
00387         break;
00388     case SEEK_AT_CUR:
00389         origin = SEEK_CUR;
00390         break;
00391     case SEEK_AT_END:
00392         origin = SEEK_END;
00393         break;
00394     }
00395 
00396     fileoff_t    l=0;
00397     l = ::os_lseek(_fd, pos, origin);
00398     if (l == -1)
00399         return RC(fcOS);
00400 
00401     newpos = l;
00402 
00403     return RCOK;
00404 }
00405 
00406 w_rc_t    sdisk_unix_t::truncate(fileoff_t size)
00407 {
00408     if (_fd == FD_NONE)
00409         return RC(stBADFD);
00410     INC_STH_STATS(num_io);
00411     int    n = ::os_ftruncate(_fd, size);
00412     return (n == -1) ? RC(fcOS) : RCOK;
00413 }
00414 
00415 w_rc_t    sdisk_unix_t::sync()
00416 {
00417     if (_fd == FD_NONE)
00418         return RC(stBADFD);
00419 
00420     INC_STH_STATS(num_io);
00421     int n = os_fsync(_fd);
00422 
00423     /* fsync's to r/o files and devices can fail ok */
00424     if (n == -1 && (errno == EBADF || errno == EINVAL))
00425         n = 0;
00426 
00427     return (n == -1) ? RC(fcOS) : RCOK;
00428 }
00429 
00430 
00431 w_rc_t    sdisk_unix_t::stat(filestat_t &st)
00432 {
00433     if (_fd == FD_NONE)
00434         return RC(stBADFD);
00435 
00436     os_stat_t    sys;
00437     int n = os_fstat(_fd, &sys);
00438     if (n == -1)
00439         return RC(fcOS);
00440 
00441     st.st_size = sys.st_size;
00442 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
00443     st.st_block_size = sys.st_blksize;
00444 #else
00445     st.st_block_size = 512;    /* XXX */
00446 #endif
00447 
00448     st.st_device_id = sys.st_dev;
00449     st.st_file_id = sys.st_ino;
00450 
00451     int mode = (sys.st_mode & S_IFMT);
00452     st.is_file = (mode == S_IFREG);
00453     st.is_dir = (mode == S_IFDIR);
00454 #ifdef S_IFBLK
00455     st.is_device = (mode == S_IFBLK);
00456 #else
00457     st.is_device = false;
00458 #endif
00459     st.is_device = st.is_device || (mode == S_IFCHR);
00460 
00461     return RCOK;
00462 }
00463 
00464 /**\endcond skip */

Generated on Wed Jul 7 17:22:32 2010 for Shore Storage Manager by  doxygen 1.4.7