<commit_before>/*
  Copyright (c) 2007-2010 Gluster, Inc. <http://www.gluster.com>
  This file is part of GlusterFS.

  GlusterFS is free software; you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published
  by the Free Software Foundation; either version 3 of the License,
  or (at your option) any later version.

  GlusterFS is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see
  <http://www.gnu.org/licenses/>.
*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include <inttypes.h>


#include "globals.h"
#include "glusterfs.h"
#include "compat.h"
#include "dict.h"
#include "protocol-common.h"
#include "xlator.h"
#include "logging.h"
#include "timer.h"
#include "defaults.h"
#include "compat.h"
#include "compat-errno.h"
#include "statedump.h"
#include "glusterd-mem-types.h"
#include "glusterd.h"
#include "glusterd-sm.h"
#include "glusterd-op-sm.h"
#include "glusterd-utils.h"
#include "glusterd-store.h"

#include "glusterd1.h"
#include "cli1.h"
#include "rpc-clnt.h"

#include <sys/resource.h>
#include <inttypes.h>
#include <dirent.h>

static int32_t
glusterd_store_create_volume_dir (char *volname)
{
        int32_t                 ret = -1;
        char                    path[PATH_MAX] = {0,};
        glusterd_conf_t         *priv = NULL;

        GF_ASSERT (volname);
        priv = THIS->private;

        GF_ASSERT (priv);

        snprintf (path, 1024, "%s/vols/%s", priv->workdir,
                  volname);

        ret = mkdir (path, 0777);

        if (-1 == ret) {
                gf_log ("", GF_LOG_ERROR, "mkdir() failed on path %s,"
                        "errno: %d", path, errno);
                goto out;
        }

out:
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);
        return ret;
}

int32_t
glusterd_store_create_brick (glusterd_volinfo_t *volinfo,
                             glusterd_brickinfo_t *brickinfo)
{
        int32_t                 ret = -1;
        glusterd_conf_t         *priv = NULL;
        char                    path[PATH_MAX] = {0,};
        char                    brickpath[PATH_MAX] = {0,};
        struct  stat            stbuf = {0,};
        char                    buf[4096] = {0,};
        char                    *tmppath = NULL;
        char                    *ptr = NULL;
        glusterd_store_handle_t *shandle = NULL;

        GF_ASSERT (volinfo);
        GF_ASSERT (brickinfo);

        priv = THIS->private;

        GF_ASSERT (priv);

        GLUSTERD_GET_BRICK_DIR (path, volinfo, priv);

        ret = stat (path, &stbuf);

        if (ret == -1 && ENOENT == errno) {
                ret = mkdir (path, 0777);
                if (ret)
                        goto out;
        }

        tmppath = gf_strdup (brickinfo->path);

        ptr = strchr (tmppath, '/');

        while (ptr) {
                *ptr = '-';
                ptr = strchr (tmppath, '/');
        }

        snprintf (brickpath, sizeof (brickpath), "%s/%s:%s",
                  path, brickinfo->hostname, tmppath);

        GF_FREE (tmppath);
        ret = glusterd_store_handle_new (brickpath, &brickinfo->shandle);

        if (ret)
                goto out;

        shandle = brickinfo->shandle;
        shandle->fd = open (brickpath, O_RDWR | O_CREAT | O_APPEND, 0666);

        if (shandle->fd < 0) {
                gf_log ("", GF_LOG_ERROR, "Open failed on %s",
                        brickpath);
                ret = -1;
                goto out;
        }


        snprintf (buf, sizeof(buf), "%s=%s\n",
                  GLUSTERD_STORE_KEY_BRICK_HOSTNAME, brickinfo->hostname);
        ret = write (shandle->fd, buf, strlen(buf));
        if (ret)
                gf_log ("", GF_LOG_TRACE, "failed to write brick->hostname");
        snprintf (buf, sizeof(buf), "%s=%s\n",
                  GLUSTERD_STORE_KEY_BRICK_PATH, brickinfo->path);
        ret = write (shandle->fd, buf, strlen(buf));
        if (ret)
                gf_log ("", GF_LOG_TRACE, "failed to write brick->path");
        snprintf (buf, sizeof(buf), "%s=%d\n",
                  GLUSTERD_STORE_KEY_BRICK_PORT, brickinfo->port);
        ret = write (shandle->fd, buf, strlen(buf));
        if (ret)
                gf_log ("", GF_LOG_TRACE, "failed to write brick->port");

        ret = 0;

out:
        if (shandle->fd > 0) {
                close (shandle->fd);
        }
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);
        return ret;
}

int32_t
glusterd_store_delete_brick (glusterd_volinfo_t *volinfo,
                             glusterd_brickinfo_t *brickinfo)
{
        int32_t                 ret = -1;
        glusterd_conf_t         *priv = NULL;
        char                    path[PATH_MAX] = {0,};
        char                    brickpath[PATH_MAX] = {0,};
        char                    *ptr = NULL;
        char                    *tmppath = NULL;

        GF_ASSERT (volinfo);
        GF_ASSERT (brickinfo);

        priv = THIS->private;

        GF_ASSERT (priv);

        GLUSTERD_GET_BRICK_DIR (path, volinfo, priv);

        tmppath = gf_strdup (brickinfo->path);

        ptr = strchr (tmppath, '/');

        while (ptr) {
                *ptr = '-';
                ptr = strchr (tmppath, '/');
        }

        snprintf (brickpath, sizeof (brickpath), "%s/%s:%s",
                  path, brickinfo->hostname, tmppath);

        GF_FREE (tmppath);

        ret = unlink (brickpath);

        if (ret < 0) {
                gf_log ("", GF_LOG_ERROR, "Unlink failed on %s",
                        brickpath);
                ret = -1;
                goto out;
        }

out:
        if (brickinfo->shandle)
                glusterd_store_handle_destroy (brickinfo->shandle);
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);
        return ret;
}

int32_t
glusterd_store_remove_bricks (glusterd_volinfo_t *volinfo)
{
        int32_t                 ret = 0;
        glusterd_brickinfo_t    *tmp = NULL;
        glusterd_conf_t         *priv = NULL;
        char                    brickdir [PATH_MAX] = {0,};
        DIR                     *dir = NULL;
        struct dirent           *entry = NULL;
        char                    path[PATH_MAX] = {0,};

        GF_ASSERT (volinfo);

        list_for_each_entry (tmp, &volinfo->bricks, brick_list) {
                ret = glusterd_store_delete_brick (volinfo, tmp);
                if (ret)
                        goto out;
        }

        priv = THIS->private;
        GF_ASSERT (priv);

        GLUSTERD_GET_BRICK_DIR (brickdir, volinfo, priv);

        dir = opendir (brickdir);

        glusterd_for_each_entry (entry, dir);

        while (entry) {
                snprintf (path, sizeof (path), "%s/%s",
                          brickdir, entry->d_name);
                ret = unlink (path);
                if (ret) {
                        gf_log ("", GF_LOG_ERROR, "Unable to unlink %s",
                                path);
                }
                glusterd_for_each_entry (entry, dir);
        }

        closedir (dir);

        ret = rmdir (brickdir);

out:
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);
        return ret;
}

int32_t
glusterd_store_create_volume (glusterd_volinfo_t *volinfo)
{
        int32_t                 ret = -1;
        char                    filepath[PATH_MAX] = {0,};
        char                    buf[4096] = {0,};
        glusterd_conf_t         *priv = NULL;
        glusterd_brickinfo_t    *brickinfo = NULL;

        GF_ASSERT (volinfo);
        priv = THIS->private;

        GF_ASSERT (priv);

        ret = glusterd_store_create_volume_dir (volinfo->volname);

        if (ret)
                goto out;

        snprintf (filepath, 1024, "%s/%s/%s/%s", priv->workdir,
                  GLUSTERD_VOLUME_DIR_PREFIX, volinfo->volname,
                  GLUSTERD_VOLUME_INFO_FILE);

        ret = glusterd_store_handle_new (filepath, &volinfo->shandle);

        if (ret) {
                gf_log ("", GF_LOG_ERROR, "Unable to create store"
                        " handle for path: %s", filepath);
                goto out;
        }

        snprintf (buf, sizeof (buf), "%d", volinfo->type);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_TYPE, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->brick_count);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_COUNT, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->status);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_STATUS, buf);
        if (ret)
                goto out;

/*        snprintf (buf, sizeof (buf), "%d", volinfo->port);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_PORT, buf);
        if (ret)
                goto out;
*/
        snprintf (buf, sizeof (buf), "%d", volinfo->sub_count);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_SUB_COUNT, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->version);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_VERSION, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->transport_type);
        ret = glusterd_store_save_value (volinfo->shandle,
                                         GLUSTERD_STORE_KEY_VOL_TRANSPORT, buf);
        if (ret)
                goto out;

        uuid_unparse (volinfo->volume_id, buf);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_ID, buf);
        if (ret)
                goto out;

        list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) {
                ret = glusterd_store_create_brick (volinfo, brickinfo);
                if (ret)
                        goto out;
        }

        ret = 0;

