summaryrefslogtreecommitdiff
path: root/ioreplay/src/init/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'ioreplay/src/init/init.c')
-rw-r--r--ioreplay/src/init/init.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/ioreplay/src/init/init.c b/ioreplay/src/init/init.c
new file mode 100644
index 0000000..988729e
--- /dev/null
+++ b/ioreplay/src/init/init.c
@@ -0,0 +1,226 @@
+// Copyright 2018 Mimecast Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "init.h"
+
+#include "../datas/stack.h"
+#include "itask.h"
+#include "ithread.h"
+#include "../meta/meta.h"
+#include "../mounts.h"
+#include "../utils/futils.h"
+
+
+init_s *init_new(options_s *opts)
+{
+ init_s *i = Malloc(init_s);
+
+ i->opts = opts;
+ i->mounts = mounts_new(opts);
+ i->threads_map = amap_new(i->mounts->count);
+ i->reuse_queue = rbuffer_new(4096);
+ i->replay_fd = Fopen(opts->replay_file, "r");
+
+ pthread_mutex_init(&i->reuse_queue_mutex, NULL);
+
+ return i;
+}
+
+void init_destroy(init_s *i)
+{
+ amap_destroy(i->threads_map);
+ mounts_destroy(i->mounts);
+
+ itask_s *task = NULL;
+ while (NULL != (task = rbuffer_get_next(i->reuse_queue))) {
+ itask_destroy(task);
+ }
+ rbuffer_destroy(i->reuse_queue);
+
+ fclose(i->replay_fd);
+ pthread_mutex_destroy(&i->reuse_queue_mutex);
+
+ free(i);
+}
+
+void init_extract_header(init_s *i, off_t *init_offset)
+{
+ options_s *opts = i->opts;
+ meta_s *m = meta_new(i->replay_fd);
+ meta_read_start(m);
+
+ long version = 0;
+ if (meta_read_l(m, "version", &version)) {
+ Put("Replay version is '%ld'", version);
+ if (version != REPLAY_VERSION) {
+ Error(".replay file of incompatible version, got %x, expected %x",
+ (int)version, REPLAY_VERSION);
+ }
+ }
+
+ char *user;
+ if (meta_read_s(m, "user", &user)) {
+ Put("Setting user to '%s'", user);
+ opts->user = user;
+ }
+
+ char *name;
+ if (meta_read_s(m, "name", &name)) {
+ Put("Setting name to '%s'", name);
+ opts->name = name;
+ }
+
+ if (meta_read_l(m, "init_offset", init_offset)) {
+ if (*init_offset < 0) {
+ Error("Offset overflow (init offset too large in .replay)");
+ }
+ Put("Setting init offset to '%ld'", *init_offset);
+ }
+
+ meta_destroy(m);
+}
+
+status_e init_run(options_s *opts)
+{
+ status_e ret = SUCCESS;
+ init_s *i = init_new(opts);
+
+ off_t init_offset;
+ init_extract_header(i, &init_offset);
+
+ // Ensure that all ./replay/NAME directories exist
+ mounts_init(i->mounts);
+
+ // Don't do messy stuff as super user
+ drop_root(opts->user);
+
+ // We need to clean up garbish from previous runs!
+ if (opts->purge)
+ mounts_purge(i->mounts);
+ else
+ mounts_trash(i->mounts);
+
+ Out("Creating all files and directories requried for test '%s'...",
+ opts->name);
+
+ // Seek to the INIT section
+ fseeko(i->replay_fd, init_offset, SEEK_SET);
+
+ bool is_file = false, is_dir = false;
+ long vsize = 0;
+ char *path;
+
+ // Stats
+ long dirs_created = 0;
+ long files_created = 0;
+ long files_total_size = 0;
+
+ // Helper variables for getline
+ char *line = NULL;
+ size_t len = 0, read = 0;
+ char *saveptr;
+
+ stack_s *all_threads = stack_new();
+
+ // Process the INIT section of the .replay file line by line.
+
+ while ((read = getline(&line, &len, i->replay_fd)) != -1) {
+ char *tok = strtok_r(line, "|", &saveptr);
+
+ for (int ntok = 0; tok; ntok++) {
+ switch (ntok) {
+ case 0:
+ is_dir = atoi(tok) == 1;
+ break;
+ case 1:
+ is_file = atoi(tok) == 1;
+ break;
+ case 2:
+ vsize = atol(tok);
+ if (vsize < 0) {
+ Error("Size overflow");
+ }
+ break;
+ case 3:
+ path = tok;
+ break;
+ default:
+ break;
+ }
+
+ tok = strtok_r(NULL, "|", &saveptr);
+ }
+
+ itask_s *task = rbuffer_get_next(i->reuse_queue);
+
+ if (!task) {
+ task = itask_new();
+
+ } else {
+ itask_extract_stats(task, &dirs_created, &files_created,
+ &files_total_size);
+ }
+
+ // Set new task values
+ if (is_dir) {
+ task->is_dir = true;
+
+ } else if (is_file) {
+ task->is_file = true;
+ task->vsize = vsize;
+ }
+ task->path = Clone(path);
+
+ // We run one init thread per mount point
+ int mnr = mounts_get_mountnumber(i->mounts, path);
+ ithread_s *t = amap_get(i->threads_map, mnr);
+
+ if (!t) {
+ t = ithread_new(i);
+ amap_set(i->threads_map, mnr, t);
+ stack_push(all_threads, t);
+ ithread_start(t);
+ }
+
+ //itask_print(task);
+ while (!rbuffer_insert(t->queue, task))
+ usleep(1000);
+ }
+
+ ithread_s *t = NULL;
+ while (NULL != (t = stack_pop(all_threads))) {
+ ithread_terminate(t);
+ ithread_destroy(t);
+ }
+ stack_destroy(all_threads);
+
+ itask_s *task = NULL;
+ while (NULL != (task = rbuffer_get_next(i->reuse_queue))) {
+ itask_extract_stats(task, &dirs_created, &files_created,
+ &files_total_size);
+ itask_destroy(task);
+ }
+
+ Put("Done!");
+
+ Put("Created %ld files (net total size: %.2fg) and %ld directories!",
+ files_created, files_total_size/(1024*1024*1024.0),
+ dirs_created);
+
+ init_destroy(i);
+
+ Put("You are ready to fire up the test now");
+
+ return ret;
+}