diff options
Diffstat (limited to 'libglusterfs/src')
| -rw-r--r-- | libglusterfs/src/Makefile.am | 4 | ||||
| -rw-r--r-- | libglusterfs/src/mem-types.h | 4 | ||||
| -rw-r--r-- | libglusterfs/src/store.c | 640 | ||||
| -rw-r--r-- | libglusterfs/src/store.h | 103 | 
4 files changed, 748 insertions, 3 deletions
diff --git a/libglusterfs/src/Makefile.am b/libglusterfs/src/Makefile.am index d0a617e7b71..046e1b984c9 100644 --- a/libglusterfs/src/Makefile.am +++ b/libglusterfs/src/Makefile.am @@ -16,7 +16,7 @@ libglusterfs_la_SOURCES = dict.c xlator.c logging.c \  	hashfn.c defaults.c common-utils.c timer.c inode.c call-stub.c \  	compat.c fd.c compat-errno.c event.c mem-pool.c gf-dirent.c syscall.c \  	iobuf.c globals.c statedump.c stack.c checksum.c daemon.c \ -	$(CONTRIBDIR)/rbtree/rb.c rbthash.c latency.c \ +	$(CONTRIBDIR)/rbtree/rb.c rbthash.c store.c latency.c \  	graph.c $(CONTRIBDIR)/uuid/clear.c $(CONTRIBDIR)/uuid/copy.c \  	$(CONTRIBDIR)/uuid/gen_uuid.c $(CONTRIBDIR)/uuid/pack.c \  	$(CONTRIBDIR)/uuid/parse.c $(CONTRIBDIR)/uuid/unparse.c \ @@ -37,7 +37,7 @@ noinst_HEADERS = common-utils.h defaults.h dict.h glusterfs.h hashfn.h \  	logging.h xlator.h stack.h timer.h list.h inode.h call-stub.h compat.h \  	fd.h revision.h compat-errno.h event.h mem-pool.h byte-order.h \  	gf-dirent.h locking.h syscall.h iobuf.h globals.h statedump.h \ -	checksum.h daemon.h $(CONTRIBDIR)/rbtree/rb.h \ +	checksum.h daemon.h $(CONTRIBDIR)/rbtree/rb.h store.h\  	rbthash.h iatt.h latency.h mem-types.h $(CONTRIBDIR)/uuid/uuidd.h \  	$(CONTRIBDIR)/uuid/uuid.h $(CONTRIBDIR)/uuid/uuidP.h \  	$(CONTRIB_BUILDDIR)/uuid/uuid_types.h syncop.h graph-utils.h trie.h run.h \ diff --git a/libglusterfs/src/mem-types.h b/libglusterfs/src/mem-types.h index 12379bf3181..015cd1a3b0e 100644 --- a/libglusterfs/src/mem-types.h +++ b/libglusterfs/src/mem-types.h @@ -102,6 +102,8 @@ enum gf_common_mem_types_ {          gf_common_mt_buffer_t             = 86,          gf_common_mt_circular_buffer_t    = 87,          gf_common_mt_eh_t                 = 88, -        gf_common_mt_end                  = 89 +        gf_common_mt_store_handle_t       = 89, +        gf_common_mt_store_iter_t         = 90, +        gf_common_mt_end                  = 91  };  #endif diff --git a/libglusterfs/src/store.c b/libglusterfs/src/store.c new file mode 100644 index 00000000000..eddd9092443 --- /dev/null +++ b/libglusterfs/src/store.c @@ -0,0 +1,640 @@ +/* +   Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> +   This file is part of GlusterFS. + +   This file is licensed to you under your choice of the GNU Lesser +   General Public License, version 3 or any later version (LGPLv3 or +   later), or the GNU General Public License, version 2 (GPLv2), in all +   cases as published by the Free Software Foundation. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <inttypes.h> +#include <libgen.h> + +#include "glusterfs.h" +#include "store.h" +#include "dict.h" +#include "xlator.h" + +int32_t +gf_store_mkdir (char *path) +{ +        int32_t     ret = -1; + +        ret = mkdir (path, 0777); + +        if ((-1 == ret) && (EEXIST != errno)) { +                gf_log ("", GF_LOG_ERROR, "mkdir() failed on path %s," +                        "errno: %s", path, strerror (errno)); +        } else { +                ret = 0; +        } + +        return ret; +} + +int32_t +gf_store_handle_create_on_absence (gf_store_handle_t **shandle, +                                   char *path) +{ +        GF_ASSERT (shandle); +        int32_t     ret = 0; + +        if (*shandle == NULL) { +                ret = gf_store_handle_new (path, shandle); + +                if (ret) { +                        gf_log ("", GF_LOG_ERROR, "Unable to create store" +                                " handle for path: %s", path); +                } +        } +        return ret; +} + +int32_t +gf_store_mkstemp (gf_store_handle_t *shandle) +{ +        int     fd = -1; +        char    tmppath[PATH_MAX] = {0,}; + +        GF_ASSERT (shandle); +        GF_ASSERT (shandle->path); + +        snprintf (tmppath, sizeof (tmppath), "%s.tmp", shandle->path); +        fd = open (tmppath, O_RDWR | O_CREAT | O_TRUNC | O_SYNC, 0600); +        if (fd <= 0) { +                gf_log ("", GF_LOG_ERROR, "Failed to open %s, error: %s", +                        tmppath, strerror (errno)); +        } + +        return fd; +} + +int +gf_store_sync_direntry (char *path) +{ +        int             ret     = -1; +        int             dirfd   = -1; +        char            *dir    = NULL; +        char            *pdir   = NULL; +        xlator_t        *this = NULL; + +        this = THIS; + +        dir = gf_strdup (path); +        if (!dir) +                goto out; + +        pdir = dirname (dir); +        dirfd = open (pdir, O_RDONLY); +        if (dirfd == -1) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to open directory " +                        "%s, due to %s", pdir, strerror (errno)); +                goto out; +        } + +        ret = fsync (dirfd); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "Failed to fsync %s, due to " +                        "%s", pdir, strerror (errno)); +                goto out; +        } + +        ret = 0; +out: +        if (dirfd >= 0) { +                ret = close (dirfd); +                if (ret) { +                        gf_log (this->name, GF_LOG_ERROR, "Failed to close " +                                "%s, due to %s", pdir, strerror (errno)); +                } +        } + +        if (dir) +                GF_FREE (dir); + +        return ret; +} + +int32_t +gf_store_rename_tmppath (gf_store_handle_t *shandle) +{ +        int32_t         ret = -1; +        char            tmppath[PATH_MAX] = {0,}; + +        GF_ASSERT (shandle); +        GF_ASSERT (shandle->path); + +        snprintf (tmppath, sizeof (tmppath), "%s.tmp", shandle->path); +        ret = rename (tmppath, shandle->path); +        if (ret) { +                gf_log (THIS->name, GF_LOG_ERROR, "Failed to rename %s to %s, " +                        "error: %s", tmppath, shandle->path, strerror (errno)); +                goto out; +        } + +        ret = gf_store_sync_direntry (tmppath); +out: +        return ret; +} + +int32_t +gf_store_unlink_tmppath (gf_store_handle_t *shandle) +{ +        int32_t         ret = -1; +        char            tmppath[PATH_MAX] = {0,}; + +        GF_ASSERT (shandle); +        GF_ASSERT (shandle->path); + +        snprintf (tmppath, sizeof (tmppath), "%s.tmp", shandle->path); +        ret = unlink (tmppath); +        if (ret && (errno != ENOENT)) { +                gf_log ("", GF_LOG_ERROR, "Failed to mv %s to %s, error: %s", +                        tmppath, shandle->path, strerror (errno)); +        } else { +                ret = 0; +        } + +        return ret; +} + +int +gf_store_read_and_tokenize (FILE *file, char *str, char **iter_key, +                            char **iter_val, gf_store_op_errno_t *store_errno) +{ +        int32_t  ret = -1; +        char *savetok = NULL; + +        GF_ASSERT (file); +        GF_ASSERT (str); +        GF_ASSERT (iter_key); +        GF_ASSERT (iter_val); +        GF_ASSERT (store_errno); + +        ret = fscanf (file, "%s", str); +        if (ret <= 0 || feof (file)) { +                ret = -1; +                *store_errno = GD_STORE_EOF; +                goto out; +        } + +        *iter_key = strtok_r (str, "=", &savetok); +        if (*iter_key == NULL) { +                ret = -1; +                *store_errno = GD_STORE_KEY_NULL; +                goto out; +        } + +        *iter_val = strtok_r (NULL, "=", &savetok); +        if (*iter_key == NULL) { +                ret = -1; +                *store_errno = GD_STORE_VALUE_NULL; +                goto out; +        } + +        *store_errno = GD_STORE_SUCCESS; +        ret = 0; +out: +        return ret; +} + +int32_t +gf_store_retrieve_value (gf_store_handle_t *handle, char *key, char **value) +{ +        int32_t         ret = -1; +        char            *scan_str = NULL; +        char            *iter_key = NULL; +        char            *iter_val = NULL; +        char            *free_str = NULL; +        struct stat     st        = {0,}; +        gf_store_op_errno_t store_errno = GD_STORE_SUCCESS; + +        GF_ASSERT (handle); + +        handle->fd = open (handle->path, O_RDWR); + +        if (handle->fd == -1) { +                gf_log ("", GF_LOG_ERROR, "Unable to open file %s errno: %s", +                        handle->path, strerror (errno)); +                goto out; +        } +        if (!handle->read) +                handle->read = fdopen (handle->fd, "r"); + +        if (!handle->read) { +                gf_log ("", GF_LOG_ERROR, "Unable to open file %s errno: %s", +                        handle->path, strerror (errno)); +                goto out; +        } + +        ret = fstat (handle->fd, &st); +        if (ret < 0) { +                gf_log ("", GF_LOG_WARNING, "stat on file %s failed", +                        handle->path); +                ret = -1; +                store_errno = GD_STORE_STAT_FAILED; +                goto out; +        } + +        scan_str = GF_CALLOC (1, st.st_size, +                              gf_common_mt_char); +        if (scan_str == NULL) { +                ret = -1; +                store_errno = GD_STORE_ENOMEM; +                goto out; +        } + +        free_str = scan_str; + +        do { +                ret = gf_store_read_and_tokenize (handle->read, scan_str, +                                                  &iter_key, &iter_val, +                                                  &store_errno); +                if (ret < 0) { +                        gf_log ("", GF_LOG_TRACE, "error while reading key " +                                "'%s': %s", key, +                                gf_store_strerror (store_errno)); +                        goto out; +                } + +                gf_log ("", GF_LOG_TRACE, "key %s read", iter_key); + +                if (!strcmp (key, iter_key)) { +                        gf_log ("", GF_LOG_DEBUG, "key %s found", key); +                        ret = 0; +                        if (iter_val) +                                *value = gf_strdup (iter_val); +                        goto out; +                } +        } while (1); +out: +        if (handle->fd > 0) { +                close (handle->fd); +                handle->read = NULL; +        } + +        GF_FREE (free_str); + +        return ret; +} + +int32_t +gf_store_save_value (int fd, char *key, char *value) +{ +        int32_t         ret = -1; +        FILE           *fp  = NULL; + +        GF_ASSERT (fd > 0); +        GF_ASSERT (key); +        GF_ASSERT (value); + +        fp = fdopen (fd, "a+"); +        if (fp == NULL) { +                gf_log ("", GF_LOG_WARNING, "fdopen failed."); +                ret = -1; +                goto out; +        } + +        ret = fprintf (fp, "%s=%s\n", key, value); +        if (ret < 0) { +                gf_log ("", GF_LOG_WARNING, "Unable to store key: %s," +                        "value: %s, error: %s", key, value, +                        strerror (errno)); +                ret = -1; +                goto out; +        } + +        ret = fflush (fp); +        if (feof (fp)) { +                gf_log ("", GF_LOG_WARNING, +                        "fflush failed, error: %s", +                        strerror (errno)); +                ret = -1; +                goto out; +        } + +        ret = 0; +out: + +        gf_log ("", GF_LOG_DEBUG, "returning: %d", ret); +        return ret; +} + +int32_t +gf_store_handle_new (char *path, gf_store_handle_t **handle) +{ +        int32_t                 ret = -1; +        gf_store_handle_t *shandle = NULL; +        int                     fd = -1; +        char                    *spath = NULL; + +        shandle = GF_CALLOC (1, sizeof (*shandle), gf_common_mt_store_handle_t); +        if (!shandle) +                goto out; + +        spath = gf_strdup (path); + +        if (!spath) +                goto out; + +        fd = open (path, O_RDWR | O_CREAT | O_APPEND, 0600); +        if (fd <= 0) { +                gf_log ("", GF_LOG_ERROR, "Failed to open file: %s, error: %s", +                        path, strerror (errno)); +                goto out; +        } + +        ret = gf_store_sync_direntry (spath); +        if (ret) +                goto out; + +        shandle->path = spath; +        *handle = shandle; + +        ret = 0; +out: +        if (fd > 0) +                close (fd); + +        if (ret == -1) { +                GF_FREE (spath); +                GF_FREE (shandle); +        } + +        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); +        return ret; +} + +int +gf_store_handle_retrieve (char *path, gf_store_handle_t **handle) +{ +        int32_t                 ret = -1; +        struct stat statbuf = {0}; + +        ret = stat (path, &statbuf); +        if (ret) { +                gf_log ("", GF_LOG_ERROR, "Unable to retrieve store handle " +                        "%s, error: %s", path, strerror (errno)); +                goto out; +        } +        ret =  gf_store_handle_new (path, handle); +out: +        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); +        return ret; +} + +int32_t +gf_store_handle_destroy (gf_store_handle_t *handle) +{ +        int32_t                 ret = -1; + +        if (!handle) { +                ret = 0; +                goto out; +        } + +        GF_FREE (handle->path); + +        GF_FREE (handle); + +        ret = 0; + +out: +        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + +        return ret; +} + +int32_t +gf_store_iter_new (gf_store_handle_t  *shandle, gf_store_iter_t  **iter) +{ +        int32_t                 ret = -1; +        gf_store_iter_t        *tmp_iter = NULL; +        int                     fd = -1; + +        GF_ASSERT (shandle); +        GF_ASSERT (iter); + +        tmp_iter = GF_CALLOC (1, sizeof (*tmp_iter), +                             gf_common_mt_store_iter_t); + +        if (!tmp_iter) { +                gf_log ("", GF_LOG_ERROR, "Out of Memory"); +                goto out; +        } + +        fd = open (shandle->path, O_RDWR); + +        if (fd < 0) { +                gf_log ("", GF_LOG_ERROR, "Unable to open %s, errno: %d", +                        shandle->path, errno); +                goto out; +        } + +        tmp_iter->fd = fd; + +        tmp_iter->file = fdopen (tmp_iter->fd, "r"); + +        if (!tmp_iter->file) { +                gf_log ("", GF_LOG_ERROR, "Unable to open file %s errno: %d", +                        shandle->path, errno); +                goto out; +        } + +        strncpy (tmp_iter->filepath, shandle->path, sizeof (tmp_iter->filepath)); +        tmp_iter->filepath[sizeof (tmp_iter->filepath) - 1] = 0; +        *iter = tmp_iter; +        ret = 0; + +out: +        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); +        return ret; +} + +int32_t +gf_store_validate_key_value (char *storepath, char *key, char *val, +                             gf_store_op_errno_t *op_errno) +{ +        int ret = 0; + +        GF_ASSERT (op_errno); +        GF_ASSERT (storepath); + +        if ((key == NULL) && (val == NULL)) { +                ret = -1; +                gf_log ("", GF_LOG_ERROR, "Glusterd store may be corrupted, " +                        "Invalid key and value (null) in %s", storepath); +                *op_errno = GD_STORE_KEY_VALUE_NULL; +        } else if (key == NULL) { +                ret = -1; +                gf_log ("", GF_LOG_ERROR, "Glusterd store may be corrupted, " +                        "Invalid key (null) in %s", storepath); +                *op_errno = GD_STORE_KEY_NULL; +        } else if (val == NULL) { +                ret = -1; +                gf_log ("", GF_LOG_ERROR, "Glusterd store may be corrupted, " +                        "Invalid value (null) for key %s in %s", key, +                        storepath); +                *op_errno = GD_STORE_VALUE_NULL; +        } else { +                ret = 0; +                *op_errno = GD_STORE_SUCCESS; +        } + +        return ret; +} + +int32_t +gf_store_iter_get_next (gf_store_iter_t *iter, char  **key, char **value, +                        gf_store_op_errno_t *op_errno) +{ +        int32_t         ret = -1; +        char            *scan_str = NULL; +        char            *free_str = NULL; +        char            *iter_key = NULL; +        char            *iter_val = NULL; +        struct stat     st        = {0,}; +        gf_store_op_errno_t store_errno = GD_STORE_SUCCESS; + +        GF_ASSERT (iter); +        GF_ASSERT (iter->file); +        GF_ASSERT (key); +        GF_ASSERT (value); + +        ret = fstat (iter->fd, &st); +        if (ret < 0) { +                gf_log ("", GF_LOG_WARNING, "stat on file failed"); +                ret = -1; +                store_errno = GD_STORE_STAT_FAILED; +                goto out; +        } + +        scan_str = GF_CALLOC (1, st.st_size, +                              gf_common_mt_char); +        if (scan_str == NULL) { +                ret = -1; +                store_errno = GD_STORE_ENOMEM; +                goto out; +        } + +        *key = NULL; +        *value = NULL; + +        free_str = scan_str; + +        ret = gf_store_read_and_tokenize (iter->file, scan_str, +                                          &iter_key, &iter_val, +                                          &store_errno); +        if (ret < 0) { +                goto out; +        } + + +        ret = gf_store_validate_key_value (iter->filepath, iter_key, +                                           iter_val, &store_errno); +        if (ret) +                goto out; + +        *value = gf_strdup (iter_val); + +        *key   = gf_strdup (iter_key); +        if (!iter_key || !iter_val) { +                ret = -1; +                store_errno = GD_STORE_ENOMEM; +                goto out; +        } + +        ret = 0; + +out: +        if (ret) { +                if (*key) { +                        GF_FREE (*key); +                        *key = NULL; +                } +                if (*value) { +                        GF_FREE (*value); +                        *value = NULL; +                } +        } +        GF_FREE (free_str); +        if (op_errno) +                *op_errno = store_errno; + +        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); +        return ret; +} + +int32_t +gf_store_iter_get_matching (gf_store_iter_t *iter, char *key, char **value) +{ +        int32_t ret = -1; +        char    *tmp_key = NULL; +        char    *tmp_value = NULL; + +        ret = gf_store_iter_get_next (iter, &tmp_key, &tmp_value, NULL); +        while (!ret) { +                if (!strncmp (key, tmp_key, strlen (key))){ +                        *value = tmp_value; +                        GF_FREE (tmp_key); +                        goto out; +                } +                GF_FREE (tmp_key); +                GF_FREE (tmp_value); +                ret = gf_store_iter_get_next (iter, &tmp_key, &tmp_value, +                                              NULL); +        } +out: +        return ret; +} + +int32_t +gf_store_iter_destroy (gf_store_iter_t *iter) +{ +        int32_t         ret = -1; + +        if (!iter) +                return 0; + +        if (iter->file) +                ret = fclose (iter->file); +        else +                ret = 0; + +        if (ret) { +                gf_log ("", GF_LOG_ERROR, "Unable to close fd: %d, ret: %d, " +                        "errno: %d" ,iter->fd, ret, errno); +        } + +        GF_FREE (iter); + +        return ret; +} + +char* +gf_store_strerror (gf_store_op_errno_t op_errno) +{ +        switch (op_errno) { +        case GD_STORE_SUCCESS: +                return "Success"; +        case GD_STORE_KEY_NULL: +                return "Invalid Key"; +        case GD_STORE_VALUE_NULL: +                return "Invalid Value"; +        case GD_STORE_KEY_VALUE_NULL: +                return "Invalid Key and Value"; +        case GD_STORE_EOF: +                return "No data"; +        case GD_STORE_ENOMEM: +                return "No memory"; +        default: +                return "Invalid errno"; +        } +        return "Invalid errno"; +} diff --git a/libglusterfs/src/store.h b/libglusterfs/src/store.h new file mode 100644 index 00000000000..8138b4cd9bd --- /dev/null +++ b/libglusterfs/src/store.h @@ -0,0 +1,103 @@ +/* +   Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com> +   This file is part of GlusterFS. + +   This file is licensed to you under your choice of the GNU Lesser +   General Public License, version 3 or any later version (LGPLv3 or +   later), or the GNU General Public License, version 2 (GPLv2), in all +   cases as published by the Free Software Foundation. +*/ +#ifndef _GLUSTERD_STORE_H_ +#define _GLUSTERD_STORE_H_ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "glusterfs.h" + +struct gf_store_handle_ { +        char    *path; +        int     fd; +        FILE    *read; +}; + +typedef struct gf_store_handle_ gf_store_handle_t; + +struct gf_store_iter_ { +        int     fd; +        FILE    *file; +        char    filepath[PATH_MAX]; +}; + +typedef struct gf_store_iter_ gf_store_iter_t; + +typedef enum { +        GD_STORE_SUCCESS, +        GD_STORE_KEY_NULL, +        GD_STORE_VALUE_NULL, +        GD_STORE_KEY_VALUE_NULL, +        GD_STORE_EOF, +        GD_STORE_ENOMEM, +        GD_STORE_STAT_FAILED +} gf_store_op_errno_t; + +int32_t +gf_store_mkdir (char *path); + +int32_t +gf_store_handle_create_on_absence (gf_store_handle_t **shandle, char *path); + +int32_t +gf_store_mkstemp (gf_store_handle_t *shandle); + +int +gf_store_sync_direntry (char *path); + +int32_t +gf_store_rename_tmppath (gf_store_handle_t *shandle); + +int32_t +gf_store_unlink_tmppath (gf_store_handle_t *shandle); + +int +gf_store_read_and_tokenize (FILE *file, char *str, char **iter_key, +                            char **iter_val, gf_store_op_errno_t *store_errno); + +int32_t +gf_store_retrieve_value (gf_store_handle_t *handle, char *key, char **value); + +int32_t +gf_store_save_value (int fd, char *key, char *value); + +int32_t +gf_store_handle_new (char *path, gf_store_handle_t **handle); + +int +gf_store_handle_retrieve (char *path, gf_store_handle_t **handle); + +int32_t +gf_store_handle_destroy (gf_store_handle_t *handle); + +int32_t +gf_store_iter_new (gf_store_handle_t  *shandle, gf_store_iter_t  **iter); + +int32_t +gf_store_validate_key_value (char *storepath, char *key, char *val, +                             gf_store_op_errno_t *op_errno); + +int32_t +gf_store_iter_get_next (gf_store_iter_t *iter, char **key, char **value, +                        gf_store_op_errno_t *op_errno); + +int32_t +gf_store_iter_get_matching (gf_store_iter_t *iter, char *key, char **value); + +int32_t +gf_store_iter_destroy (gf_store_iter_t *iter); + +char* +gf_store_strerror (gf_store_op_errno_t op_errno); + +#endif  | 