out:
        if (ret) {
                glusterd_store_delete_volume (volinfo);
        }

        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);

        return ret;
}


int32_t
glusterd_store_delete_volume (glusterd_volinfo_t *volinfo)
{
        char    pathname[PATH_MAX] = {0,};
        int32_t ret = 0;
        glusterd_conf_t *priv = NULL;
        DIR     *dir = NULL;
        struct dirent *entry = NULL;
        char path[PATH_MAX] = {0,};
        struct stat     st = {0, };

        GF_ASSERT (volinfo);
        priv = THIS->private;

        GF_ASSERT (priv);
        snprintf (pathname, 1024, "%s/vols/%s", priv->workdir,
                  volinfo->volname);

        dir = opendir (pathname);
        if (!dir)
                goto out;
        ret = glusterd_store_remove_bricks (volinfo);

        if (ret) {
                gf_log ("", GF_LOG_ERROR, "Remove bricks failed");
        }

        glusterd_for_each_entry (entry, dir);
        while (entry) {

                snprintf (path, PATH_MAX, "%s/%s", pathname, entry->d_name);
                ret = stat (path, &st);
                if (ret == -1) {
                        gf_log ("", GF_LOG_ERROR, "Failed to stat entry: %s:%s",
                                path, strerror (errno));
                        goto stat_failed;
                }

                if (S_ISDIR (st.st_mode))
                        ret = rmdir (path);
                else
                        ret = unlink (path);

                gf_log ("", GF_LOG_NORMAL, "%s %s",
                                ret?"Failed to remove":"Removed",
                                entry->d_name);
                if (ret)
                        gf_log ("", GF_LOG_NORMAL, "errno:%d", errno);
stat_failed:
                memset (path, 0, sizeof(path));
                glusterd_for_each_entry (entry, dir);
        }

        ret = closedir (dir);
        if (ret) {
                gf_log ("", GF_LOG_NORMAL, "Failed to close dir, errno:%d",
                        errno);
        }

        ret = rmdir (pathname);
        if (ret) {
                gf_log ("", GF_LOG_ERROR, "Failed to rmdir: %s, errno: %d",
                        pathname, errno);
        }


out:
        if (volinfo->shandle)
                glusterd_store_handle_destroy (volinfo->shandle);
        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);

        return ret;
}



int32_t
glusterd_store_retrieve_value (glusterd_store_handle_t *handle,
                               char *key, char **value)
{
        int32_t         ret = -1;
        char            scan_str[4096] = {0,};
        char            *iter_key = NULL;
        char            *iter_val = NULL;
        char            *str = NULL;
        char            *free_str = NULL;

        GF_ASSERT (handle);

        handle->fd = open (handle->path, O_RDWR);

        if (!handle->read)
                handle->read = fdopen (handle->fd, "r");

        if (!handle->read) {
                gf_log ("", GF_LOG_ERROR, "Unable to open file %s errno: %d",
                        handle->path, errno);
                goto out;
        }

        ret = fscanf (handle->read, "%s", scan_str);

        while (ret != EOF) {
                if (free_str) {
                        GF_FREE (free_str);
                        free_str = NULL;
                }
                str = gf_strdup (scan_str);
                if (!str)
                        goto out;
                else
                        free_str = str;
                iter_key = strtok (str, "=");
                gf_log ("", GF_LOG_DEBUG, "key %s read", iter_key);

                if (!strcmp (key, iter_key)) {
                        gf_log ("", GF_LOG_DEBUG, "key %s found", key);
                        iter_val = strtok (NULL, "=");
                        ret = 0;
                        if (iter_val)
                                *value = gf_strdup (iter_val);
                        goto out;
                }

                ret = fscanf (handle->read, "%s", scan_str);
        }

        if (EOF == ret)
                ret = -1;
out:
        if (handle->fd > 0) {
                close (handle->fd);
                handle->read = NULL;
        }

        if (free_str)
                GF_FREE (free_str);

        return ret;
}

int32_t
glusterd_store_save_value (glusterd_store_handle_t *handle,
                           char *key, char *value)
{
        int32_t         ret = -1;
        char            buf[4096] = {0,};

        GF_ASSERT (handle);
        GF_ASSERT (key);
        GF_ASSERT (value);

        handle->fd = open (handle->path, O_RDWR | O_APPEND);

        if (handle->fd < 0) {
                gf_log ("", GF_LOG_ERROR, "Unable to open %s, errno: %d",
                        handle->path, errno);
                goto out;
        }

        snprintf (buf, sizeof (buf), "%s=%s\n", key, value);
        ret = write (handle->fd, buf, strlen (buf));

        if (ret < 0) {
                gf_log ("", GF_LOG_CRITICAL, "Unable to store key: %s,"
                        "value: %s, error: %s", key, value,
                        strerror (errno));
                ret = -1;
                goto out;
        }

        ret = 0;

out:

        if (handle->fd > 0) {
                close (handle->fd);
                handle->fd = -1;
        }

        gf_log ("", GF_LOG_DEBUG, "returning: %d", ret);
        return ret;
}

int32_t
glusterd_store_handle_new (char *path, glusterd_store_handle_t **handle)
{
        int32_t                 ret = -1;
        glusterd_store_handle_t *shandle = NULL;

        shandle = GF_CALLOC (1, sizeof (*shandle), gf_gld_mt_store_handle_t);
        if (!shandle)
                goto out;

        shandle->path = gf_strdup (path);

        if (!shandle->path)
                goto out;

        shandle->fd = open (path, O_RDWR | O_CREAT | O_APPEND, 0644);
        if (!shandle->fd)
                goto out;

        *handle = shandle;

        ret = 0;

out:
        if (ret == -1) {
                if (shandle) {
                        if (shandle->path)
                                GF_FREE (shandle->path);
                        if (shandle->fd > 0)
                                close (shandle->fd);
                        GF_FREE (shandle);
                }
        } else {
                close (shandle->fd);
        }

        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);

        return ret;
}

