src/xcalls/x_create.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/stats.h>
00019 #include <libc/syscalls.h>
00020 #include <core/txdesc.h>
00021 #include <xcalls/xcalls.h>
00022 
00023 
00030 typedef struct x_create_case1_commit_undo_args_s   x_create_case1_commit_undo_args_t;
00031 
00032 struct x_create_case1_commit_undo_args_s {
00033         int          fd;
00034         txc_koa_t    *koa;
00035         char         pathname[TXC_MAX_LEN_PATHNAME];
00036 };
00037 
00038 
00039 static
00040 void
00041 x_create_case1_undo(void *args, int *result)
00042 {
00043         int                                ret1;
00044         int                                local_result = 0; 
00045         x_create_case1_commit_undo_args_t *myargs = (x_create_case1_commit_undo_args_t *) args;
00046         txc_koamgr_t                       *koamgr;
00047 
00048         koamgr = txc_koa_get_koamgr(myargs->koa);
00049         txc_koa_lock_alias_cache(koamgr);
00050         if ((ret1 = txc_libc_unlink(myargs->pathname)) < 0) {
00051                 local_result = errno;
00052         }
00053         txc_koa_detach_fd(myargs->koa, myargs->fd, 1);
00054         if (txc_libc_close(myargs->fd) < 0) {
00055                 if (ret1 == 0) {
00056                         local_result = errno;
00057                 }       
00058         }       
00059         txc_koa_unlock_alias_cache(koamgr);
00060         if (result) {
00061                 *result = local_result;
00062         }
00063 }
00064 
00065 
00066 /*
00067  * Case 2a: commit and undo actions
00068  */
00069 
00070 typedef struct x_create_case2_commit_undo_args_s   x_create_case2_commit_undo_args_t;
00071 
00072 struct x_create_case2_commit_undo_args_s {
00073         int          fd;
00074         txc_koa_t    *koa;
00075         char         temp_pathname[TXC_MAX_LEN_PATHNAME];
00076         char         original_pathname[TXC_MAX_LEN_PATHNAME];
00077 
00078 };
00079 
00080 
00081 static
00082 void
00083 x_create_case2_commit(void *args, int *result)
00084 {
00085         int                                local_result = 0;
00086         x_create_case2_commit_undo_args_t *myargs = (x_create_case2_commit_undo_args_t *) args;
00087 
00088         if ((txc_libc_unlink(myargs->temp_pathname) < 0)) {
00089                 local_result = errno;
00090         }       
00091         if (result) {
00092                 *result = local_result;
00093         }
00094 }
00095 
00096 
00097 static
00098 void
00099 x_create_case2_undo(void *args, int *result)
00100 {
00101         int                                ret1;
00102         int                                ret2;
00103         int                                local_result = 0; 
00104         x_create_case2_commit_undo_args_t *myargs = (x_create_case2_commit_undo_args_t *) args;
00105         txc_koamgr_t                       *koamgr;
00106 
00107         koamgr = txc_koa_get_koamgr(myargs->koa);
00108         txc_koa_lock_alias_cache(koamgr);
00109         if ((ret1 = txc_libc_unlink(myargs->original_pathname)) < 0) {
00110                 local_result = errno;
00111         }
00112         if ((ret2 = txc_libc_rename(myargs->temp_pathname, 
00113                                     myargs->original_pathname)) < 0) 
00114         {
00115                 if (ret1 == 0) {
00116                         local_result = errno;
00117                 }       
00118         }       
00119         txc_koa_detach_fd(myargs->koa, myargs->fd, 1);
00120         if (txc_libc_close(myargs->fd) < 0) {
00121                 if (ret1 == 0 && ret2 == 0) {
00122                         local_result = errno;
00123                 }       
00124         }       
00125         txc_koa_unlock_alias_cache(koamgr);
00126         if (result) {
00127                 *result = local_result;
00128         }
00129 }
00130 
00131 
00149 int
00150 XCALL_DEF(x_create)(const char *pathname, mode_t mode, int *result) 
00151 {
00152         txc_tx_t       *txd;
00153         txc_koamgr_t   *koamgr = txc_g_koamgr;
00154         txc_koa_t      *koa_new;
00155         txc_koa_t      *koa_old;
00156         txc_sentinel_t *sentinel;
00157         txc_result_t   xret;
00158         int            fildes;
00159         int            ret;
00160         int            local_result = 0;
00161         ino_t          inode;
00162         char           temp_pathname[128]; 
00163         int            creation_flags = O_CREAT| O_NOCTTY| O_TRUNC| O_RDWR;
00164 
00165         txd = txc_tx_get_txd();
00166 
00167         switch(txc_tx_get_xactstate(txd)) {
00168                 case TXC_XACTSTATE_TRANSACTIONAL_RETRYABLE:
00169                         /* Serialize open/create/close file operations to detect aliasing */
00170                         txc_koa_lock_alias_cache(koamgr);
00171                         txc_koa_path2inode(pathname, &inode);
00172                         TXC_DEBUG_PRINT(TXC_DEBUG_XCALL, "X_CREATE: path = %s, inode= %d\n", 
00173                                         pathname, inode);
00174                         if (inode == 0) {
00175                                 x_create_case1_commit_undo_args_t *args_commit_undo; 
00176                                 /* 
00177                                  * CASE 1: File does not exist.  
00178                                  */
00179 
00180                                 /* 
00181                                  * The logic is similar to CASE 2. The difference is that we 
00182                                  * don't have an existing file to rename.
00183                                  */
00184 
00185                                 TXC_ASSERT(txc_koa_alias_cache_lookup_inode(koamgr, inode, &koa_old) 
00186                                            == TXC_R_NOTEXISTS);
00187 
00188                                 if ((ret = fildes = txc_libc_open(pathname, 
00189                                                                   creation_flags, 
00190                                                                       mode)) < 0) 
00191                                 {
00192                                         txc_koa_unlock_alias_cache(koamgr);
00193                                         local_result = errno;
00194                                         goto done;
00195                                 }
00196                                 txc_koa_path2inode(pathname, &inode);
00197                                 txc_koa_create(koamgr, &koa_new, TXC_KOA_IS_FILE, (void *) inode);
00198                                 txc_koa_lock_fd(koamgr, fildes);
00199                                 txc_koa_attach_fd(koa_new, fildes, 0);
00200                                 sentinel = txc_koa_get_sentinel(koa_new);
00201                                  /* 
00202                                   * We don't ask the sentinel to be acquired after restart.
00203                                   * This is because the KOA is created by this transaction, 
00204                                   * thus it won't be live after transaction rollbacks. So 
00205                                   * the sentinel mapped to the KOA does not need to be 
00206                                   * reacquired.
00207                                   *
00208                                   * Note though that someone may see the KOA, try to get
00209                                   * the sentinel and fail, and retry when the transaction 
00210                                   * restarts. Thus, this guy continues holding a reference 
00211                                   * to the sentinel even if the KOA has been be destroyed. 
00212                                   * This is fine since a sentinel is detached from a KOA 
00213                                   * when the latter is destroyed, but is not destroyed 
00214                                   * until its refcnt reaches zero.
00215                                   */
00216                                 xret = txc_sentinel_tryacquire(txd, sentinel, 0);
00217                                 if (xret != TXC_R_SUCCESS) {
00218                                         TXC_INTERNALERROR("Cannot acquire the sentinel of the KOA I've just created!\n");
00219                                 }
00220                                 args_commit_undo = (x_create_case1_commit_undo_args_t *)
00221                                                    txc_buffer_linear_malloc(txd->buffer_linear, 
00222                                                                             sizeof(x_create_case1_commit_undo_args_t));
00223                                 if (args_commit_undo == NULL) {
00224                                         TXC_INTERNALERROR("Allocation failed. Linear buffer out of space.\n");
00225                                 }
00226                                 strcpy(args_commit_undo->pathname, pathname);
00227                                 args_commit_undo->koa = koa_new;
00228                                 args_commit_undo->fd = fildes;
00229 
00230                                 txc_tx_register_undo_action  (txd, x_create_case1_undo, 
00231                                                               (void *) args_commit_undo, result,
00232                                                               TXC_KOA_CREATE_UNDO_ACTION_ORDER);
00233 
00234                                 txc_koa_unlock_fd(koamgr, fildes);
00235                                 txc_koa_unlock_alias_cache(koamgr);
00236                                 ret = fildes;
00237                         } else {
00238                                 /* 
00239                                  * CASE 2: Overwriting an existing file.  
00240                                  */
00241                                  
00242                                 if (txc_koa_alias_cache_lookup_inode(koamgr, inode, &koa_old) 
00243                                     == TXC_R_SUCCESS) 
00244                                 {
00245                                         TXC_DEBUG_PRINT(TXC_DEBUG_XCALL, "X_CREATE: Case 2A\n");
00246                                         /* 
00247                                          * CASE 2a:
00248                                          *  - Overwriting an existing file, and 
00249                                          *  - KOA exists in the alias cache so other in-flight 
00250                                          *    transaction may operate on the file.
00251                                          */
00252 
00253                                         /*
00254                                          * Acquire the sentinel attached to the existing KOA to
00255                                          * properly isolated ourself from other transaction 
00256                                          * operating on the file.
00257                                          * e.g other transaction could be:
00258                                          *   atomic {
00259                                          *     fd = create(pathname, ...);
00260                                          *     write(fd, ...);
00261                                          *     close(fd);
00262                                          *     unlink(pathname);
00263                                          *   }
00264                                          *
00265                                          * While this transaction might not make any sense, we 
00266                                          * still need to ensure it is executed correctly. Thus,
00267                                          * this transaction must delete the file it created.
00268                                          * If here we don't acquire the sentinel of that KOA
00269                                          * then the unlink operation will see the new file (because
00270                                          * we rename in-place) and therefore will try to
00271                                          * acquire the sentinel of the new KOA and fail. While
00272                                          * this will abort the transaction and result in correct
00273                                          * execution we still feel that is not the right thing
00274                                          * to do and could make the implementation more complex.
00275                                          */
00276 
00277                                         txc_koa_lock_fds_refby_koa(koa_old);
00278                                         sentinel = txc_koa_get_sentinel(koa_old);
00279                                          /* We don't ask the sentinel to be acquired after restart. */
00280                                         xret = txc_sentinel_tryacquire(txd, sentinel, 0);
00281                                         if (xret == TXC_R_BUSYSENTINEL) {
00282                                                 txc_koa_unlock_fds_refby_koa(koa_old);
00283                                                 txc_koa_unlock_alias_cache(koamgr);
00284                                                 txc_tx_abort_transaction(txd, TXC_ABORTREASON_BUSYSENTINEL);
00285                                                 TXC_INTERNALERROR("Never gets here. Transaction abort failed.\n");
00286                                         } else {
00287                                                 txc_koa_unlock_fds_refby_koa(koa_old);
00288                                         }
00289                                 
00290                                 } else {
00291                                         TXC_DEBUG_PRINT(TXC_DEBUG_XCALL, "X_CREATE: Case 2B\n");
00292                                         /* 
00293                                          * CASE 2b:
00294                                          * - Overwriting an existing file, and
00295                                          * - KOA does not exist in the alias cache so there is no
00296                                          *   way for some other in-flight transaction to have a 
00297                                          *   reference to the file to operate on it.
00298                                          */
00299 
00300                                          /* 
00301                                           * No special actions for this case. Fall through the 
00302                                           * common code.
00303                                           */
00304                                 }       
00305                                 x_create_case2_commit_undo_args_t *args_commit_undo; 
00306                                 strcpy(temp_pathname, "/tmp/libtxc.tmp.XXXXXX");
00307                                 mktemp(temp_pathname); 
00308                                 txc_libc_rename(pathname, temp_pathname);
00309                                 if ((ret = fildes = txc_libc_open(pathname, 
00310                                                                   creation_flags, 
00311                                                                       mode)) < 0) 
00312                                 {
00313                                         txc_libc_rename(temp_pathname, pathname);
00314                                         txc_koa_unlock_alias_cache(koamgr);
00315                                         local_result = errno;
00316                                         goto done;
00317                                 }
00318                                 txc_koa_path2inode(pathname, &inode);
00319                                 txc_koa_create(koamgr, &koa_new, TXC_KOA_IS_FILE, (void *) inode);
00320 
00321                                 TXC_DEBUG_PRINT(TXC_DEBUG_XCALL, 
00322                                                 "X_CREATE: Case 2B: KOA = %x\n", 
00323                                                 koa_old);
00324                                 txc_koa_lock_fd(koamgr, fildes);
00325                                 txc_koa_attach_fd(koa_new, fildes, 0);
00326                                 TXC_ASSERT(TXC_R_SUCCESS == txc_koa_alias_cache_lookup_inode(koamgr, inode, &koa_old)); 
00327                                 sentinel = txc_koa_get_sentinel(koa_new);
00328                                  /* 
00329                                   * We don't ask the sentinel to be acquired after restart.
00330                                   * This is because the KOA is created by this transaction, 
00331                                   * thus it won't be live after transaction rollbacks. So 
00332                                   * the sentinel mapped to the KOA does not need to be 
00333                                   * reacquired.
00334                                   *
00335                                   * Note though that someone may see the KOA, try to get
00336                                   * the sentinel and fail, and retry when the transaction 
00337                                   * restarts. Thus, this guy continues holding a reference 
00338                                   * to the sentinel even if the KOA has been be destroyed. 
00339                                   * This is fine since a sentinel is detached from a KOA 
00340                                   * when the latter is destroyed, but is not destroyed 
00341                                   * until its refcnt reaches zero.
00342                                   */
00343                                 xret = txc_sentinel_tryacquire(txd, sentinel, 0);
00344                                 if (xret != TXC_R_SUCCESS) {
00345                                         TXC_INTERNALERROR("Cannot acquire the sentinel of the KOA I've just created!\n");
00346                                 }
00347                                 args_commit_undo = (x_create_case2_commit_undo_args_t *)
00348                                                    txc_buffer_linear_malloc(txd->buffer_linear, 
00349                                                                             sizeof(x_create_case2_commit_undo_args_t));
00350                                 if (args_commit_undo == NULL) {
00351                                         TXC_INTERNALERROR("Allocation failed. Linear buffer out of space.\n");
00352                                 }
00353                                 strcpy(args_commit_undo->temp_pathname, temp_pathname);
00354                                 strcpy(args_commit_undo->original_pathname, pathname);
00355                                 args_commit_undo->koa = koa_new;
00356                                 args_commit_undo->fd = fildes;
00357 
00358                                 txc_tx_register_commit_action(txd, x_create_case2_commit, 
00359                                                               (void *) args_commit_undo, result,
00360                                                               TXC_KOA_CREATE_COMMIT_ACTION_ORDER);
00361                                 txc_tx_register_undo_action  (txd, x_create_case2_undo, 
00362                                                               (void *) args_commit_undo, result,
00363                                                               TXC_KOA_CREATE_UNDO_ACTION_ORDER);
00364 
00365                                 txc_koa_unlock_fd(koamgr, fildes);
00366                                 txc_koa_unlock_alias_cache(koamgr);
00367                                 ret = fildes;
00368                         }
00369                         txc_stats_txstat_increment(txd, XCALL, x_create, 1);
00370                         break;
00371                 case TXC_XACTSTATE_TRANSACTIONAL_IRREVOCABLE:
00372                 case TXC_XACTSTATE_NONTRANSACTIONAL:
00373                         /* 
00374                          * Even if xCalls don't provide transactional properties when called
00375                          * outside of a transaction, we still need to create a KOA and assign
00376                          * a sentinel to be used later by any transactional xCalls. Thus, we
00377                          * still need to properly synchronize accesses to internal data
00378                          * structures.
00379                          */
00380                         txc_koa_lock_alias_cache(koamgr);
00381                         if ((ret = fildes = txc_libc_open(pathname, creation_flags, mode)) < 0) { 
00382                                 local_result = errno;
00383                                 goto done;
00384                         }
00385                         txc_koa_path2inode(pathname, &inode);
00386                         txc_koa_create(koamgr, &koa_new, TXC_KOA_IS_FILE, (void *) inode);
00387                         txc_koa_lock_fd(koamgr, fildes);
00388                         txc_koa_attach_fd(koa_new, fildes, 0);
00389                         sentinel = txc_koa_get_sentinel(koa_new);
00390                         txc_koa_unlock_fd(koamgr, fildes);
00391                         txc_koa_unlock_alias_cache(koamgr);
00392                         ret = fildes;
00393                         break;
00394                 default:
00395                         TXC_INTERNALERROR("Unknown transaction state\n");
00396         }
00397 done:
00398         if (result) {
00399                 *result = local_result; 
00400         }
00401         return ret;
00402 }

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