Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Persistent storage durability API 
0003  *  TODO: For MacOS which support F_FULLSYNC, use this fcntl command
0004  *
0005  * @file sys_fsync.c
0006  */
0007 /* -----------------------------------------------------------------------------
0008  * Enduro/X Middleware Platform for Distributed Transaction Processing
0009  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0010  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0011  * This software is released under one of the following licenses:
0012  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0013  * See LICENSE file for full text.
0014  * -----------------------------------------------------------------------------
0015  * AGPL license:
0016  *
0017  * This program is free software; you can redistribute it and/or modify it under
0018  * the terms of the GNU Affero General Public License, version 3 as published
0019  * by the Free Software Foundation;
0020  *
0021  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0022  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0023  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0024  * for more details.
0025  *
0026  * You should have received a copy of the GNU Affero General Public License along 
0027  * with this program; if not, write to the Free Software Foundation, Inc.,
0028  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0029  *
0030  * -----------------------------------------------------------------------------
0031  * A commercial use license is available from Mavimax, Ltd
0032  * contact@mavimax.com
0033  * -----------------------------------------------------------------------------
0034  */
0035 
0036 /*---------------------------Includes-----------------------------------*/
0037 #include <ndrstandard.h>
0038 #include <stdio.h>
0039 #include <stdlib.h>
0040 #include <nstdutil.h>
0041 #include <fcntl.h>
0042 #include "ndebug.h"
0043 #include <nstdutil.h>
0044 /*---------------------------Externs------------------------------------*/
0045 /*---------------------------Macros-------------------------------------*/
0046 #define NDRX_FSYNC_SEP          ","     /**< separator used for config parse */
0047 /*---------------------------Enums--------------------------------------*/
0048 /*---------------------------Typedefs-----------------------------------*/
0049 /*---------------------------Globals------------------------------------*/
0050 /*---------------------------Statics------------------------------------*/
0051 /*---------------------------Prototypes---------------------------------*/
0052 
0053 /**
0054  * Parse fsync setting. Syntax is comma separated keywords
0055  * currently settings are: 
0056  * - fsync - full fsync on file
0057  * - fdatasync - only data content sync on file (no metadata update)
0058  * - dsync - perform directory meta data sync (for new files or moved)
0059  * @param setting_str setting string to parsz
0060  * @param flag parsed setting
0061  * @return EXSUCCEED/EXFAIL
0062  */
0063 expublic int ndrx_fsync_parse(char *setting_str, long *flags)
0064 {
0065     int ret = EXSUCCEED;
0066     char *parse, *p, *saveptr1;
0067     
0068     *flags = 0;
0069     
0070     if (NULL==setting_str || EXEOS==setting_str[0])
0071     {
0072         goto out;
0073     }
0074 
0075     /* remove whitespace */
0076     parse=ndrx_str_strip(setting_str, "\t\n ");
0077     
0078     for (p=strtok_r(parse, NDRX_FSYNC_SEP, &saveptr1); 
0079             NULL!=p; 
0080             p=strtok_r(NULL, NDRX_FSYNC_SEP, &saveptr1))
0081     {
0082         if (0==strcmp(p, NDRX_FSYNC_FSYNC_STR))
0083         {
0084             *flags |= NDRX_FSYNC_FSYNC;
0085         }
0086         else if (0==strcmp(p, NDRX_FSYNC_FDATASYNC_STR))
0087         {
0088             *flags |= NDRX_FSYNC_FDATASYNC;
0089         }
0090         else if (0==strcmp(p, NDRX_FSYNC_DSYNC_STR))
0091         {
0092             *flags |= NDRX_FSYNC_DSYNC;
0093         }
0094         else
0095         {
0096             NDRX_LOG(log_error, "Unknown fsync setting: [%s]", p);
0097             EXFAIL_OUT(ret);
0098         }
0099     }
0100     
0101 out:
0102     
0103     if (EXSUCCEED==ret)
0104     {
0105         NDRX_LOG(log_warn, "fsync setting: 0x%lx", *flags);
0106     }
0107     
0108     return ret;
0109 }
0110 
0111 /**
0112  * Perform fsync on the file contents (if needed)
0113  * @param file handle to sync
0114  * @param setting parsed settings from ndrx_fsync_parse
0115  * @return EXSUCCEED/EXFAIL
0116  */
0117 expublic int ndrx_fsync_fsync(FILE *file, long flags)
0118 {
0119     int ret = EXSUCCEED;
0120     int fd, err;
0121 
0122     if (NULL==file)
0123     {
0124         NDRX_LOG(log_error, "Invalid fsync handle");
0125         EXFAIL_OUT(ret);
0126     }
0127     
0128     if ( (flags & NDRX_FSYNC_FSYNC) || (flags & NDRX_FSYNC_FDATASYNC))
0129     {
0130         fd = fileno(file);
0131         if (EXFAIL==fd)
0132         {
0133             err = errno;
0134             NDRX_LOG(log_error, "%s: fileno() failed on %p: %s", __func__,
0135                     file, strerror(err));
0136             userlog("%s: fileno() failed on %p: %s", __func__,
0137                     file, strerror(err));
0138             EXFAIL_OUT(ret);
0139         }
0140     }
0141     
0142     if (flags & NDRX_FSYNC_FSYNC)
0143     {
0144         if (EXSUCCEED!=fsync(fd))
0145         {
0146             int err = errno;
0147             NDRX_LOG(log_error, "%s: fsync() failed on %p / %d: %s", __func__,
0148                     file, fd, strerror(err));
0149             userlog("%s: fsync() failed on %p / %d: %s", __func__,
0150                     file, fd, strerror(err));
0151             EXFAIL_OUT(ret);
0152         }
0153     }
0154     else if (flags & NDRX_FSYNC_FDATASYNC)
0155     {
0156 #ifdef EX_OS_DARWIN
0157         /* no fdatasync (warning) on macos */
0158         if (EXSUCCEED!=fsync(fd))
0159 #else
0160         if (EXSUCCEED!=fdatasync(fd))
0161 #endif
0162         {
0163             int err = errno;
0164             NDRX_LOG(log_error, "%s: fdatasync() failed on %p / %d: %s", __func__,
0165                     file, fd, strerror(err));
0166             userlog("%s: fdatasync() failed on %p / %d: %s", __func__,
0167                     file, fd, strerror(err));
0168             EXFAIL_OUT(ret);
0169         }
0170     }
0171     
0172 out:
0173     return ret;
0174 }
0175 
0176 /**
0177  * Perform directory sync
0178  * @param dir directory to sync
0179  * @param flags parsed setting
0180  * @return EXSUCCEED/EXFAIL
0181  */
0182 expublic int ndrx_fsync_dsync(char *dir, long flags)
0183 {
0184     int ret = EXSUCCEED;
0185     int err, fd=EXFAIL;
0186     
0187     if (NULL==dir || EXEOS==dir[0])
0188     {
0189         NDRX_LOG(log_error, "NULL/empty dsync handle");
0190         EXFAIL_OUT(ret);
0191     }
0192 
0193     if (flags & NDRX_FSYNC_DSYNC)
0194     {
0195         fd = open(dir, O_RDONLY);
0196         
0197         if (EXFAIL==fd)
0198         {
0199             err = errno;
0200             NDRX_LOG(log_error, "%s: failed to open dir [%s]: %s", 
0201                     __func__, dir, strerror(err));
0202             userlog("%s: Failed to open dir [%s]: %s", 
0203                     __func__, dir, strerror(err));
0204             EXFAIL_OUT(ret);
0205         }
0206 
0207 #ifdef EX_OS_AIX
0208         /* On aix getting "Bad file number" 
0209          * thus only what we can do is ignore these errors
0210          */
0211         fsync_range(fd, O_DSYNC, 0, 0);
0212 #else
0213         if (EXSUCCEED!=fsync(fd))
0214         {
0215             int err = errno;
0216             NDRX_LOG(log_error, "%s: fsync() failed on %s / %d: %s", __func__,
0217                     dir, fd, strerror(err));
0218             userlog("%s: fsync() failed on %s / %d: %s", __func__,
0219                     dir, fd, strerror(err));
0220             EXFAIL_OUT(ret);
0221         }        
0222 #endif
0223     }
0224     
0225 out:
0226     
0227     if (EXFAIL!=fd)
0228     {
0229         close(fd);
0230     }
0231 
0232     return ret;
0233 }
0234 
0235 /* vim: set ts=4 sw=4 et smartindent: */