int32_t
glusterd_store_handle_destroy (glusterd_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
glusterd_store_handle_truncate (glusterd_store_handle_t *handle)
{
        int32_t         ret = -1;

        GF_ASSERT (handle);
        GF_ASSERT (handle->path);

        ret = truncate (handle->path, 0);

        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);

        return ret;
}

int32_t
glusterd_store_uuid ()
{
        char            str[GLUSTERD_UUID_LEN] = {0,};
        glusterd_conf_t *priv = NULL;
        char            path[PATH_MAX] = {0,};
        int32_t         ret = -1;
        glusterd_store_handle_t *handle = NULL;

        priv = THIS->private;

        uuid_unparse (priv->uuid, str);

        snprintf (path, PATH_MAX, "%s/%s", priv->workdir,
                  GLUSTERD_INFO_FILE);

        if (!priv->handle) {
                ret = glusterd_store_handle_new (path, &handle);

                if (ret) {
                        gf_log ("", GF_LOG_ERROR, "Unable to get store"
                                " handle!");
                        goto out;
                }

                priv->handle = handle;
        }

        ret = glusterd_store_save_value (priv->handle, GLUSTERD_STORE_UUID_KEY,
                                         str);

        if (ret) {
                gf_log ("", GF_LOG_CRITICAL, "Storing uuid failed"
                        "ret = %d", ret);
                goto out;
        }


out:
        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
        return ret;
}


int32_t
glusterd_retrieve_uuid ()
{
        char            *uuid_str = NULL;
        int32_t         ret = -1;
        glusterd_store_handle_t *handle = NULL;
        glusterd_conf_t *priv = NULL;
        char            path[PATH_MAX] = {0,};

        priv = THIS->private;


        if (!priv->handle) {
                snprintf (path, PATH_MAX, "%s/%s", priv->workdir,
                          GLUSTERD_INFO_FILE);
                ret = glusterd_store_handle_new (path, &handle);

                if (ret) {
                        gf_log ("", GF_LOG_ERROR, "Unable to get store "
                                "handle!");
                        goto out;
                }

                priv->handle = handle;
        }

        ret = glusterd_store_retrieve_value (priv->handle,
                                             GLUSTERD_STORE_UUID_KEY,
                                             &uuid_str);

        if (ret) {
                gf_log ("", GF_LOG_CRITICAL, "Retrieving uuid failed"
                        " ret = %d", ret);
                goto out;
        }

        uuid_parse (uuid_str, priv->uuid);

out:
        if (uuid_str)
                GF_FREE (uuid_str);
        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
        return ret;
}

int32_t
glusterd_store_iter_new (glusterd_store_handle_t  *shandle,
                         glusterd_store_iter_t  **iter)
{
        int32_t                 ret = -1;
        glusterd_store_iter_t   *tmp_iter = NULL;
        int                     fd = -1;

        GF_ASSERT (shandle);
        GF_ASSERT (iter);

        tmp_iter = GF_CALLOC (1, sizeof (*tmp_iter),
                             gf_gld_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 (shandle->fd, "r");

        if (!tmp_iter->file) {
                gf_log ("", GF_LOG_ERROR, "Unable to open file %s errno: %d",
                        shandle->path, errno);
                goto out;
        }

        *iter = tmp_iter;
        ret = 0;

out:
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);
        return ret;
}

int32_t
glusterd_store_iter_get_next (glusterd_store_iter_t *iter,
                              char  **key, char **value)
{
        int32_t         ret = -1;
        char            scan_str[4096] = {0,};
        char            *str = NULL;
        char            *free_str = NULL;
        char            *iter_key = NULL;
        char            *iter_val = NULL;

        GF_ASSERT (iter);
        GF_ASSERT (iter->file);

        ret = fscanf (iter->file, "%s", scan_str);

        if (ret <= 0) {
                ret = -1;
                goto out;
        }

        str = gf_strdup (scan_str);
        if (!str)
                goto out;
        else
                free_str = str;

        iter_key = strtok (str, "=");
        gf_log ("", GF_LOG_DEBUG, "key %s read", iter_key);


        iter_val = strtok (NULL, "=");
        gf_log ("", GF_LOG_DEBUG, "value %s read", iter_val);

        if (iter_val)
                *value = gf_strdup (iter_val);
        *key   = gf_strdup (iter_key);

        ret = 0;

out:
        if (free_str)
                GF_FREE (free_str);

        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);
        return ret;
}

int32_t
glusterd_store_iter_destroy (glusterd_store_iter_t *iter)
{
        int32_t         ret = -1;

        GF_ASSERT (iter);
        GF_ASSERT (iter->fd > 0);

        ret = fclose (iter->file);

        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;
}

int32_t
glusterd_store_retrieve_bricks (glusterd_volinfo_t *volinfo)
{

        int32_t                 ret = 0;
        glusterd_brickinfo_t    *brickinfo = NULL;
        glusterd_store_iter_t   *iter = NULL;
        char                    *key = NULL;
        char                    *value = NULL;
        char                    brickdir[PATH_MAX] = {0,};
        char                    path[PATH_MAX] = {0,};
        glusterd_conf_t         *priv = NULL;
        DIR                     *dir = NULL;
        struct dirent           *entry = NULL;

        GF_ASSERT (volinfo);
        GF_ASSERT (volinfo->volname);

        priv = THIS->private;

        GLUSTERD_GET_BRICK_DIR (brickdir, volinfo, priv);

        dir = opendir (brickdir);

        glusterd_for_each_entry (entry, dir);

        while (entry) {
                ret = glusterd_brickinfo_new (&brickinfo);

                if (ret)
                        goto out;

                snprintf (path, sizeof (path), "%s/%s", brickdir,
                          entry->d_name);

                ret = glusterd_store_handle_new (path, &brickinfo->shandle);

                if (ret)
                        goto out;

                ret = glusterd_store_iter_new (brickinfo->shandle, &iter);

                if (ret)
                        goto out;

                ret = glusterd_store_iter_get_next (iter, &key, &value);

                while (!ret) {
                        if (!strncmp (key, GLUSTERD_STORE_KEY_BRICK_HOSTNAME,
                                      strlen (GLUSTERD_STORE_KEY_BRICK_HOSTNAME))) {
                                strncpy (brickinfo->hostname, value, 1024);
                        } else if (!strncmp (key, GLUSTERD_STORE_KEY_BRICK_PATH,
                                    strlen (GLUSTERD_STORE_KEY_BRICK_PATH))) {
                                strncpy (brickinfo->path, value,
                                         sizeof (brickinfo->path));
                        } else if (!strncmp (key, GLUSTERD_STORE_KEY_BRICK_PORT,
                                    strlen (GLUSTERD_STORE_KEY_BRICK_PORT))) {
                                gf_string2int (value, &brickinfo->port);
                        } else {
                                gf_log ("", GF_LOG_ERROR, "Unknown key: %s",
                                        key);
                        }

                        GF_FREE (key);
                        GF_FREE (value);
                        key = NULL;
                        value = NULL;

                        ret = glusterd_store_iter_get_next (iter, &key, &value);
                }

                ret = glusterd_store_iter_destroy (iter);

                if (ret)
                        goto out;

                list_add_tail (&brickinfo->brick_list, &volinfo->bricks);
                glusterd_for_each_entry (entry, dir);
        }

out:
        if (dir)
                closedir (dir);
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);

        return ret;
}


