src/xcalls/x_write.c

Go to the documentation of this file.
00001 
00007 #include <fcntl.h>
00008 #include <unistd.h>
00009 #include <errno.h>
00010 #include <string.h>
00011 #include <stdlib.h>
00012 #include <misc/debug.h>
00013 #include <misc/errno.h>
00014 #include <core/tx.h>
00015 #include <core/config.h>
00016 #include <core/koa.h>
00017 #include <core/buffer.h>
00018 #include <core/txdesc.h>
00019 #include <core/stats.h>
00020 #include <libc/syscalls.h>
00021 #include <xcalls/xcalls.h>
00022 
00023 
00024 #define TXC_WRITE_SEQ         0x1
00025 #define TXC_WRITE_OVR_SAVE    0x2
00026 #define TXC_WRITE_OVR_IGNORE  0x3
00027 
00028 typedef struct x_write_undo_args_s x_write_undo_args_t;
00029 
00030 struct x_write_undo_args_s {
00031         int  fd;
00032         void *buf;
00033         int  nbyte_new;
00034         int  nbyte_old;
00035 };
00036 
00037 
00038 static
00039 void
00040 x_write_seq_undo(void *args, int *result)
00041 {
00042         x_write_undo_args_t *args_undo = (x_write_undo_args_t *) args;
00043         off_t               offset;
00044         int                 local_result = 0;
00045 
00046         if ((offset = txc_libc_lseek(args_undo->fd, 
00047                                      -(args_undo->nbyte_new), SEEK_CUR)) < 0) 
00048         {
00049                 local_result = errno;
00050                 goto done;
00051         }
00052         if (txc_libc_ftruncate(args_undo->fd, offset) < 0) {
00053                 local_result = errno;
00054         }       
00055 done:
00056         if (result) {
00057                 *result = local_result;
00058         }       
00059 }
00060 
00061 
00062 static
00063 void
00064 x_write_ovr_undo(void *args, int *result)
00065 {
00066         x_write_undo_args_t *args_undo = (x_write_undo_args_t *) args;
00067         off_t               offset;
00068         int                 local_result = 0;
00069 
00070         if ((offset = txc_libc_lseek(args_undo->fd, 
00071                                      -(args_undo->nbyte_new), SEEK_CUR)) < 0) 
00072         {
00073                 local_result = errno;
00074                 goto done;
00075         }
00076         if (args_undo->buf) {   
00077                 if (args_undo->nbyte_old < args_undo->nbyte_new) {
00078                         /*
00079                          * (nbyte_old < nbyte_new) means we wrote more data than we were 
00080                          * able to read. Treat this as the write was near the end-of-file 
00081                          * and truncate the file to its original size.
00082                          * (nbyte_old < nbyte_new) could also hold if we were interrupted 
00083                          * by a signal but currently we treat this as a failure and report
00084                          * it to user.
00085                          */
00086                         if (txc_libc_ftruncate(args_undo->fd, offset) < 0) {
00087                                 local_result = errno;
00088                                 goto done;
00089                         }       
00090                 }
00091                 if (txc_libc_pwrite(args_undo->fd, args_undo->buf, 
00092                                     args_undo->nbyte_old, offset)  < 0)
00093                 {
00094                         local_result = errno;
00095                 }
00096         }
00097 done:
00098         if (result) {
00099                 *result = local_result;
00100         }       
00101 }
00102 
00103 
00104 static
00105 ssize_t 
00106 x_write(int fd, const void *buf, size_t nbyte, int *result, int flags)
00107 {
00108         txc_tx_t            *txd;
00109         txc_koamgr_t        *koamgr = txc_g_koamgr;
00110         txc_koa_t           *koa;
00111         txc_sentinel_t      *sentinel;
00112         txc_result_t        xret;
00113         int                 ret;
00114         void                *old_data;
00115         x_write_undo_args_t *args_write_undo;
00116         int                 local_result;
00117 
00118 
00119         txd = txc_tx_get_txd();
00120 
00121         switch(txc_tx_get_xactstate(txd)) {
00122                 case TXC_XACTSTATE_TRANSACTIONAL_IRREVOCABLE:
00123                 case TXC_XACTSTATE_NONTRANSACTIONAL:
00124                         if ((ret = txc_libc_write(fd, buf, nbyte)) < 0) {
00125                                 local_result = errno;
00126                         } else {
00127                                 local_result = 0;
00128                         }
00129                         goto done;
00130 
00131                 case TXC_XACTSTATE_TRANSACTIONAL_RETRYABLE:
00132                         txc_koa_lock_fd(koamgr, fd);
00133                         xret = txc_koa_lookup_fd2koa(koamgr, fd, &koa);
00134                         if (xret == TXC_R_FAILURE) {
00135                                 /* 
00136                                  * The KOA mapped to the file descriptor has gone. Report
00137                                  * this error as invalid file descriptor.
00138                                  */
00139                                 txc_koa_unlock_fd(koamgr, fd);
00140                                 local_result = EBADF;
00141                                 ret = -1;
00142                                 goto done;
00143                         }
00144                         sentinel = txc_koa_get_sentinel(koa);
00145                         xret = txc_sentinel_tryacquire(txd, sentinel, 
00146                                                        TXC_SENTINEL_ACQUIREONRETRY);
00147                         txc_koa_unlock_fd(koamgr, fd);
00148                         if (xret == TXC_R_BUSYSENTINEL) {
00149                                 txc_tx_abort_transaction(txd, TXC_ABORTREASON_BUSYSENTINEL);
00150                                 TXC_INTERNALERROR("Never gets here. Transaction abort failed.\n");
00151                         }
00152 
00153                         /* Got sentinel. Continue with the rest of the stuff. */
00154                         switch (flags) {
00155                                 case TXC_WRITE_SEQ:
00156                                         if ((args_write_undo = (x_write_undo_args_t *)
00157                                                        txc_buffer_linear_malloc(txd->buffer_linear, 
00158                                                                                         sizeof(x_write_undo_args_t)))
00159                                                 == NULL)
00160                                         {
00161                                                 local_result = ENOMEM;
00162                                                 ret = -1;
00163                                                 goto error_handler_write_seq_0;
00164                                         }
00165                                         args_write_undo->fd = fd;
00166                                         if ((ret = txc_libc_write(fd, buf, nbyte)) < 0) {
00167                                                 local_result = errno;
00168                                                 goto error_handler_write_seq_1;
00169                                         }
00170                                         args_write_undo->nbyte_new = ret;
00171                                         txc_tx_register_undo_action(txd, x_write_seq_undo, 
00172                                                                     (void *) args_write_undo, result,
00173                                                                     TXC_TX_REGULAR_UNDO_ACTION_ORDER);
00174                                         local_result = 0;                                                       
00175                                         ret = args_write_undo->nbyte_new;
00176                                         txc_stats_txstat_increment(txd, XCALL, x_write_seq, 1);
00177                                         goto done;
00178 
00179                         case TXC_WRITE_OVR_IGNORE:
00180                         case TXC_WRITE_OVR_SAVE:
00181                                         if ((args_write_undo = (x_write_undo_args_t *)
00182                                                        txc_buffer_linear_malloc(txd->buffer_linear, 
00183                                                                                         sizeof(x_write_undo_args_t)))
00184                                             == NULL)
00185                                         {       
00186                                                 local_result = ENOMEM;
00187                                                 ret = -1;
00188                                                 goto error_handler_write_ovr_0;
00189                                         }
00190                                         if (flags == TXC_WRITE_OVR_SAVE) {
00191                                                 if ((old_data = (void *) txc_buffer_linear_malloc(txd->buffer_linear, 
00192                                                                                                   sizeof(char) * nbyte))
00193                                                     == NULL) 
00194                                                 {
00195                                                         local_result = ENOMEM;
00196                                                         ret = -1;
00197                                                         goto error_handler_write_ovr_1;
00198                                                 }
00199                                                 if ((ret = txc_libc_read(fd, old_data, nbyte)) < 0) {
00200                                                         local_result = errno;
00201                                                         goto error_handler_write_ovr_2;                                    
00202                                                 }
00203                                                 args_write_undo->nbyte_old = ret;
00204                                         } else { /* TXC_WRITE_OVR_IGNORE */
00205                                                 args_write_undo->nbyte_old = 0;
00206                                                 old_data = NULL;
00207                                         }
00208                                         args_write_undo->buf = old_data;
00209                                         args_write_undo->fd = fd;
00210                                         if (args_write_undo->nbyte_old > 0) {
00211                                                 txc_libc_lseek(fd, -args_write_undo->nbyte_old, SEEK_CUR);
00212                                         }       
00213                                         if ((ret = txc_libc_write(fd, buf, nbyte)) < 0) {
00214                                                 local_result = errno;
00215                                                 goto error_handler_write_ovr_2;
00216                                         }
00217                                         args_write_undo->nbyte_new = ret;
00218                                         txc_tx_register_undo_action(txd, x_write_ovr_undo, 
00219                                                                     (void *) args_write_undo, result,
00220                                                                     TXC_TX_REGULAR_UNDO_ACTION_ORDER);
00221                                         local_result = 0;                                                       
00222                                         ret = args_write_undo->nbyte_new;
00223                                         if (flags == TXC_WRITE_OVR_SAVE) {
00224                                                 txc_stats_txstat_increment(txd, XCALL, x_write_ovr, 1);
00225                                         } else {
00226                                                 txc_stats_txstat_increment(txd, XCALL, x_write_ovr_ignore, 1);
00227                                         }
00228                                         goto done;
00229 
00230                                 default:
00231                                         TXC_INTERNALERROR("Unknown x_write type\n");
00232                         }
00233                         
00234                 default:
00235                         TXC_INTERNALERROR("Unknown transaction state\n");
00236         }
00237 
00238 error_handler_write_ovr_2:
00239         if (old_data) {
00240                 txc_buffer_linear_free(txd->buffer_linear, 
00241                                        sizeof(char) *nbyte);
00242         }
00243 
00244 error_handler_write_seq_1:
00245 error_handler_write_ovr_1:
00246         txc_buffer_linear_free(txd->buffer_linear,
00247                                    sizeof(x_write_undo_args_t));
00248 
00249 error_handler_write_seq_0:
00250 error_handler_write_ovr_0:
00251 done:
00252         if (result) {
00253                 *result = local_result;
00254         }
00255         return ret;
00256 }
00257 
00258 
00273 ssize_t 
00274 XCALL_DEF(x_write_seq)(int fd, const void *buf, size_t nbyte, int *result)
00275 {
00276         return x_write(fd, buf, nbyte, result, TXC_WRITE_SEQ);
00277 }
00278 
00279 
00294 ssize_t 
00295 XCALL_DEF(x_write_ovr_ignore)(int fd, const void *buf, size_t nbyte, int *result)
00296 {
00297         return x_write(fd, buf, nbyte, result, TXC_WRITE_OVR_IGNORE);
00298 }
00299 
00300 
00304 ssize_t 
00305 XCALL_DEF(x_write_ovr_save)(int fd, const void *buf, size_t nbyte, int *result)
00306 {
00307         return x_write(fd, buf, nbyte, result, TXC_WRITE_OVR_SAVE);
00308 }
00309 
00310 
00325 ssize_t 
00326 XCALL_DEF(x_write_ovr)(int fd, const void *buf, size_t nbyte, int *result)
00327 {
00328         return x_write(fd, buf, nbyte, result, TXC_WRITE_OVR_SAVE);
00329 }

Generated on Wed Dec 9 20:32:39 2009 for xCalls by  doxygen 1.4.7