summaryrefslogtreecommitdiffstats
path: root/glusterfs-guts/src/glusterfs-guts.c
diff options
context:
space:
mode:
Diffstat (limited to 'glusterfs-guts/src/glusterfs-guts.c')
-rw-r--r--glusterfs-guts/src/glusterfs-guts.c400
1 files changed, 400 insertions, 0 deletions
diff --git a/glusterfs-guts/src/glusterfs-guts.c b/glusterfs-guts/src/glusterfs-guts.c
new file mode 100644
index 000000000..3efac3a35
--- /dev/null
+++ b/glusterfs-guts/src/glusterfs-guts.c
@@ -0,0 +1,400 @@
+/*
+ Copyright (c) 2008 Z RESEARCH, Inc. <http://www.zresearch.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 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <argp.h>
+#include <string.h>
+
+#include "glusterfs.h"
+#include "xlator.h"
+#include "glusterfs-guts.h"
+
+/* argp initializations */
+static char doc[] = "glusterfs-guts is unit testing suite for glusterfs";
+static char argp_doc[] = "";
+const char *argp_program_version = PACKAGE_NAME " " PACKAGE_VERSION " built on " __DATE__;
+const char *argp_program_bug_address = PACKAGE_BUGREPORT;
+
+guts_ctx_t guts_ctx;
+error_t parse_opts (int32_t key, char *arg, struct argp_state *_state);
+
+static struct argp_option options[] = {
+ {"spec-file", 'f', "VOLUMESPEC-FILE", 0,\
+ "Load VOLUMESPEC-FILE."},
+ {"threads", 't', "NUMBER", 0,\
+ "Load NUMBER of threads."},
+ {"tio-file", 'i', "FILE", 0,\
+ "Replay fops from FILE."},
+ {"tio-directory", 'I', "DIRECTORY", 0,\
+ "Replay fops from files in DIRECTORY. Valid option only when using more than one thread."},
+ {"log-level", 'L', "LOGLEVEL", 0,
+ "LOGLEVEL should be one of DEBUG, WARNING, [ERROR], CRITICAL, NONE"},
+ {"log-file", 'l', "LOGFILE", 0, \
+ "Specify the file to redirect logs"},
+ {"trace", 'T', "MOUNTPOINT", 0, \
+ "Run guts in trace mode. Guts mounts glusterfs on MOUNTPOINT specified"},
+ {"output", 'o', "OUTPUT-TIOFILE", 0, \
+ "Write trace io output to OUTPUT-TIOFILE. Valid only when run in trace(-T) mode."},
+ {"version", 'V', 0, 0,\
+ "print version information"},
+ { 0, }
+};
+
+static struct argp argp = { options, parse_opts, argp_doc, doc };
+
+/* guts_print_version - used by argument parser routine to print version information for guts */
+static int32_t
+guts_print_version (void)
+{
+ printf ("%s\n", argp_program_version);
+ printf ("Copyright (c) 2006, 2007 Z RESEARCH Inc. <http://www.zresearch.com>\n");
+ printf ("GlusterFS comes with ABSOLUTELY NO WARRANTY.\nYou may redistribute copies of GlusterFS under the terms of the GNU General Public License.\n");
+ exit (0);
+}
+
+/* parse_opts - argument parsing helper routine for argp library */
+error_t
+parse_opts (int32_t key, char *arg, struct argp_state *_state)
+{
+ guts_ctx_t *state = _state->input;
+
+ switch (key) {
+ case 'f':
+ if (!state->specfile) {
+ state->specfile = strdup (arg);
+ }
+ break;
+
+ case 't':
+ if (!state->threads) {
+ state->threads = strtol (arg, NULL, 0);
+ }
+ break;
+
+ case 'i':
+ if (state->threads == 1) {
+ state->file = strdup (arg);
+ } else {
+ fprintf (stderr, "glusterfs-guts: -i option is valid only when guts is running single thread\n");
+ exit (1);
+ }
+ break;
+
+ case 'I':
+ if (state->threads > 1) {
+ state->directory = strdup (arg);
+ } else {
+ fprintf (stderr, "glusterfs-guts: -I option is valid only when guts is running multiple threads\n");
+ exit (1);
+ }
+ break;
+
+ case 'L':
+ /* set log level */
+ if (!strncasecmp (arg, "DEBUG", strlen ("DEBUG"))) {
+ state->loglevel = GF_LOG_DEBUG;
+ } else if (!strncasecmp (arg, "WARNING", strlen ("WARNING"))) {
+ state->loglevel = GF_LOG_WARNING;
+ } else if (!strncasecmp (arg, "CRITICAL", strlen ("CRITICAL"))) {
+ state->loglevel = GF_LOG_CRITICAL;
+ } else if (!strncasecmp (arg, "NONE", strlen ("NONE"))) {
+ state->loglevel = GF_LOG_NONE;
+ } else if (!strncasecmp (arg, "ERROR", strlen ("ERROR"))) {
+ state->loglevel = GF_LOG_ERROR;
+ } else {
+ fprintf (stderr, "glusterfs-guts: Unrecognized log-level \"%s\", possible values are \"DEBUG|WARNING|[ERROR]|CRITICAL|NONE\"\n", arg);
+ exit (EXIT_FAILURE);
+ }
+ break;
+ case 'l':
+ /* set log file */
+ state->logfile = strdup (arg);
+ break;
+
+ case 'T':
+ state->trace = 1;
+ state->mountpoint = strdup (arg);
+ break;
+
+ case 'o':
+ state->file = strdup (arg);
+ break;
+
+ case 'V':
+ guts_print_version ();
+ break;
+
+ }
+ return 0;
+}
+
+/* get_xlator_graph - creates a translator graph and returns the pointer to the root of the xlator tree
+ *
+ * @ctx: guts context structure
+ * @conf: file handle to volume specfile
+ *
+ * returns pointer to the root of the translator tree
+ */
+static xlator_t *
+get_xlator_graph (glusterfs_ctx_t *ctx,
+ FILE *conf)
+{
+ xlator_t *tree, *trav = NULL;
+
+ tree = file_to_xlator_tree (ctx, conf);
+ trav = tree;
+
+ if (tree == NULL) {
+ gf_log ("glusterfs-guts",
+ GF_LOG_ERROR,
+ "specification file parsing failed, exiting");
+ return NULL;
+ }
+
+ tree = trav;
+
+ return tree;
+}
+
+/* get_spec_fp - get file handle to volume spec file specified.
+ *
+ * @ctx: guts context structure
+ *
+ * returns FILE pointer to the volume spec file.
+ */
+static FILE *
+get_spec_fp (guts_ctx_t *ctx)
+{
+ char *specfile = ctx->specfile;
+ FILE *conf = NULL;
+
+ specfile = ctx->specfile;
+
+ conf = fopen (specfile, "r");
+
+ if (!conf) {
+ perror (specfile);
+ return NULL;
+ }
+ gf_log ("glusterfs-guts",
+ GF_LOG_DEBUG,
+ "loading spec from %s",
+ specfile);
+
+ return conf;
+}
+
+static void *
+guts_thread_main (void *ctx)
+{
+ guts_thread_ctx_t *tctx = (guts_thread_ctx_t *) ctx;
+
+ printf ("starting thread main with %s:\n", tctx->file);
+ guts_replay (tctx);
+ printf ("ending thread main.\n");
+
+ return NULL;
+}
+
+/* guts_create_threads - creates different threads based on thread number specified in ctx and assigns a
+ * tio file to each thread and attaches each thread to the graph created by main().
+ * @ctx: guts_ctx_t which contains the context corresponding to the current run of guts
+ *
+ * returns the guts_threads_t structure which contains handles to the different threads created.
+ *
+ */
+static guts_threads_t *
+guts_create_threads (guts_ctx_t *ctx)
+{
+ guts_threads_t *threads = NULL;
+ int32_t thread_count = ctx->threads;
+
+ threads = CALLOC (1, sizeof (*threads));
+ ERR_ABORT (threads);
+
+
+ INIT_LIST_HEAD (&(threads->threads));
+
+ if (thread_count == 1) {
+ /* special case: we have only one thread and we are given a tio-file as argument instead of a directory.
+ * handling differently */
+ guts_thread_ctx_t *thread = NULL;
+ thread = CALLOC (1, sizeof (*thread));
+ ERR_ABORT (thread);
+ list_add (&thread->threads, &threads->threads);
+ thread->file = strdup (ctx->file);
+ thread->ctx = ctx;
+ } else {
+ /* look for .tio files in the directory given and assign to each of the threads */
+ DIR *dir = opendir (ctx->directory);
+
+ if (!dir) {
+ gf_log ("guts",
+ GF_LOG_ERROR,
+ "failed to open directory %s", ctx->directory);
+ } else {
+ guts_thread_ctx_t *thread = NULL;
+ struct dirent *dirp = NULL;
+ /* to pass through "." and ".." */
+ readdir (dir);
+ readdir (dir);
+
+ while (thread_count > 0) {
+ char pathname[256] = {0,};
+
+ thread = CALLOC (1, sizeof (*thread));
+ ERR_ABORT (thread);
+ dirp = NULL;
+
+ list_add (&thread->threads, &threads->threads);
+ dirp = readdir (dir);
+ if (dirp) {
+ sprintf (pathname, "%s/%s", ctx->directory, dirp->d_name);
+ printf ("file name for thread(%d) is %s\n", thread_count, pathname);
+ thread->file = strdup (pathname);
+ thread->ctx = ctx;
+ } else if (thread_count > 0) {
+ gf_log ("guts",
+ GF_LOG_ERROR,
+ "number of tio files less than %d, number of threads specified", ctx->threads);
+ /* TODO: cleanup */
+ return NULL;
+ }
+ --thread_count;
+ }
+ }
+ }
+ return threads;
+}
+
+/* guts_start_threads - starts all the threads in @threads.
+ *
+ * @threads: guts_threads_t structure containing the handles to threads created by guts_create_threads.
+ *
+ * returns <0 on error.
+ *
+ */
+static void
+guts_start_threads (guts_threads_t *gthreads)
+{
+ guts_thread_ctx_t *thread = NULL;
+ list_for_each_entry (thread, &gthreads->threads, threads) {
+ if (pthread_create (&thread->pthread, NULL, guts_thread_main, (void *)thread) < 0) {
+ gf_log ("guts",
+ GF_LOG_ERROR,
+ "failed to start thread");
+ } else {
+ gf_log ("guts",
+ GF_LOG_DEBUG,
+ "started thread with file %s", thread->file);
+ }
+ }
+}
+
+static int32_t
+guts_join_threads (guts_threads_t *gthreads)
+{
+ guts_thread_ctx_t *thread = NULL;
+ list_for_each_entry (thread, &gthreads->threads, threads) {
+ if (pthread_join (thread->pthread, NULL) < 0) {
+ gf_log ("guts",
+ GF_LOG_ERROR,
+ "failed to join thread");
+ } else {
+ gf_log ("guts",
+ GF_LOG_DEBUG,
+ "joined thread with file %s", thread->file);
+ }
+ }
+ return 0;
+}
+
+
+int32_t
+main (int32_t argc, char *argv[])
+{
+ /* glusterfs_ctx_t is required to be passed to
+ * 1. get_xlator_graph
+ * 2. glusterfs_mount
+ */
+ glusterfs_ctx_t gfs_ctx = {
+ .logfile = DATADIR "/log/glusterfs/glusterfs-guts.log",
+ .loglevel = GF_LOG_DEBUG,
+ .poll_type = SYS_POLL_TYPE_EPOLL,
+ };
+
+ guts_ctx_t guts_ctx = {0,};
+ FILE *specfp = NULL;
+ xlator_t *graph = NULL;
+ guts_threads_t *threads = NULL;
+
+ argp_parse (&argp, argc, argv, 0, 0, &guts_ctx);
+
+ if (gf_log_init (gfs_ctx.logfile) == -1 ) {
+ fprintf (stderr,
+ "glusterfs-guts: failed to open logfile \"%s\"\n",
+ gfs_ctx.logfile);
+ return -1;
+ }
+ gf_log_set_loglevel (gfs_ctx.loglevel);
+
+ specfp = get_spec_fp (&guts_ctx);
+ if (!specfp) {
+ fprintf (stderr,
+ "glusterfs-guts: could not open specfile\n");
+ return -1;
+ }
+
+ graph = get_xlator_graph (&gfs_ctx, specfp);
+ if (!graph) {
+ gf_log ("guts", GF_LOG_ERROR,
+ "Unable to get xlator graph");
+ return -1;
+ }
+ fclose (specfp);
+
+ guts_ctx.graph = graph;
+
+ if (guts_ctx.trace) {
+ return guts_trace (&guts_ctx);
+ } else {
+ /* now that we have the xlator graph, we need to create as many threads as requested and assign a tio file
+ * to each of the threads and tell each thread to attach to the graph we just created. */
+
+ if (!guts_ctx.file && !guts_ctx.directory) {
+ fprintf (stderr,
+ "glusterfs-guts: no tio file specified");
+ return -1;
+ }
+
+ threads = guts_create_threads (&guts_ctx);
+
+ if (threads) {
+ guts_start_threads (threads);
+ guts_join_threads (threads);
+ } else {
+ gf_log ("guts", GF_LOG_ERROR,
+ "unable to create threads");
+ return 0;
+ }
+ }
+
+ return 0;
+}
+