int32_t
glusterd_store_retrieve_volume (char    *volname)
{
        int32_t                 ret = -1;
        glusterd_volinfo_t      *volinfo = NULL;
        glusterd_store_iter_t   *iter = NULL;
        char                    *key = NULL;
        char                    *value = NULL;
        char                    volpath[PATH_MAX] = {0,};
        glusterd_conf_t         *priv = NULL;
        char                    path[PATH_MAX] = {0,};

        ret = glusterd_volinfo_new (&volinfo);

        if (ret)
                goto out;

        strncpy (volinfo->volname, volname, GLUSTERD_MAX_VOLUME_NAME);

        priv = THIS->private;

        GLUSTERD_GET_VOLUME_DIR(volpath, volinfo, priv);
        snprintf (path, sizeof (path), "%s/%s", volpath,
                  GLUSTERD_VOLUME_INFO_FILE);

        ret = glusterd_store_handle_new (path, &volinfo->shandle);

        if (ret)
                goto out;

        ret = glusterd_store_iter_new (volinfo->shandle, &iter);

        if (ret)
                goto out;

        ret = glusterd_store_iter_get_next (iter, &key, &value);

        while (!ret) {
                if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_TYPE,
                              strlen (GLUSTERD_STORE_KEY_VOL_TYPE))) {
                        volinfo->type = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_COUNT,
                            strlen (GLUSTERD_STORE_KEY_VOL_COUNT))) {
                        volinfo->brick_count = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_STATUS,
                            strlen (GLUSTERD_STORE_KEY_VOL_STATUS))) {
                        volinfo->status = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_VERSION,
                            strlen (GLUSTERD_STORE_KEY_VOL_VERSION))) {
                        volinfo->version = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_PORT,
                            strlen (GLUSTERD_STORE_KEY_VOL_PORT))) {
                        volinfo->port = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_SUB_COUNT,
                            strlen (GLUSTERD_STORE_KEY_VOL_SUB_COUNT))) {
                        volinfo->sub_count = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_TRANSPORT,
                            strlen (GLUSTERD_STORE_KEY_VOL_TRANSPORT))) {
                        volinfo->transport_type = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_ID,
                            strlen (GLUSTERD_STORE_KEY_VOL_ID))) {
                        ret = uuid_parse (value, volinfo->volume_id);
                        if (ret)
                                gf_log ("", GF_LOG_WARNING,
                                        "failed to parse uuid");
                } else {
                        gf_log ("", GF_LOG_ERROR, "Unknown key: %s",
                                        key);
                }

                GF_FREE (key);
                GF_FREE (value);
                key = NULL;
                value = NULL;

                ret = glusterd_store_iter_get_next (iter, &key, &value);
        }

        ret = glusterd_store_iter_destroy (iter);

        if (ret)
                goto out;

        ret = glusterd_store_retrieve_bricks (volinfo);

        list_add_tail (&volinfo->vol_list, &priv->volumes);

out:
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);

        return ret;
}


int32_t
glusterd_store_retrieve_volumes (xlator_t  *this)
{
        int32_t         ret = 0;
        char            path[PATH_MAX] = {0,};
        glusterd_conf_t *priv = NULL;
        DIR             *dir = NULL;
        struct dirent   *entry = NULL;

        GF_ASSERT (this);
        priv = this->private;

        GF_ASSERT (priv);

        snprintf (path, PATH_MAX, "%s/%s", priv->workdir,
                        GLUSTERD_VOLUME_DIR_PREFIX);

        dir = opendir (path);

        if (!dir) {
                gf_log ("", GF_LOG_ERROR, "Unable to open dir %s", path);
                ret = -1;
                goto out;
        }

        glusterd_for_each_entry (entry, dir);

        while (entry) {
                ret = glusterd_store_retrieve_volume (entry->d_name);
                if (ret) {
                        gf_log ("", GF_LOG_ERROR, "Unable to restore "
                                "volume: %s", entry->d_name);
                        goto out;
                }
                glusterd_for_each_entry (entry, dir);
        }

out:
        if (dir)
                closedir (dir);
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);

        return ret;
}

int32_t
glusterd_store_update_volume (glusterd_volinfo_t *volinfo)
{
        int32_t         ret = -1;
        char            buf[1024] = {0,};
        glusterd_brickinfo_t    *brickinfo = NULL;
        glusterd_brickinfo_t    *tmp = NULL;


        list_for_each_entry (tmp, &volinfo->bricks, brick_list) {
                ret = glusterd_store_delete_brick (volinfo, tmp);
                //if (ret)
                  //      goto out;
        }

        ret = glusterd_store_handle_truncate (volinfo->shandle);

        snprintf (buf, sizeof (buf), "%d", volinfo->type);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_TYPE, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->brick_count);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_COUNT, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->status);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_STATUS, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->sub_count);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_SUB_COUNT, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->version);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_VERSION, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->transport_type);
        ret = glusterd_store_save_value (volinfo->shandle,
                                         GLUSTERD_STORE_KEY_VOL_TRANSPORT, buf);
        if (ret)
                goto out;

        uuid_unparse (volinfo->volume_id, buf);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_ID, buf);
        if (ret)
                goto out;

        list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) {
                ret = glusterd_store_create_brick (volinfo, brickinfo);
                if (ret)
                        goto out;
        }

        ret = 0;


out:
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);

        return ret;
}

int32_t
glusterd_store_delete_peerinfo (glusterd_peerinfo_t *peerinfo)
{
        int32_t                         ret = -1;
        glusterd_conf_t                 *priv = NULL;
        char                            peerdir[PATH_MAX] = {0,};
        char                            filepath[PATH_MAX] = {0,};
        char                            str[512] = {0,};<commit_msg>Starting/stoppin glusterd changes brick pairs<commit_after>/*
  Copyright (c) 2007-2010 Gluster, Inc. <http://www.gluster.com>
  This file is part of GlusterFS.

  GlusterFS is free software; you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as published
  by the Free Software Foundation; either version 3 of the License,
  or (at your option) any later version.

  GlusterFS is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see
  <http://www.gnu.org/licenses/>.
*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include <inttypes.h>


#include "globals.h"
#include "glusterfs.h"
#include "compat.h"
#include "dict.h"
#include "protocol-common.h"
#include "xlator.h"
#include "logging.h"
#include "timer.h"
#include "defaults.h"
#include "compat.h"
#include "compat-errno.h"
#include "statedump.h"
#include "glusterd-mem-types.h"
#include "glusterd.h"
#include "glusterd-sm.h"
#include "glusterd-op-sm.h"
#include "glusterd-utils.h"
#include "glusterd-store.h"

#include "glusterd1.h"
#include "cli1.h"
#include "rpc-clnt.h"

#include <sys/resource.h>
#include <inttypes.h>
#include <dirent.h>

static int32_t
glusterd_store_create_volume_dir (char *volname)
{
        int32_t                 ret = -1;
        char                    path[PATH_MAX] = {0,};
        glusterd_conf_t         *priv = NULL;

        GF_ASSERT (volname);
        priv = THIS->private;

        GF_ASSERT (priv);

        snprintf (path, 1024, "%s/vols/%s", priv->workdir,
                  volname);

        ret = mkdir (path, 0777);

        if (-1 == ret) {
                gf_log ("", GF_LOG_ERROR, "mkdir() failed on path %s,"
                        "errno: %d", path, errno);
                goto out;
        }

out:
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);
        return ret;
}

int32_t
glusterd_store_create_brick (glusterd_volinfo_t *volinfo,
                             glusterd_brickinfo_t *brickinfo, int32_t brick_count)
{
        int32_t                 ret = -1;
        glusterd_conf_t         *priv = NULL;
        char                    path[PATH_MAX] = {0,};
        char                    brickpath[PATH_MAX] = {0,};
        struct  stat            stbuf = {0,};
        char                    buf[4096] = {0,};
        char                    *tmppath = NULL;
        char                    *ptr = NULL;
        glusterd_store_handle_t *shandle = NULL;
        char                    tmpbuf[4096] = {0,};

        GF_ASSERT (volinfo);
        GF_ASSERT (brickinfo);

        priv = THIS->private;

        GF_ASSERT (priv);

        GLUSTERD_GET_BRICK_DIR (path, volinfo, priv);

        ret = stat (path, &stbuf);

        if (ret == -1 && ENOENT == errno) {
                ret = mkdir (path, 0777);
                if (ret)
                        goto out;
        }

        tmppath = gf_strdup (brickinfo->path);

        ptr = strchr (tmppath, '/');

        while (ptr) {
                *ptr = '-';
                ptr = strchr (tmppath, '/');
        }

        snprintf (brickpath, sizeof (brickpath), "%s/%s:%s",
                  path, brickinfo->hostname, tmppath);

        ret = glusterd_store_handle_new (brickpath, &brickinfo->shandle);

        if (ret)
                goto out;

        shandle = brickinfo->shandle;
        shandle->fd = open (brickpath, O_RDWR | O_CREAT | O_APPEND, 0666);

        if (shandle->fd < 0) {
                gf_log ("", GF_LOG_ERROR, "Open failed on %s",
                        brickpath);
                ret = -1;
                goto out;
        }


        snprintf (buf, sizeof(buf), "%s=%s\n",
                  GLUSTERD_STORE_KEY_BRICK_HOSTNAME, brickinfo->hostname);
        ret = write (shandle->fd, buf, strlen(buf));
        if (ret)
                gf_log ("", GF_LOG_TRACE, "failed to write brick->hostname");
        snprintf (buf, sizeof(buf), "%s=%s\n",
                  GLUSTERD_STORE_KEY_BRICK_PATH, brickinfo->path);
        ret = write (shandle->fd, buf, strlen(buf));
        if (ret)
                gf_log ("", GF_LOG_TRACE, "failed to write brick->path");
        snprintf (buf, sizeof(buf), "%s=%d\n",
                  GLUSTERD_STORE_KEY_BRICK_PORT, brickinfo->port);
        ret = write (shandle->fd, buf, strlen(buf));
        if (ret)
                gf_log ("", GF_LOG_TRACE, "failed to write brick->port");

        ret = 0;

        snprintf (buf, sizeof (buf), "%s-%d",GLUSTERD_STORE_KEY_VOL_BRICK,
                  brick_count);
        snprintf (tmpbuf, sizeof (tmpbuf), "%s:%s", brickinfo->hostname,
                  tmppath);
        ret = glusterd_store_save_value (volinfo->shandle, buf, tmpbuf);
       
        GF_FREE (tmppath);
  
out:
        if (shandle->fd > 0) {
                close (shandle->fd);
        }
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);
        return ret;
}

int32_t
glusterd_store_delete_brick (glusterd_volinfo_t *volinfo,
                             glusterd_brickinfo_t *brickinfo)
{
        int32_t                 ret = -1;
        glusterd_conf_t         *priv = NULL;
        char                    path[PATH_MAX] = {0,};
        char                    brickpath[PATH_MAX] = {0,};
        char                    *ptr = NULL;
        char                    *tmppath = NULL;

        GF_ASSERT (volinfo);
        GF_ASSERT (brickinfo);

        priv = THIS->private;

        GF_ASSERT (priv);

        GLUSTERD_GET_BRICK_DIR (path, volinfo, priv);

        tmppath = gf_strdup (brickinfo->path);

        ptr = strchr (tmppath, '/');

        while (ptr) {
                *ptr = '-';
                ptr = strchr (tmppath, '/');
        }

        snprintf (brickpath, sizeof (brickpath), "%s/%s:%s",
                  path, brickinfo->hostname, tmppath);

        GF_FREE (tmppath);

        ret = unlink (brickpath);

        if (ret < 0) {
                gf_log ("", GF_LOG_ERROR, "Unlink failed on %s",
                        brickpath);
                ret = -1;
                goto out;
        }

out:
        if (brickinfo->shandle)
                glusterd_store_handle_destroy (brickinfo->shandle);
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);
        return ret;
}

int32_t
glusterd_store_remove_bricks (glusterd_volinfo_t *volinfo)
{
        int32_t                 ret = 0;
        glusterd_brickinfo_t    *tmp = NULL;
        glusterd_conf_t         *priv = NULL;
        char                    brickdir [PATH_MAX] = {0,};
        DIR                     *dir = NULL;
        struct dirent           *entry = NULL;
        char                    path[PATH_MAX] = {0,};

        GF_ASSERT (volinfo);

        list_for_each_entry (tmp, &volinfo->bricks, brick_list) {
                ret = glusterd_store_delete_brick (volinfo, tmp);
                if (ret)
                        goto out;
        }

        priv = THIS->private;
        GF_ASSERT (priv);

        GLUSTERD_GET_BRICK_DIR (brickdir, volinfo, priv);

        dir = opendir (brickdir);

        glusterd_for_each_entry (entry, dir);

        while (entry) {
                snprintf (path, sizeof (path), "%s/%s",
                          brickdir, entry->d_name);
                ret = unlink (path);
                if (ret) {
                        gf_log ("", GF_LOG_ERROR, "Unable to unlink %s",
                                path);
                }
                glusterd_for_each_entry (entry, dir);
        }

        closedir (dir);

        ret = rmdir (brickdir);

out:
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);
        return ret;
}

int32_t
glusterd_store_create_volume (glusterd_volinfo_t *volinfo)
{
        int32_t                 ret = -1;
        char                    filepath[PATH_MAX] = {0,};
        char                    buf[4096] = {0,};
        glusterd_conf_t         *priv = NULL;
        glusterd_brickinfo_t    *brickinfo = NULL;
        int32_t                 brick_count = 0;

        GF_ASSERT (volinfo);
        priv = THIS->private;

        GF_ASSERT (priv);

        ret = glusterd_store_create_volume_dir (volinfo->volname);

        if (ret)
                goto out;

        snprintf (filepath, 1024, "%s/%s/%s/%s", priv->workdir,
                  GLUSTERD_VOLUME_DIR_PREFIX, volinfo->volname,
                  GLUSTERD_VOLUME_INFO_FILE);

        ret = glusterd_store_handle_new (filepath, &volinfo->shandle);

        if (ret) {
                gf_log ("", GF_LOG_ERROR, "Unable to create store"
                        " handle for path: %s", filepath);
                goto out;
        }

        snprintf (buf, sizeof (buf), "%d", volinfo->type);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_TYPE, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->brick_count);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_COUNT, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->status);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_STATUS, buf);
        if (ret)
                goto out;

/*        snprintf (buf, sizeof (buf), "%d", volinfo->port);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_PORT, buf);
        if (ret)
                goto out;
*/
        snprintf (buf, sizeof (buf), "%d", volinfo->sub_count);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_SUB_COUNT, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->version);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_VERSION, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->transport_type);
        ret = glusterd_store_save_value (volinfo->shandle,
                                         GLUSTERD_STORE_KEY_VOL_TRANSPORT, buf);
        if (ret)
                goto out;

        uuid_unparse (volinfo->volume_id, buf);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_ID, buf);
        if (ret)
                goto out;

        list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) {
                ret = glusterd_store_create_brick (volinfo, brickinfo, 
                                                   brick_count);
                if (ret)
                        goto out;
                brick_count++;
        }

        ret = 0;

out:
        if (ret) {
                glusterd_store_delete_volume (volinfo);
        }

        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);

        return ret;
}


int32_t
glusterd_store_delete_volume (glusterd_volinfo_t *volinfo)
{
        char    pathname[PATH_MAX] = {0,};
        int32_t ret = 0;
        glusterd_conf_t *priv = NULL;
        DIR     *dir = NULL;
        struct dirent *entry = NULL;
        char path[PATH_MAX] = {0,};
        struct stat     st = {0, };

        GF_ASSERT (volinfo);
        priv = THIS->private;

        GF_ASSERT (priv);
        snprintf (pathname, 1024, "%s/vols/%s", priv->workdir,
                  volinfo->volname);

        dir = opendir (pathname);
        if (!dir)
                goto out;
        ret = glusterd_store_remove_bricks (volinfo);

        if (ret) {
                gf_log ("", GF_LOG_ERROR, "Remove bricks failed");
        }

        glusterd_for_each_entry (entry, dir);
        while (entry) {

                snprintf (path, PATH_MAX, "%s/%s", pathname, entry->d_name);
                ret = stat (path, &st);
                if (ret == -1) {
                        gf_log ("", GF_LOG_ERROR, "Failed to stat entry: %s:%s",
                                path, strerror (errno));
                        goto stat_failed;
                }

                if (S_ISDIR (st.st_mode))
                        ret = rmdir (path);
                else
                        ret = unlink (path);

                gf_log ("", GF_LOG_NORMAL, "%s %s",
                                ret?"Failed to remove":"Removed",
                                entry->d_name);
                if (ret)
                        gf_log ("", GF_LOG_NORMAL, "errno:%d", errno);
stat_failed:
                memset (path, 0, sizeof(path));
                glusterd_for_each_entry (entry, dir);
        }

        ret = closedir (dir);
        if (ret) {
                gf_log ("", GF_LOG_NORMAL, "Failed to close dir, errno:%d",
                        errno);
        }

        ret = rmdir (pathname);
        if (ret) {
                gf_log ("", GF_LOG_ERROR, "Failed to rmdir: %s, errno: %d",
                        pathname, errno);
        }


out:
        if (volinfo->shandle)
                glusterd_store_handle_destroy (volinfo->shandle);
        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);

        return ret;
}



int32_t
glusterd_store_retrieve_value (glusterd_store_handle_t *handle,
                               char *key, char **value)
{
        int32_t         ret = -1;
        char            scan_str[4096] = {0,};
        char            *iter_key = NULL;
        char            *iter_val = NULL;
        char            *str = NULL;
        char            *free_str = NULL;

        GF_ASSERT (handle);

        handle->fd = open (handle->path, O_RDWR);

        if (!handle->read)
                handle->read = fdopen (handle->fd, "r");

        if (!handle->read) {
                gf_log ("", GF_LOG_ERROR, "Unable to open file %s errno: %d",
                        handle->path, errno);
                goto out;
        }

        ret = fscanf (handle->read, "%s", scan_str);

        while (ret != EOF) {
                if (free_str) {
                        GF_FREE (free_str);
                        free_str = NULL;
                }
                str = gf_strdup (scan_str);
                if (!str)
                        goto out;
                else
                        free_str = str;
                iter_key = strtok (str, "=");
                gf_log ("", GF_LOG_DEBUG, "key %s read", iter_key);

                if (!strcmp (key, iter_key)) {
                        gf_log ("", GF_LOG_DEBUG, "key %s found", key);
                        iter_val = strtok (NULL, "=");
                        ret = 0;
                        if (iter_val)
                                *value = gf_strdup (iter_val);
                        goto out;
                }

                ret = fscanf (handle->read, "%s", scan_str);
        }

        if (EOF == ret)
                ret = -1;
out:
        if (handle->fd > 0) {
                close (handle->fd);
                handle->read = NULL;
        }

        if (free_str)
                GF_FREE (free_str);

        return ret;
}

int32_t
glusterd_store_save_value (glusterd_store_handle_t *handle,
                           char *key, char *value)
{
        int32_t         ret = -1;
        char            buf[4096] = {0,};

        GF_ASSERT (handle);
        GF_ASSERT (key);
        GF_ASSERT (value);

        handle->fd = open (handle->path, O_RDWR | O_APPEND);

        if (handle->fd < 0) {
                gf_log ("", GF_LOG_ERROR, "Unable to open %s, errno: %d",
                        handle->path, errno);
                goto out;
        }

        snprintf (buf, sizeof (buf), "%s=%s\n", key, value);
        ret = write (handle->fd, buf, strlen (buf));

        if (ret < 0) {
                gf_log ("", GF_LOG_CRITICAL, "Unable to store key: %s,"
                        "value: %s, error: %s", key, value,
                        strerror (errno));
                ret = -1;
                goto out;
        }

        ret = 0;

out:

        if (handle->fd > 0) {
                close (handle->fd);
                handle->fd = -1;
        }

        gf_log ("", GF_LOG_DEBUG, "returning: %d", ret);
        return ret;
}

int32_t
glusterd_store_handle_new (char *path, glusterd_store_handle_t **handle)
{
        int32_t                 ret = -1;
        glusterd_store_handle_t *shandle = NULL;

        shandle = GF_CALLOC (1, sizeof (*shandle), gf_gld_mt_store_handle_t);
        if (!shandle)
                goto out;

        shandle->path = gf_strdup (path);

        if (!shandle->path)
                goto out;

        shandle->fd = open (path, O_RDWR | O_CREAT | O_APPEND, 0644);
        if (!shandle->fd)
                goto out;

        *handle = shandle;

        ret = 0;

out:
        if (ret == -1) {
                if (shandle) {
                        if (shandle->path)
                                GF_FREE (shandle->path);
                        if (shandle->fd > 0)
                                close (shandle->fd);
                        GF_FREE (shandle);
                }
        } else {
                close (shandle->fd);
        }

        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);

        return ret;
}

int32_t
glusterd_store_handle_destroy (glusterd_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
glusterd_store_handle_truncate (glusterd_store_handle_t *handle)
{
        int32_t         ret = -1;

        GF_ASSERT (handle);
        GF_ASSERT (handle->path);

        ret = truncate (handle->path, 0);

        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);

        return ret;
}

int32_t
glusterd_store_uuid ()
{
        char            str[GLUSTERD_UUID_LEN] = {0,};
        glusterd_conf_t *priv = NULL;
        char            path[PATH_MAX] = {0,};
        int32_t         ret = -1;
        glusterd_store_handle_t *handle = NULL;

        priv = THIS->private;

        uuid_unparse (priv->uuid, str);

        snprintf (path, PATH_MAX, "%s/%s", priv->workdir,
                  GLUSTERD_INFO_FILE);

        if (!priv->handle) {
                ret = glusterd_store_handle_new (path, &handle);

                if (ret) {
                        gf_log ("", GF_LOG_ERROR, "Unable to get store"
                                " handle!");
                        goto out;
                }

                priv->handle = handle;
        }

        ret = glusterd_store_save_value (priv->handle, GLUSTERD_STORE_UUID_KEY,
                                         str);

        if (ret) {
                gf_log ("", GF_LOG_CRITICAL, "Storing uuid failed"
                        "ret = %d", ret);
                goto out;
        }


out:
        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
        return ret;
}


int32_t
glusterd_retrieve_uuid ()
{
        char            *uuid_str = NULL;
        int32_t         ret = -1;
        glusterd_store_handle_t *handle = NULL;
        glusterd_conf_t *priv = NULL;
        char            path[PATH_MAX] = {0,};

        priv = THIS->private;


        if (!priv->handle) {
                snprintf (path, PATH_MAX, "%s/%s", priv->workdir,
                          GLUSTERD_INFO_FILE);
                ret = glusterd_store_handle_new (path, &handle);

                if (ret) {
                        gf_log ("", GF_LOG_ERROR, "Unable to get store "
                                "handle!");
                        goto out;
                }

                priv->handle = handle;
        }

        ret = glusterd_store_retrieve_value (priv->handle,
                                             GLUSTERD_STORE_UUID_KEY,
                                             &uuid_str);

        if (ret) {
                gf_log ("", GF_LOG_CRITICAL, "Retrieving uuid failed"
                        " ret = %d", ret);
                goto out;
        }

        uuid_parse (uuid_str, priv->uuid);

out:
        if (uuid_str)
                GF_FREE (uuid_str);
        gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
        return ret;
}

int32_t
glusterd_store_iter_new (glusterd_store_handle_t  *shandle,
                         glusterd_store_iter_t  **iter)
{
        int32_t                 ret = -1;
        glusterd_store_iter_t   *tmp_iter = NULL;
        int                     fd = -1;

        GF_ASSERT (shandle);
        GF_ASSERT (iter);

        tmp_iter = GF_CALLOC (1, sizeof (*tmp_iter),
                             gf_gld_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 (shandle->fd, "r");

        if (!tmp_iter->file) {
                gf_log ("", GF_LOG_ERROR, "Unable to open file %s errno: %d",
                        shandle->path, errno);
                goto out;
        }

        *iter = tmp_iter;
        ret = 0;

out:
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);
        return ret;
}

int32_t
glusterd_store_iter_get_next (glusterd_store_iter_t *iter,
                              char  **key, char **value)
{
        int32_t         ret = -1;
        char            scan_str[4096] = {0,};
        char            *str = NULL;
        char            *free_str = NULL;
        char            *iter_key = NULL;
        char            *iter_val = NULL;

        GF_ASSERT (iter);
        GF_ASSERT (iter->file);

        ret = fscanf (iter->file, "%s", scan_str);

        if (ret <= 0) {
                ret = -1;
                goto out;
        }

        str = gf_strdup (scan_str);
        if (!str)
                goto out;
        else
                free_str = str;

        iter_key = strtok (str, "=");
        gf_log ("", GF_LOG_DEBUG, "key %s read", iter_key);


        iter_val = strtok (NULL, "=");
        gf_log ("", GF_LOG_DEBUG, "value %s read", iter_val);

        if (iter_val)
                *value = gf_strdup (iter_val);
        *key   = gf_strdup (iter_key);

        ret = 0;

out:
        if (free_str)
                GF_FREE (free_str);

        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);
        return ret;
}

int32_t
glusterd_store_iter_get_matching (glusterd_store_iter_t *iter,
                              char  *key, char **value)
{
        int32_t ret = -1;
        char    *tmp_key = NULL;
        char    *tmp_value = NULL;

        ret = glusterd_store_iter_get_next (iter, &tmp_key, &tmp_value);
        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 = glusterd_store_iter_get_next (iter, &tmp_key, 
                                                    &tmp_value);
        }
out:
        return ret;
}

int32_t
glusterd_store_iter_destroy (glusterd_store_iter_t *iter)
{
        int32_t         ret = -1;

        GF_ASSERT (iter);
        GF_ASSERT (iter->fd > 0);

        ret = fclose (iter->file);

        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;
}

int32_t
glusterd_store_retrieve_bricks (glusterd_volinfo_t *volinfo)
{

        int32_t                 ret = 0;
        glusterd_brickinfo_t    *brickinfo = NULL;
        glusterd_store_iter_t   *iter = NULL;
        char                    *key = NULL;
        char                    *value = NULL;
        char                    brickdir[PATH_MAX] = {0,};
        char                    path[PATH_MAX] = {0,};
        glusterd_conf_t         *priv = NULL;
        int32_t                 brick_count = 0;
        char                    tmpkey[4096] = {0,};
        glusterd_store_iter_t   *tmpiter = NULL;
        char                    *tmpvalue = NULL;

        GF_ASSERT (volinfo);
        GF_ASSERT (volinfo->volname);

        priv = THIS->private;

        GLUSTERD_GET_BRICK_DIR (brickdir, volinfo, priv)

        ret = glusterd_store_iter_new (volinfo->shandle, &tmpiter);

        if (ret)
                goto out;

        while (brick_count < volinfo->brick_count) {
                ret = glusterd_brickinfo_new (&brickinfo);

                if (ret)
                        goto out;
             
                snprintf (tmpkey, sizeof (tmpkey), "%s-%d",
                          GLUSTERD_STORE_KEY_VOL_BRICK,brick_count); 
                ret = glusterd_store_iter_get_matching (tmpiter, tmpkey, 
                                                        &tmpvalue);
                snprintf (path, sizeof (path), "%s/%s", brickdir, tmpvalue);

                GF_FREE (tmpvalue);                          

                tmpvalue = NULL;

                ret = glusterd_store_handle_new (path, &brickinfo->shandle);

                if (ret)
                        goto out;

                ret = glusterd_store_iter_new (brickinfo->shandle, &iter);

                if (ret)
                        goto out;

                ret = glusterd_store_iter_get_next (iter, &key, &value);

                while (!ret) {
                        if (!strncmp (key, GLUSTERD_STORE_KEY_BRICK_HOSTNAME,
                                      strlen (GLUSTERD_STORE_KEY_BRICK_HOSTNAME))) {
                                strncpy (brickinfo->hostname, value, 1024);
                        } else if (!strncmp (key, GLUSTERD_STORE_KEY_BRICK_PATH,
                                    strlen (GLUSTERD_STORE_KEY_BRICK_PATH))) {
                                strncpy (brickinfo->path, value,
                                         sizeof (brickinfo->path));
                        } else if (!strncmp (key, GLUSTERD_STORE_KEY_BRICK_PORT,
                                    strlen (GLUSTERD_STORE_KEY_BRICK_PORT))) {
                                gf_string2int (value, &brickinfo->port);
                        } else {
                                gf_log ("", GF_LOG_ERROR, "Unknown key: %s",
                                        key);
                        }

                        GF_FREE (key);
                        GF_FREE (value);
                        key = NULL;
                        value = NULL;

                        ret = glusterd_store_iter_get_next (iter, &key, &value);
                }

                ret = glusterd_store_iter_destroy (iter);

                if (ret)
                        goto out;

                list_add_tail (&brickinfo->brick_list, &volinfo->bricks);
                brick_count++;
        }

        ret = glusterd_store_iter_destroy (tmpiter);
        if (ret)
                goto out;
out:
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);

        return ret;
}


int32_t
glusterd_store_retrieve_volume (char    *volname)
{
        int32_t                 ret = -1;
        glusterd_volinfo_t      *volinfo = NULL;
        glusterd_store_iter_t   *iter = NULL;
        char                    *key = NULL;
        char                    *value = NULL;
        char                    volpath[PATH_MAX] = {0,};
        glusterd_conf_t         *priv = NULL;
        char                    path[PATH_MAX] = {0,};

        ret = glusterd_volinfo_new (&volinfo);

        if (ret)
                goto out;

        strncpy (volinfo->volname, volname, GLUSTERD_MAX_VOLUME_NAME);

        priv = THIS->private;

        GLUSTERD_GET_VOLUME_DIR(volpath, volinfo, priv);
        snprintf (path, sizeof (path), "%s/%s", volpath,
                  GLUSTERD_VOLUME_INFO_FILE);

        ret = glusterd_store_handle_new (path, &volinfo->shandle);

        if (ret)
                goto out;

        ret = glusterd_store_iter_new (volinfo->shandle, &iter);

        if (ret)
                goto out;

        ret = glusterd_store_iter_get_next (iter, &key, &value);

        while (!ret) {
                if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_TYPE,
                              strlen (GLUSTERD_STORE_KEY_VOL_TYPE))) {
                        volinfo->type = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_COUNT,
                            strlen (GLUSTERD_STORE_KEY_VOL_COUNT))) {
                        volinfo->brick_count = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_STATUS,
                            strlen (GLUSTERD_STORE_KEY_VOL_STATUS))) {
                        volinfo->status = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_VERSION,
                            strlen (GLUSTERD_STORE_KEY_VOL_VERSION))) {
                        volinfo->version = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_PORT,
                            strlen (GLUSTERD_STORE_KEY_VOL_PORT))) {
                        volinfo->port = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_SUB_COUNT,
                            strlen (GLUSTERD_STORE_KEY_VOL_SUB_COUNT))) {
                        volinfo->sub_count = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_TRANSPORT,
                            strlen (GLUSTERD_STORE_KEY_VOL_TRANSPORT))) {
                        volinfo->transport_type = atoi (value);
                } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_ID,
                            strlen (GLUSTERD_STORE_KEY_VOL_ID))) {
                        ret = uuid_parse (value, volinfo->volume_id);
                        if (ret)
                                gf_log ("", GF_LOG_WARNING,
                                        "failed to parse uuid");
                } else {
                        gf_log ("", GF_LOG_ERROR, "Unknown key: %s",
                                        key);
                }

                GF_FREE (key);
                GF_FREE (value);
                key = NULL;
                value = NULL;

                ret = glusterd_store_iter_get_next (iter, &key, &value);
        }

        ret = glusterd_store_iter_destroy (iter);

        if (ret)
                goto out;

        ret = glusterd_store_retrieve_bricks (volinfo);

        list_add_tail (&volinfo->vol_list, &priv->volumes);

out:
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);

        return ret;
}


int32_t
glusterd_store_retrieve_volumes (xlator_t  *this)
{
        int32_t         ret = 0;
        char            path[PATH_MAX] = {0,};
        glusterd_conf_t *priv = NULL;
        DIR             *dir = NULL;
        struct dirent   *entry = NULL;

        GF_ASSERT (this);
        priv = this->private;

        GF_ASSERT (priv);

        snprintf (path, PATH_MAX, "%s/%s", priv->workdir,
                        GLUSTERD_VOLUME_DIR_PREFIX);

        dir = opendir (path);

        if (!dir) {
                gf_log ("", GF_LOG_ERROR, "Unable to open dir %s", path);
                ret = -1;
                goto out;
        }

        glusterd_for_each_entry (entry, dir);

        while (entry) {
                ret = glusterd_store_retrieve_volume (entry->d_name);
                if (ret) {
                        gf_log ("", GF_LOG_ERROR, "Unable to restore "
                                "volume: %s", entry->d_name);
                        goto out;
                }
                glusterd_for_each_entry (entry, dir);
        }

out:
        if (dir)
                closedir (dir);
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);

        return ret;
}

int32_t
glusterd_store_update_volume (glusterd_volinfo_t *volinfo)
{
        int32_t         ret = -1;
        char            buf[1024] = {0,};
        glusterd_brickinfo_t    *brickinfo = NULL;
        glusterd_brickinfo_t    *tmp = NULL;
        int32_t         brick_count = 0;


        list_for_each_entry (tmp, &volinfo->bricks, brick_list) {
                ret = glusterd_store_delete_brick (volinfo, tmp);
                //if (ret)
                  //      goto out;
        }

        ret = glusterd_store_handle_truncate (volinfo->shandle);

        snprintf (buf, sizeof (buf), "%d", volinfo->type);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_TYPE, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->brick_count);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_COUNT, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->status);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_STATUS, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->sub_count);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_SUB_COUNT, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->version);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_VERSION, buf);
        if (ret)
                goto out;

        snprintf (buf, sizeof (buf), "%d", volinfo->transport_type);
        ret = glusterd_store_save_value (volinfo->shandle,
                                         GLUSTERD_STORE_KEY_VOL_TRANSPORT, buf);
        if (ret)
                goto out;

        uuid_unparse (volinfo->volume_id, buf);
        ret = glusterd_store_save_value (volinfo->shandle,
                                        GLUSTERD_STORE_KEY_VOL_ID, buf);
        if (ret)
                goto out;

        list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) {
                ret = glusterd_store_create_brick (volinfo, brickinfo, 
                                                   brick_count);
                if (ret)
                        goto out;
                brick_count++;
        }

        ret = 0;


out:
        gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret);

        return ret;
}

int32_t
glusterd_store_delete_peerinfo (glusterd_peerinfo_t *peerinfo)
{
        int32_t                         ret = -1;
        glusterd_conf_t                 *priv = NULL;
        char                            peerdir[PATH_MAX] = {0,};
        char                            filepath[PATH_MAX] = {0,};
        char                            str[512] = {0,};
{'fraction_non_alphanumeric': 0.10608577578112587, 'fraction_numerical': 0.007367067762578185, 'mean_word_length': 1.3210621605310802, 'pattern_counts': {'":': 2, '<': 28, '<?xml version=': 0, '>': 346, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 72, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3095523', 'n_tokens_mistral': 22240, 'n_tokens_neox': 20846, 'n_words': 4696}