[sheepdog] [PATCH v4 1/3] rename collie as dog
Liu Yuan
namei.unix at gmail.com
Tue Aug 13 08:09:48 CEST 2013
Signed-off-by: Liu Yuan <namei.unix at gmail.com>
---
.gitignore | 6 +-
INSTALL | 2 +-
Makefile.am | 10 +-
README | 12 +-
collie/Makefile.am | 56 -
collie/cluster.c | 524 ---------
collie/collie.c | 433 --------
collie/collie.h | 97 --
collie/common.c | 324 ------
collie/farm/farm.c | 410 --------
collie/farm/farm.h | 83 --
collie/farm/object_tree.c | 124 ---
collie/farm/sha1_file.c | 148 ---
collie/farm/slice.c | 109 --
collie/farm/snap.c | 127 ---
collie/farm/trunk.c | 84 --
collie/node.c | 417 --------
collie/trace.c | 387 -------
collie/treeview.c | 188 ----
collie/treeview.h | 21 -
collie/vdi.c | 2160 --------------------------------------
configure.ac | 6 +-
debian/sheepdog.bash-completion | 2 +-
dog/Makefile.am | 56 +
dog/cluster.c | 524 +++++++++
dog/common.c | 324 ++++++
dog/dog.c | 433 ++++++++
dog/dog.h | 97 ++
dog/farm/farm.c | 410 ++++++++
dog/farm/farm.h | 83 ++
dog/farm/object_tree.c | 124 +++
dog/farm/sha1_file.c | 148 +++
dog/farm/slice.c | 109 ++
dog/farm/snap.c | 127 +++
dog/farm/trunk.c | 84 ++
dog/node.c | 417 ++++++++
dog/trace.c | 387 +++++++
dog/treeview.c | 188 ++++
dog/treeview.h | 21 +
dog/vdi.c | 2160 ++++++++++++++++++++++++++++++++++++++
include/internal_proto.h | 4 +-
lib/logger.c | 2 +-
man/Makefile.am | 10 +-
man/collie.8.in | 37 -
man/dog.8.in | 37 +
man/sheep.8.in | 4 +-
man/sheepfs.8.in | 4 +-
script/Makefile.am | 2 +-
script/bash_completion_collie | 303 ------
script/bash_completion_dog | 303 ++++++
sheep/sheep.c | 2 +-
sheep/store.c | 2 +-
sheepdog.spec.in | 4 +-
sheepfs/cluster.c | 2 +-
sheepfs/node.c | 4 +-
sheepfs/vdi.c | 2 +-
sheepfs/volume.c | 2 +-
tests/dynamorio/journaling/01.sh | 4 +-
tests/functional/001 | 2 +-
tests/functional/002 | 2 +-
tests/functional/003 | 2 +-
tests/functional/004 | 2 +-
tests/functional/005 | 4 +-
tests/functional/006 | 2 +-
tests/functional/007 | 6 +-
tests/functional/008 | 6 +-
tests/functional/009 | 6 +-
tests/functional/010 | 32 +-
tests/functional/011 | 2 +-
tests/functional/012 | 2 +-
tests/functional/014 | 12 +-
tests/functional/015 | 48 +-
tests/functional/016 | 10 +-
tests/functional/017 | 2 +-
tests/functional/018 | 8 +-
tests/functional/019 | 6 +-
tests/functional/020 | 4 +-
tests/functional/022 | 2 +-
tests/functional/023 | 4 +-
tests/functional/024 | 2 +-
tests/functional/025 | 4 +-
tests/functional/026 | 6 +-
tests/functional/027 | 4 +-
tests/functional/028 | 18 +-
tests/functional/029 | 12 +-
tests/functional/030 | 62 +-
tests/functional/031 | 4 +-
tests/functional/032 | 8 +-
tests/functional/033 | 8 +-
tests/functional/034 | 10 +-
tests/functional/035 | 12 +-
tests/functional/036 | 6 +-
tests/functional/037 | 8 +-
tests/functional/038 | 8 +-
tests/functional/039 | 34 +-
tests/functional/040 | 2 +-
tests/functional/041 | 46 +-
tests/functional/042 | 14 +-
tests/functional/043 | 24 +-
tests/functional/044 | 42 +-
tests/functional/045 | 8 +-
tests/functional/046 | 24 +-
tests/functional/047 | 10 +-
tests/functional/048 | 20 +-
tests/functional/049 | 6 +-
tests/functional/050 | 8 +-
tests/functional/051 | 6 +-
tests/functional/052 | 16 +-
tests/functional/053 | 10 +-
tests/functional/054 | 6 +-
tests/functional/055 | 26 +-
tests/functional/056 | 18 +-
tests/functional/057 | 24 +-
tests/functional/058 | 8 +-
tests/functional/059 | 8 +-
tests/functional/060 | 16 +-
tests/functional/061 | 4 +-
tests/functional/062 | 36 +-
tests/functional/063 | 12 +-
tests/functional/064 | 16 +-
tests/functional/065 | 6 +-
tests/functional/066 | 12 +-
tests/functional/067 | 4 +-
tests/functional/068 | 6 +-
tests/functional/069 | 6 +-
tests/functional/070 | 4 +-
tests/functional/071 | 6 +-
tests/functional/072 | 6 +-
tests/functional/check | 2 +-
tests/functional/common.config | 4 +-
tests/functional/common.filter | 2 +-
tests/functional/common.rc | 24 +-
tests/functional/group | 4 +-
tests/unit/Makefile.am | 2 +-
tests/unit/collie/Makefile.am | 23 -
tests/unit/collie/mock_collie.c | 25 -
tests/unit/collie/test_common.c | 56 -
tests/unit/dog/Makefile.am | 23 +
tests/unit/dog/mock_dog.c | 25 +
tests/unit/dog/test_common.c | 56 +
140 files changed, 6613 insertions(+), 6613 deletions(-)
delete mode 100644 collie/Makefile.am
delete mode 100644 collie/cluster.c
delete mode 100644 collie/collie.c
delete mode 100644 collie/collie.h
delete mode 100644 collie/common.c
delete mode 100644 collie/farm/farm.c
delete mode 100644 collie/farm/farm.h
delete mode 100644 collie/farm/object_tree.c
delete mode 100644 collie/farm/sha1_file.c
delete mode 100644 collie/farm/slice.c
delete mode 100644 collie/farm/snap.c
delete mode 100644 collie/farm/trunk.c
delete mode 100644 collie/node.c
delete mode 100644 collie/trace.c
delete mode 100644 collie/treeview.c
delete mode 100644 collie/treeview.h
delete mode 100644 collie/vdi.c
create mode 100644 dog/Makefile.am
create mode 100644 dog/cluster.c
create mode 100644 dog/common.c
create mode 100644 dog/dog.c
create mode 100644 dog/dog.h
create mode 100644 dog/farm/farm.c
create mode 100644 dog/farm/farm.h
create mode 100644 dog/farm/object_tree.c
create mode 100644 dog/farm/sha1_file.c
create mode 100644 dog/farm/slice.c
create mode 100644 dog/farm/snap.c
create mode 100644 dog/farm/trunk.c
create mode 100644 dog/node.c
create mode 100644 dog/trace.c
create mode 100644 dog/treeview.c
create mode 100644 dog/treeview.h
create mode 100644 dog/vdi.c
delete mode 100644 man/collie.8.in
create mode 100644 man/dog.8.in
delete mode 100644 script/bash_completion_collie
create mode 100644 script/bash_completion_dog
delete mode 100644 tests/unit/collie/Makefile.am
delete mode 100644 tests/unit/collie/mock_collie.c
delete mode 100644 tests/unit/collie/test_common.c
create mode 100644 tests/unit/dog/Makefile.am
create mode 100644 tests/unit/dog/mock_dog.c
create mode 100644 tests/unit/dog/test_common.c
diff --git a/.gitignore b/.gitignore
index fdbf367..69aca9d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,12 +31,12 @@ GSYMS
#
# programs
#
-collie/collie
+dog/dog
sheep/sheep
sheepfs/sheepfs
shepherd/shepherd
tools/zk_control
-tests/unit/collie/test_common
+tests/unit/dog/test_common
tests/unit/sheep/test_vdi
tests/unit/sheep/test_cluster_driver
@@ -73,7 +73,7 @@ tests/*.out.bad
*.patch
man/sheep.8
-man/collie.8
+man/dog.8
man/sheepfs.8
*.deb
diff --git a/INSTALL b/INSTALL
index 1a23091..28fbb55 100644
--- a/INSTALL
+++ b/INSTALL
@@ -65,7 +65,7 @@ Installing from source
$ make rpm
$ sudo rpm -ivh x86_64/sheepdog-0.*
-Please read the README file, the sheep(8), collie(8) or sheepfs(8) man page for
+Please read the README file, the sheep(8), dog(8) or sheepfs(8) man page for
further usage instructions.
===============================================================================
diff --git a/Makefile.am b/Makefile.am
index beafa1c..915ce54 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -17,7 +17,7 @@ sheepdogsysconfdir = ${SHEEPDOGCONFDIR}
sheepdogsysconf_DATA =
-SUBDIRS = lib collie sheep include script shepherd tools
+SUBDIRS = lib dog sheep include script shepherd tools
if BUILD_SHEEPFS
SUBDIRS += sheepfs
@@ -92,7 +92,7 @@ sparse:
CHECK_STYLE=../script/checkpatch.pl -f --no-summary --terse
check-style:
- @for dir in lib collie sheep include sheepfs; do \
+ @for dir in lib dog sheep include sheepfs; do \
make -C $$dir check-style CHECK_STYLE="$(CHECK_STYLE)"; \
done
@@ -100,12 +100,12 @@ if BUILD_COVERAGE
coverage: clean check
@rm -rf coverage
- @for dir in collie sheep tests/unit/collie tests/unit/sheep ; do\
+ @for dir in dog sheep tests/unit/dog tests/unit/sheep ; do\
$(MAKE) -C $$dir coverage; \
done
- @lcov -a collie/collie.info -a sheep/sheep.info \
- -a tests/unit/collie/collie.info -a tests/unit/sheep/sheep.info \
+ @lcov -a dog/dog.info -a sheep/sheep.info \
+ -a tests/unit/dog/dog.info -a tests/unit/sheep/sheep.info \
-o sheep.info && \
lcov -r sheep.info /usr/include/\* -o sheep.info && \
lcov -r sheep.info tests/unit/\* -o sheep.info && \
diff --git a/README b/README
index f130e86..8561db3 100644
--- a/README
+++ b/README
@@ -82,7 +82,7 @@ Usage
2. Make fs
- $ collie cluster format --copies=3
+ $ dog cluster format --copies=3
--copies specifies the number of default data redundancy. In this case,
the replicated data is stored on three machines.
@@ -91,7 +91,7 @@ Usage
Following list shows that Sheepdog is running on 32 nodes.
- $ collie node list
+ $ dog node list
Idx Node id (FNV-1a) - Host:Port
------------------------------------------------
0 0308164db75cff7e - 10.68.13.15:7000
@@ -138,7 +138,7 @@ Usage
3. See Sheepdog images by the following command.
- $ collie vdi list
+ $ dog vdi list
name id size used shared creation time object id
--------------------------------------------------------------------
Bob 0 2.0 GB 1.6 GB 0.0 MB 2010-03-23 16:16 80000
@@ -151,7 +151,7 @@ Usage
2. Following command checks used images.
- $ collie vm list
+ $ dog vm list
Name |Vdi size |Allocated| Shared | Status
----------------+---------+---------+---------+------------
Bob | 2.0 GB| 1.6 GB| 0.0 MB| running on xx.xx.xx.xx
@@ -167,7 +167,7 @@ Usage
2. After getting snapshot, a new virtual machine images are added as a not-
current image.
- $ collie vdi list
+ $ dog vdi list
name id size used shared creation time object id
--------------------------------------------------------------------
Bob 0 2.0 GB 1.6 GB 0.0 MB 2010-03-23 16:16 80000
@@ -185,7 +185,7 @@ Usage
2. Charlie's image is added to the virtual machine list.
- $ collie vdi list
+ $ dog vdi list
name id size used shared creation time object id
--------------------------------------------------------------------
Bob 0 2.0 GB 1.6 GB 0.0 MB 2010-03-23 16:16 80000
diff --git a/collie/Makefile.am b/collie/Makefile.am
deleted file mode 100644
index 2b57f5a..0000000
--- a/collie/Makefile.am
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-# Copyright 2010 Red Hat, Inc.
-#
-# This program 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.
-#
-# This program 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; see the file COPYING. If not, write to
-# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-
-MAINTAINERCLEANFILES = Makefile.in
-
-AM_CFLAGS =
-
-INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
-
-sbin_PROGRAMS = collie
-
-collie_SOURCES = farm/object_tree.c farm/sha1_file.c farm/snap.c \
- farm/trunk.c farm/farm.c farm/slice.c \
- collie.c common.c treeview.c vdi.c node.c cluster.c
-
-if BUILD_TRACE
-collie_SOURCES += trace.c
-override CFLAGS := $(subst -pg,,$(CFLAGS))
-endif
-
-collie_LDADD = ../lib/libsheepdog.a -lpthread
-collie_DEPENDENCIES = ../lib/libsheepdog.a
-
-noinst_HEADERS = treeview.h collie.h farm/farm.h
-
-EXTRA_DIST =
-
-all-local:
- @echo Built collie
-
-clean-local:
- rm -f collie *.o gmon.out *.da *.bb *.bbg
-
-# support for GNU Flymake
-check-syntax:
- $(COMPILE) -fsyntax-only $(CHK_SOURCES)
-
-check-style:
- @$(CHECK_STYLE) $(collie_SOURCES) $(noinst_HEADERS)
-
-coverage:
- @lcov -d . -c -o collie.info
diff --git a/collie/cluster.c b/collie/cluster.c
deleted file mode 100644
index ef87bc4..0000000
--- a/collie/cluster.c
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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 <time.h>
-#include <string.h>
-#include <ctype.h>
-#include <sys/time.h>
-
-#include "collie.h"
-#include "farm/farm.h"
-
-static struct sd_option cluster_options[] = {
- {'b', "store", true, "specify backend store"},
- {'c', "copies", true, "specify the default data redundancy (number of copies)"},
- {'f', "force", false, "do not prompt for confirmation"},
-
- { 0, NULL, false, NULL },
-};
-
-static struct cluster_cmd_data {
- int copies;
- bool force;
- char name[STORE_LEN];
-} cluster_cmd_data;
-
-#define DEFAULT_STORE "plain"
-
-static int list_store(void)
-{
- int ret;
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- char buf[512] = { 0 };
-
- sd_init_req(&hdr, SD_OP_GET_STORE_LIST);
- hdr.data_length = 512;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, buf);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("Restore failed: %s", sd_strerror(rsp->result));
- return EXIT_FAILURE;
- }
-
- printf("Available stores:\n");
- printf("---------------------------------------\n");
- printf("%s\n", buf);
- return EXIT_SYSFAIL;
-}
-
-static bool no_vdi(const unsigned long *vdis)
-{
- return find_next_bit(vdis, SD_NR_VDIS, 0) == SD_NR_VDIS;
-}
-
-#define FORMAT_PRINT \
- " __\n" \
- " ()'`;\n" \
- " /\\|`\n" \
- " / | Caution! The cluster is not empty.\n" \
- "(/_)_|_ Are you sure you want to continue? [yes/no]: "
-
-static int cluster_format(int argc, char **argv)
-{
- int ret;
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- struct timeval tv;
- char store_name[STORE_LEN];
- static DECLARE_BITMAP(vdi_inuse, SD_NR_VDIS);
-
- sd_init_req(&hdr, SD_OP_READ_VDIS);
- hdr.data_length = sizeof(vdi_inuse);
-
- ret = collie_exec_req(sdhost, sdport, &hdr, &vdi_inuse);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- if (!no_vdi(vdi_inuse))
- confirm(FORMAT_PRINT);
-
- gettimeofday(&tv, NULL);
-
- sd_init_req(&hdr, SD_OP_MAKE_FS);
- hdr.cluster.copies = cluster_cmd_data.copies;
- hdr.cluster.ctime = (uint64_t) tv.tv_sec << 32 | tv.tv_usec * 1000;
-
- if (strlen(cluster_cmd_data.name))
- pstrcpy(store_name, STORE_LEN, cluster_cmd_data.name);
- else
- pstrcpy(store_name, STORE_LEN, DEFAULT_STORE);
- hdr.data_length = strlen(store_name) + 1;
- hdr.flags |= SD_FLAG_CMD_WRITE;
-
- printf("using backend %s store\n", store_name);
- ret = collie_exec_req(sdhost, sdport, &hdr, store_name);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("Format failed: %s", sd_strerror(rsp->result));
- if (rsp->result == SD_RES_NO_STORE)
- return list_store();
- else
- return EXIT_SYSFAIL;
- }
-
- return EXIT_SUCCESS;
-}
-
-static int cluster_info(int argc, char **argv)
-{
- int i, ret;
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- struct epoch_log *logs;
- int nr_logs, log_length;
- time_t ti, ct;
- struct tm tm;
- char time_str[128];
-
- log_length = sd_epoch * sizeof(struct epoch_log);
- logs = xmalloc(log_length);
-
- sd_init_req(&hdr, SD_OP_STAT_CLUSTER);
- hdr.data_length = log_length;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, logs);
- if (ret < 0)
- goto error;
-
- if (!raw_output)
- printf("Cluster status: ");
- if (rsp->result == SD_RES_SUCCESS)
- printf("running, auto-recovery %s\n", logs->disable_recovery ?
- "disabled" : "enabled");
- else
- printf("%s\n", sd_strerror(rsp->result));
-
- if (!raw_output && rsp->data_length > 0) {
- ct = logs[0].ctime >> 32;
- printf("\nCluster created at %s\n", ctime(&ct));
- printf("Epoch Time Version\n");
- }
-
- nr_logs = rsp->data_length / sizeof(struct epoch_log);
- for (i = 0; i < nr_logs; i++) {
- int j;
- const struct sd_node *entry;
-
- ti = logs[i].time;
- if (raw_output) {
- snprintf(time_str, sizeof(time_str), "%" PRIu64, (uint64_t) ti);
- } else {
- localtime_r(&ti, &tm);
- strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm);
- }
-
- printf(raw_output ? "%s %d" : "%s %6d", time_str, logs[i].epoch);
- printf(" [");
- for (j = 0; j < logs[i].nr_nodes; j++) {
- entry = logs[i].nodes + j;
- printf("%s%s",
- (j == 0) ? "" : ", ",
- addr_to_str(entry->nid.addr, entry->nid.port));
- }
- printf("]\n");
- }
-
- free(logs);
- return EXIT_SUCCESS;
-error:
- free(logs);
- return EXIT_SYSFAIL;
-}
-
-static int cluster_shutdown(int argc, char **argv)
-{
- int ret;
- struct sd_req hdr;
-
- sd_init_req(&hdr, SD_OP_SHUTDOWN);
-
- ret = send_light_req(&hdr, sdhost, sdport);
- if (ret) {
- sd_err("failed to execute request");
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-static void print_list(void *buf, unsigned len)
-{
- struct snap_log *log_buf = (struct snap_log *)buf;
- unsigned nr = len / sizeof(struct snap_log);
-
- printf("Index\t\tTag\t\tSnapshot Time\n");
- for (unsigned i = 0; i < nr; i++, log_buf++) {
- time_t *t = (time_t *)&log_buf->time;
- printf("%d\t\t", log_buf->idx);
- printf("%s\t\t", log_buf->tag);
- printf("%s", ctime(t));
- }
-}
-
-static int list_snapshot(int argc, char **argv)
-{
- char *path = argv[optind++];
- void *buf = NULL;
- int log_nr;
- int ret = EXIT_SYSFAIL;
-
- if (farm_init(path) != SD_RES_SUCCESS)
- goto out;
-
- buf = snap_log_read(&log_nr);
- if (!buf)
- goto out;
-
- print_list(buf, log_nr * sizeof(struct snap_log));
- ret = EXIT_SUCCESS;
-out:
- if (ret)
- sd_err("Fail to list snapshot.");
- free(buf);
- return ret;
-}
-
-static void fill_object_tree(uint32_t vid, const char *name, const char *tag,
- uint32_t snapid, uint32_t flags,
- const struct sd_inode *i, void *data)
-{
- uint64_t vdi_oid = vid_to_vdi_oid(vid), vmstate_oid;
- int nr_vmstate_object;
-
- /* ignore active vdi */
- if (!vdi_is_snapshot(i))
- return;
-
- /* fill vdi object id */
- object_tree_insert(vdi_oid, i->nr_copies);
-
- /* fill data object id */
- for (uint64_t idx = 0; idx < MAX_DATA_OBJS; idx++) {
- if (i->data_vdi_id[idx]) {
- uint64_t oid = vid_to_data_oid(i->data_vdi_id[idx],
- idx);
- object_tree_insert(oid, i->nr_copies);
- }
- }
-
- /* fill vmstate object id */
- nr_vmstate_object = DIV_ROUND_UP(i->vm_state_size, SD_DATA_OBJ_SIZE);
- for (int idx = 0; idx < nr_vmstate_object; idx++) {
- vmstate_oid = vid_to_vmstate_oid(vid, idx);
- object_tree_insert(vmstate_oid, i->nr_copies);
- }
-}
-
-static int save_snapshot(int argc, char **argv)
-{
- char *tag = argv[optind++];
- char *path, *p;
- int ret = EXIT_SYSFAIL, uninitialized_var(unused);
-
- unused = strtol(tag, &p, 10);
- if (tag != p) {
- sd_err("Tag should not start with number.");
- return EXIT_USAGE;
- }
-
- if (!argv[optind]) {
- sd_err("Please specify the path to save snapshot.");
- return EXIT_USAGE;
- }
- path = argv[optind];
-
- if (farm_init(path) != SD_RES_SUCCESS)
- goto out;
-
- if (farm_contain_snapshot(0, tag)) {
- sd_err("Snapshot tag has already been used for another"
- " snapshot, please, use another one.");
- goto out;
- }
-
- if (parse_vdi(fill_object_tree, SD_INODE_SIZE, NULL) != SD_RES_SUCCESS)
- goto out;
-
- if (farm_save_snapshot(tag) != SD_RES_SUCCESS)
- goto out;
-
- ret = EXIT_SUCCESS;
-out:
- if (ret)
- sd_err("Fail to save snapshot to path: %s.", path);
- object_tree_free();
- return ret;
-}
-
-static int load_snapshot(int argc, char **argv)
-{
- char *tag = argv[optind++];
- char *path, *p;
- uint32_t idx;
- int ret = EXIT_SYSFAIL;
-
- idx = strtol(tag, &p, 10);
- if (tag == p)
- idx = 0;
-
- if (!argv[optind]) {
- sd_err("Please specify the path to save snapshot.");
- return EXIT_USAGE;
- }
- path = argv[optind];
-
- if (farm_init(path) != SD_RES_SUCCESS)
- goto out;
-
- if (!farm_contain_snapshot(idx, tag)) {
- sd_err("Snapshot index or tag does not exist.");
- goto out;
- }
-
- if (cluster_format(0, NULL) != SD_RES_SUCCESS)
- goto out;
-
- if (farm_load_snapshot(idx, tag) != SD_RES_SUCCESS)
- goto out;
-
- ret = EXIT_SUCCESS;
-out:
- if (ret)
- sd_err("Fail to load snapshot");
- return ret;
-}
-
-#define RECOVER_PRINT \
- "Caution! Please try starting all the cluster nodes normally before\n" \
- "running this command.\n\n" \
- "The cluster may need to be force recovered if:\n" \
- " - the master node fails to start because of epoch mismatch; or\n" \
- " - some nodes fail to start after a cluster shutdown.\n\n" \
- "Are you sure you want to continue? [yes/no]: "
-
-static int cluster_force_recover(int argc, char **argv)
-{
- int ret;
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- char str[123] = {'\0'};
- struct sd_node nodes[SD_MAX_NODES];
-
- if (!cluster_cmd_data.force) {
- int i, l;
- printf(RECOVER_PRINT);
- ret = scanf("%s", str);
- if (ret < 0)
- return EXIT_SYSFAIL;
- l = strlen(str);
- for (i = 0; i < l; i++)
- str[i] = tolower(str[i]);
- if (strncmp(str, "yes", 3) != 0)
- return EXIT_SUCCESS;
- }
-
- sd_init_req(&hdr, SD_OP_FORCE_RECOVER);
- hdr.data_length = sizeof(nodes);
-
- ret = collie_exec_req(sdhost, sdport, &hdr, nodes);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("failed to execute request, %s",
- sd_strerror(rsp->result));
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-static int cluster_disable_recover(int argc, char **argv)
-{
- int ret;
- struct sd_req hdr;
-
- sd_init_req(&hdr, SD_OP_DISABLE_RECOVER);
-
- ret = send_light_req(&hdr, sdhost, sdport);
- if (ret)
- return EXIT_FAILURE;
-
- printf("Cluster recovery: disable\n");
- return EXIT_SUCCESS;
-}
-
-static int cluster_enable_recover(int argc, char **argv)
-{
- int ret;
- struct sd_req hdr;
-
- sd_init_req(&hdr, SD_OP_ENABLE_RECOVER);
-
- ret = send_light_req(&hdr, sdhost, sdport);
- if (ret)
- return EXIT_FAILURE;
-
- printf("Cluster recovery: enable\n");
- return EXIT_SUCCESS;
-}
-
-/* Subcommand list of recover */
-static struct subcommand cluster_recover_cmd[] = {
- {"force", NULL, NULL, "force recover cluster immediately",
- NULL, 0, cluster_force_recover},
- {"enable", NULL, NULL, "enable automatic recovery and "
- "run once recover if necessary",
- NULL, 0, cluster_enable_recover},
- {"disable", NULL, NULL, "disable automatic recovery",
- NULL, 0, cluster_disable_recover},
- {NULL},
-};
-
-static int cluster_recover(int argc, char **argv)
-{
- return do_generic_subcommand(cluster_recover_cmd, argc, argv);
-}
-
-/* Subcommand list of snapshot */
-static struct subcommand cluster_snapshot_cmd[] = {
- {"save", NULL, "h", "save snapshot to localpath",
- NULL, CMD_NEED_ARG|CMD_NEED_NODELIST,
- save_snapshot, NULL},
- {"list", NULL, "h", "list snapshot of localpath",
- NULL, CMD_NEED_ARG, list_snapshot, NULL},
- {"load", NULL, "h", "load snapshot from localpath",
- NULL, CMD_NEED_ARG, load_snapshot, NULL},
- {NULL},
-};
-
-static int cluster_snapshot(int argc, char **argv)
-{
- return do_generic_subcommand(cluster_snapshot_cmd, argc, argv);
-}
-
-static int cluster_reweight(int argc, char **argv)
-{
- int ret;
- struct sd_req hdr;
-
- sd_init_req(&hdr, SD_OP_REWEIGHT);
- ret = send_light_req(&hdr, sdhost, sdport);
- if (ret)
- return EXIT_FAILURE;
- return EXIT_SUCCESS;
-}
-
-static struct subcommand cluster_cmd[] = {
- {"info", NULL, "aprh", "show cluster information",
- NULL, CMD_NEED_NODELIST, cluster_info, cluster_options},
- {"format", NULL, "bcaph", "create a Sheepdog store",
- NULL, 0, cluster_format, cluster_options},
- {"shutdown", NULL, "aph", "stop Sheepdog",
- NULL, 0, cluster_shutdown, cluster_options},
- {"snapshot", "<tag|idx> <path>", "aph", "snapshot/restore the cluster",
- cluster_snapshot_cmd, CMD_NEED_ARG,
- cluster_snapshot, cluster_options},
- {"recover", NULL, "afph",
- "See 'collie cluster recover' for more information",
- cluster_recover_cmd, CMD_NEED_ARG,
- cluster_recover, cluster_options},
- {"reweight", NULL, "aph", "reweight the cluster", NULL, 0,
- cluster_reweight, cluster_options},
- {NULL,},
-};
-
-static int cluster_parser(int ch, char *opt)
-{
- int copies;
- char *p;
-
- switch (ch) {
- case 'b':
- pstrcpy(cluster_cmd_data.name, sizeof(cluster_cmd_data.name),
- opt);
- break;
- case 'c':
- copies = strtol(opt, &p, 10);
- if (opt == p || copies < 1) {
- sd_err("There must be at least one copy of data");
- exit(EXIT_FAILURE);
- } else if (copies > SD_MAX_COPIES) {
- sd_err("Redundancy may not exceed %d copies",
- SD_MAX_COPIES);
- exit(EXIT_FAILURE);
- }
- cluster_cmd_data.copies = copies;
- break;
- case 'f':
- cluster_cmd_data.force = true;
- break;
- }
-
- return 0;
-}
-
-struct command cluster_command = {
- "cluster",
- cluster_cmd,
- cluster_parser
-};
diff --git a/collie/collie.c b/collie/collie.c
deleted file mode 100644
index f95f3c5..0000000
--- a/collie/collie.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Copyright (C) 2009-2011 Nippon Telegraph and Telephone Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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 <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-
-#include "sheepdog_proto.h"
-#include "sheep.h"
-#include "collie.h"
-#include "util.h"
-#include "sockfd_cache.h"
-
-#define EPOLL_SIZE 4096
-
-static const char program_name[] = "collie";
-/* default sdhost is "127.0.0.1" */
-uint8_t sdhost[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1 };
-int sdport = SD_LISTEN_PORT;
-bool highlight = true;
-bool raw_output;
-bool verbose;
-
-static const struct sd_option collie_options[] = {
-
- /* common options for all collie commands */
- {'a', "address", true, "specify the daemon address (default: localhost)"},
- {'p', "port", true, "specify the daemon port"},
- {'r', "raw", false, "raw output mode: omit headers, separate fields with\n"
- " single spaces and print all sizes in decimal bytes"},
- {'v', "verbose", false, "print more information than default"},
- {'h', "help", false, "display this help and exit"},
-
- { 0, NULL, false, NULL },
-};
-
-static void usage(const struct command *commands, int status);
-
-uint32_t sd_epoch;
-
-struct sd_node sd_nodes[SD_MAX_NODES];
-struct sd_vnode sd_vnodes[SD_MAX_VNODES];
-int sd_nodes_nr, sd_vnodes_nr;
-
-int update_node_list(int max_nodes)
-{
- int ret;
- unsigned int size;
- char *buf = NULL;
- struct sd_node *ent;
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
-
- size = sizeof(*ent) * max_nodes;
- buf = xzalloc(size);
- sd_init_req(&hdr, SD_OP_GET_NODE_LIST);
-
- hdr.data_length = size;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, buf);
- if (ret < 0)
- goto out;
-
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("Failed to update node list: %s",
- sd_strerror(rsp->result));
- ret = -1;
- goto out;
- }
-
- size = rsp->data_length;
- sd_nodes_nr = size / sizeof(*ent);
- if (sd_nodes_nr == 0) {
- sd_err("There are no active sheep daemons");
- exit(EXIT_FAILURE);
- }
-
- /* FIXME */
- if (sd_nodes_nr > max_nodes) {
- ret = -1;
- goto out;
- }
-
- memcpy(sd_nodes, buf, size);
- sd_vnodes_nr = nodes_to_vnodes(sd_nodes, sd_nodes_nr, sd_vnodes);
- sd_epoch = hdr.epoch;
-out:
- if (buf)
- free(buf);
-
- return ret;
-}
-
-static int (*command_parser)(int, char *);
-static int (*command_fn)(int, char **);
-static const char *command_opts;
-static const char *command_arg;
-static const char *command_desc;
-static struct sd_option *command_options;
-
-static const struct sd_option *find_opt(int ch)
-{
- const struct sd_option *opt;
-
- /* search for common options */
- sd_for_each_option(opt, collie_options) {
- if (opt->ch == ch)
- return opt;
- }
-
- /* search for self options */
- if (command_options) {
- sd_for_each_option(opt, command_options) {
- if (opt->ch == ch)
- return opt;
- }
- }
-
- sd_err("Internal error");
- exit(EXIT_SYSFAIL);
-}
-
-static void init_commands(const struct command **commands)
-{
- static struct command *cmds;
- struct command command_list[] = {
- vdi_command,
- node_command,
- cluster_command,
- trace_command,
- {NULL,}
- };
-
- if (!cmds) {
- cmds = (struct command *)xmalloc(sizeof(command_list));
- memcpy(cmds, command_list, sizeof(command_list));
- }
-
- *commands = cmds;
- return;
-}
-
-static const struct subcommand *find_subcmd(const char *cmd, const char *subcmd)
-{
- int i, j;
- const struct command *commands;
- const struct subcommand *sub;
-
- init_commands(&commands);
-
- for (i = 0; commands[i].name; i++) {
- if (!strcmp(commands[i].name, cmd)) {
- sub = commands[i].sub;
- for (j = 0; sub[j].name; j++) {
- if (!strcmp(sub[j].name, subcmd))
- return &sub[j];
- }
- }
- }
-
- return NULL;
-}
-
-static unsigned long setup_commands(const struct command *commands,
- char *cmd, char *subcmd)
-{
- int i;
- bool found = false;
- struct subcommand *s;
- unsigned long flags = 0;
-
- for (i = 0; commands[i].name; i++) {
- if (!strcmp(commands[i].name, cmd)) {
- found = true;
- if (commands[i].parser)
- command_parser = commands[i].parser;
- break;
- }
- }
-
- if (!found) {
- if (cmd && strcmp(cmd, "help") && strcmp(cmd, "--help") &&
- strcmp(cmd, "-h")) {
- sd_err("Invalid command '%s'", cmd);
- usage(commands, EXIT_USAGE);
- }
- usage(commands, 0);
- }
-
- for (s = commands[i].sub; subcmd && s->name; s++) {
- if (!strcmp(s->name, subcmd)) {
- command_fn = s->fn;
- command_opts = s->opts;
- command_arg = s->arg;
- command_desc = s->desc;
- command_options = s->options;
- flags = s->flags;
- break;
- }
- }
-
- if (!command_fn) {
- if (subcmd && strcmp(subcmd, "help") &&
- strcmp(subcmd, "--help") && strcmp(subcmd, "-h"))
- sd_err("Invalid command '%s %s'", cmd, subcmd);
- sd_err("Available %s commands:", cmd);
- for (s = commands[i].sub; s->name; s++)
- sd_err(" %s %s", cmd, s->name);
- exit(EXIT_USAGE);
- }
-
- return flags;
-}
-
-static void usage(const struct command *commands, int status)
-{
- int i;
- struct subcommand *s;
- char name[64];
-
- if (status)
- sd_err("Try '%s --help' for more information.", program_name);
- else {
- printf("Sheepdog administrator utility\n");
- printf("Usage: %s <command> <subcommand> [options]\n", program_name);
- printf("\nAvailable commands:\n");
- for (i = 0; commands[i].name; i++) {
- for (s = commands[i].sub; s->name; s++) {
- snprintf(name, sizeof(name), "%s %s",
- commands[i].name, s->name);
- printf(" %-24s%s\n", name, s->desc);
- }
- }
- printf("\n");
- printf("For more information, run "
- "'%s <command> <subcommand> --help'.\n", program_name);
- }
- exit(status);
-}
-
-void subcommand_usage(char *cmd, char *subcmd, int status)
-{
- int i, n, len = strlen(command_opts);
- const struct sd_option *sd_opt;
- const struct subcommand *sub, *subsub;
- char name[64];
-
- printf("Usage: %s %s %s", program_name, cmd, subcmd);
-
- /* Show subcmd's subcommands if necessary */
- sub = find_subcmd(cmd, subcmd);
- subsub = sub->sub;
- if (subsub) {
- n = 0;
- while (subsub[n].name)
- n++;
- if (n == 1)
- printf(" %s", subsub[0].name);
- else if (n > 1) {
- printf(" {%s", subsub[0].name);
- for (i = 1; i < n; i++)
- printf("|%s", subsub[i].name);
- printf("}");
- }
- }
-
- for (i = 0; i < len; i++) {
- sd_opt = find_opt(command_opts[i]);
- if (sd_opt->has_arg)
- printf(" [-%c %s]", sd_opt->ch, sd_opt->name);
- else
- printf(" [-%c]", sd_opt->ch);
- }
- if (command_arg)
- printf(" %s", command_arg);
-
- printf("\n");
- if (subsub) {
- printf("Available subcommands:\n");
- for (i = 0; subsub[i].name; i++)
- printf(" %-24s%s\n", subsub[i].name, subsub[i].desc);
-
- }
-
- printf("Options:\n");
- for (i = 0; i < len; i++) {
- sd_opt = find_opt(command_opts[i]);
- snprintf(name, sizeof(name), "-%c, --%s",
- sd_opt->ch, sd_opt->name);
- printf(" %-24s%s\n", name, sd_opt->desc);
- }
-
- exit(status);
-}
-
-static const struct sd_option *build_sd_options(const char *opts)
-{
- static struct sd_option sd_opts[256], *p;
- int i, len = strlen(opts);
-
- p = sd_opts;
- for (i = 0; i < len; i++)
- *p++ = *find_opt(opts[i]);
- memset(p, 0, sizeof(struct sd_option));
-
- return sd_opts;
-}
-
-static void crash_handler(int signo)
-{
- sd_err("collie exits unexpectedly (%s).", strsignal(signo));
-
- sd_backtrace();
-
- /*
- * OOM raises SIGABRT in xmalloc but the administrator expects
- * that collie exits with EXIT_SYSFAIL. We have to give up
- * dumping a core file in this case.
- */
- if (signo == SIGABRT)
- exit(EXIT_SYSFAIL);
-
- reraise_crash_signal(signo, EXIT_SYSFAIL);
-}
-
-static size_t get_nr_nodes(void)
-{
- return sd_nodes_nr;
-}
-
-int main(int argc, char **argv)
-{
- int ch, longindex, ret;
- unsigned long flags;
- struct option *long_options;
- const struct command *commands;
- const char *short_options;
- char *p;
- const struct sd_option *sd_opts;
-
- install_crash_handler(crash_handler);
-
- init_commands(&commands);
-
- if (argc < 2)
- usage(commands, 0);
-
- flags = setup_commands(commands, argv[1], argv[2]);
-
- optind = 3;
-
- sd_opts = build_sd_options(command_opts);
- long_options = build_long_options(sd_opts);
- short_options = build_short_options(sd_opts);
-
- while ((ch = getopt_long(argc, argv, short_options, long_options,
- &longindex)) >= 0) {
-
- switch (ch) {
- case 'a':
- if (!str_to_addr(optarg, sdhost)) {
- sd_err("Invalid ip address %s", optarg);
- return EXIT_FAILURE;
- }
- break;
- case 'p':
- sdport = strtol(optarg, &p, 10);
- if (optarg == p || sdport < 1 || sdport > UINT16_MAX) {
- sd_err("Invalid port number '%s'", optarg);
- exit(EXIT_USAGE);
- }
- break;
- case 'r':
- raw_output = true;
- break;
- case 'v':
- verbose = true;
- break;
- case 'h':
- subcommand_usage(argv[1], argv[2], EXIT_SUCCESS);
- break;
- case '?':
- usage(commands, EXIT_USAGE);
- break;
- default:
- if (command_parser)
- command_parser(ch, optarg);
- else
- usage(commands, EXIT_USAGE);
- break;
- }
- }
-
- if (!is_stdout_console() || raw_output)
- highlight = false;
-
- if (flags & CMD_NEED_NODELIST) {
- ret = update_node_list(SD_MAX_NODES);
- if (ret < 0) {
- sd_err("Failed to get node list");
- exit(EXIT_SYSFAIL);
- }
- }
-
- if (flags & CMD_NEED_ARG && argc == optind)
- subcommand_usage(argv[1], argv[2], EXIT_USAGE);
-
- if (init_event(EPOLL_SIZE) < 0)
- exit(EXIT_SYSFAIL);
-
- if (init_work_queue(get_nr_nodes) != 0) {
- sd_err("Failed to init work queue");
- exit(EXIT_SYSFAIL);
- }
-
- if (sockfd_init()) {
- sd_err("sockfd_init() failed");
- exit(EXIT_SYSFAIL);
- }
-
- ret = command_fn(argc, argv);
- if (ret == EXIT_USAGE)
- subcommand_usage(argv[1], argv[2], EXIT_USAGE);
- return ret;
-}
diff --git a/collie/collie.h b/collie/collie.h
deleted file mode 100644
index 5f6797d..0000000
--- a/collie/collie.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef __COLLIE_H__
-#define __COLLIE_H__
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-
-#include "sheepdog_proto.h"
-#include "sheep.h"
-#include "exits.h"
-#include "option.h"
-#include "work.h"
-#include "event.h"
-#include "config.h"
-
-#define CMD_NEED_NODELIST (1 << 0)
-#define CMD_NEED_ARG (1 << 1)
-
-#define UINT64_DECIMAL_SIZE 21
-
-struct command {
- const char *name;
- struct subcommand *sub;
- int (*parser)(int, char *);
-};
-
-struct subcommand {
- const char *name;
- const char *arg;
- const char *opts;
- const char *desc;
- struct subcommand *sub;
- unsigned long flags;
- int (*fn)(int, char **);
- struct sd_option *options;
-};
-void subcommand_usage(char *cmd, char *subcmd, int status);
-
-extern uint8_t sdhost[16];
-extern int sdport;
-extern bool highlight;
-extern bool raw_output;
-extern bool verbose;
-
-extern uint32_t sd_epoch;
-extern struct sd_node sd_nodes[SD_MAX_NODES];
-extern struct sd_vnode sd_vnodes[SD_MAX_VNODES];
-extern int sd_nodes_nr, sd_vnodes_nr;
-
-bool is_current(const struct sd_inode *i);
-char *size_to_str(uint64_t _size, char *str, int str_size);
-typedef void (*vdi_parser_func_t)(uint32_t vid, const char *name,
- const char *tag, uint32_t snapid,
- uint32_t flags,
- const struct sd_inode *i, void *data);
-int parse_vdi(vdi_parser_func_t func, size_t size, void *data);
-int sd_read_object(uint64_t oid, void *data, unsigned int datalen,
- uint64_t offset, bool direct);
-int sd_write_object(uint64_t oid, uint64_t cow_oid, void *data,
- unsigned int datalen, uint64_t offset, uint32_t flags,
- int copies, bool create, bool direct);
-int collie_exec_req(const uint8_t *addr, int port, struct sd_req *hdr,
- void *data);
-int send_light_req(struct sd_req *hdr, const uint8_t *addr, int port);
-int do_generic_subcommand(struct subcommand *sub, int argc, char **argv);
-int update_node_list(int max_nodes);
-void confirm(const char *message);
-void work_queue_wait(struct work_queue *q);
-int do_vdi_create(const char *vdiname, int64_t vdi_size,
- uint32_t base_vid, uint32_t *vdi_id, bool snapshot,
- int nr_copies);
-void show_progress(uint64_t done, uint64_t total, bool raw);
-
-extern struct command vdi_command;
-extern struct command node_command;
-extern struct command cluster_command;
-
-#ifdef HAVE_TRACE
- extern struct command trace_command;
-#else
- #define trace_command {}
-#endif /* HAVE_TRACE */
-
-#endif
diff --git a/collie/common.c b/collie/common.c
deleted file mode 100644
index 3237608..0000000
--- a/collie/common.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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 "collie.h"
-#include "sha1.h"
-#include "sockfd_cache.h"
-
-char *size_to_str(uint64_t _size, char *str, int str_size)
-{
- const char *units[] = {"MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
- int i = 0;
- double size;
-
- if (raw_output) {
- snprintf(str, str_size, "%" PRIu64, _size);
- return str;
- }
-
- size = (double)_size;
- size /= 1024 * 1024;
- while (i < ARRAY_SIZE(units) - 1 && size >= 1024) {
- i++;
- size /= 1024;
- }
-
- if (size >= 10)
- snprintf(str, str_size, "%.0lf %s", size, units[i]);
- else
- snprintf(str, str_size, "%.1lf %s", size, units[i]);
-
- return str;
-}
-
-int sd_read_object(uint64_t oid, void *data, unsigned int datalen,
- uint64_t offset, bool direct)
-{
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- int ret;
-
- sd_init_req(&hdr, SD_OP_READ_OBJ);
- hdr.data_length = datalen;
-
- hdr.obj.oid = oid;
- hdr.obj.offset = offset;
- if (direct)
- hdr.flags |= SD_FLAG_CMD_DIRECT;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, data);
- if (ret < 0) {
- sd_err("Failed to read object %" PRIx64, oid);
- return SD_RES_EIO;
- }
-
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("Failed to read object %" PRIx64 " %s", oid,
- sd_strerror(rsp->result));
- return rsp->result;
- }
-
- untrim_zero_blocks(data, rsp->obj.offset, rsp->data_length, datalen);
-
- return SD_RES_SUCCESS;
-}
-
-int sd_write_object(uint64_t oid, uint64_t cow_oid, void *data,
- unsigned int datalen, uint64_t offset, uint32_t flags,
- int copies, bool create, bool direct)
-{
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- int ret;
-
- if (create)
- sd_init_req(&hdr, SD_OP_CREATE_AND_WRITE_OBJ);
- else
- sd_init_req(&hdr, SD_OP_WRITE_OBJ);
-
- hdr.data_length = datalen;
- hdr.flags = flags | SD_FLAG_CMD_WRITE;
- if (cow_oid)
- hdr.flags |= SD_FLAG_CMD_COW;
- if (direct)
- hdr.flags |= SD_FLAG_CMD_DIRECT;
-
- hdr.obj.copies = copies;
- hdr.obj.oid = oid;
- hdr.obj.cow_oid = cow_oid;
- hdr.obj.offset = offset;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, data);
- if (ret < 0) {
- sd_err("Failed to write object %" PRIx64, oid);
- return SD_RES_EIO;
- }
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("Failed to write object %" PRIx64 ": %s", oid,
- sd_strerror(rsp->result));
- return rsp->result;
- }
-
- return SD_RES_SUCCESS;
-}
-
-#define FOR_EACH_VDI(nr, vdis) FOR_EACH_BIT(nr, vdis, SD_NR_VDIS)
-
-int parse_vdi(vdi_parser_func_t func, size_t size, void *data)
-{
- int ret;
- unsigned long nr;
- static struct sd_inode i;
- struct sd_req req;
- static DECLARE_BITMAP(vdi_inuse, SD_NR_VDIS);
- unsigned int rlen = sizeof(vdi_inuse);
-
- sd_init_req(&req, SD_OP_READ_VDIS);
- req.data_length = sizeof(vdi_inuse);
-
- ret = collie_exec_req(sdhost, sdport, &req, &vdi_inuse);
- if (ret < 0)
- goto out;
-
- FOR_EACH_VDI(nr, vdi_inuse) {
- uint64_t oid;
- uint32_t snapid;
-
- oid = vid_to_vdi_oid(nr);
-
- memset(&i, 0, sizeof(i));
- ret = sd_read_object(oid, &i, SD_INODE_HEADER_SIZE, 0, true);
- if (ret != SD_RES_SUCCESS) {
- sd_err("Failed to read inode header");
- continue;
- }
-
- if (i.name[0] == '\0') /* this VDI has been deleted */
- continue;
-
- if (size > SD_INODE_HEADER_SIZE) {
- rlen = DIV_ROUND_UP(i.vdi_size, SD_DATA_OBJ_SIZE) *
- sizeof(i.data_vdi_id[0]);
- if (rlen > size - SD_INODE_HEADER_SIZE)
- rlen = size - SD_INODE_HEADER_SIZE;
-
- ret = sd_read_object(oid, ((char *)&i) + SD_INODE_HEADER_SIZE,
- rlen, SD_INODE_HEADER_SIZE, true);
-
- if (ret != SD_RES_SUCCESS) {
- sd_err("Failed to read inode");
- continue;
- }
- }
-
- snapid = vdi_is_snapshot(&i) ? i.snap_id : 0;
- func(i.vdi_id, i.name, i.tag, snapid, 0, &i, data);
- }
-
-out:
- return ret;
-}
-
-int collie_exec_req(const uint8_t *addr, int port, struct sd_req *hdr,
- void *buf)
-{
- struct node_id nid = {};
- struct sockfd *sfd;
- int ret;
-
- memcpy(nid.addr, addr, sizeof(nid.addr));
- nid.port = port;
-
- sfd = sockfd_cache_get(&nid);
- if (!sfd)
- return -1;
-
- /*
- * Retry forever for collie because
- * 1. We can't get the newest epoch
- * 2. Some operations might take unexpected long time
- */
- ret = exec_req(sfd->fd, hdr, buf, NULL, 0, UINT32_MAX);
-
- sockfd_cache_put(&nid, sfd);
-
- return ret ? -1 : 0;
-}
-
-/* Light request only contains header, without body content. */
-int send_light_req(struct sd_req *hdr, const uint8_t *addr, int port)
-{
- int ret = collie_exec_req(addr, port, hdr, NULL);
-
- if (ret == -1)
- return -1;
-
- if (ret != SD_RES_SUCCESS) {
- sd_err("Response's result: %s", sd_strerror(ret));
- return -1;
- }
-
- return 0;
-}
-
-int do_generic_subcommand(struct subcommand *sub, int argc, char **argv)
-{
- int i, ret;
-
- for (i = 0; sub[i].name; i++) {
- if (!strcmp(sub[i].name, argv[optind])) {
- unsigned long flags = sub[i].flags;
-
- if (flags & CMD_NEED_NODELIST) {
- ret = update_node_list(SD_MAX_NODES);
- if (ret < 0) {
- sd_err("Failed to get node list");
- exit(EXIT_SYSFAIL);
- }
- }
-
- if (flags & CMD_NEED_ARG && argc < 5)
- subcommand_usage(argv[1], argv[2], EXIT_USAGE);
- optind++;
- ret = sub[i].fn(argc, argv);
- if (ret == EXIT_USAGE)
- subcommand_usage(argv[1], argv[2], EXIT_USAGE);
- return ret;
- }
- }
-
- subcommand_usage(argv[1], argv[2], EXIT_FAILURE);
- return EXIT_FAILURE;
-}
-
-void confirm(const char *message)
-{
- char input[8] = "";
- char *ret;
-
- printf("%s", message);
- ret = fgets(input, sizeof(input), stdin);
- if (ret == NULL || strncasecmp(input, "yes", 3) != 0)
- exit(EXIT_SUCCESS);
-}
-
-void work_queue_wait(struct work_queue *q)
-{
- while (!work_queue_empty(q))
- event_loop(-1);
-}
-
-#define DEFAULT_SCREEN_WIDTH 80
-
-static int get_screen_width(void)
-{
- struct winsize wsz;
-
- if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &wsz) < 0)
- return DEFAULT_SCREEN_WIDTH;
-
- return wsz.ws_col;
-}
-
-/*
- * Show prograss bar as follows.
- *
- * 45.0 % [===============> ] 180 MB / 400 MB
- */
-void show_progress(uint64_t done, uint64_t total, bool raw)
-{
- char done_str[256], total_str[256];
- int screen_width = get_screen_width();
- int bar_length = screen_width - 30;
- char *buf;
-
- if (!is_stdout_console())
- return;
- if (screen_width <= 0)
- return;
-
- printf("\r"); /* move to the beginning of the line */
-
- if (raw) {
- snprintf(done_str, sizeof(done_str), "%"PRIu64, done);
- snprintf(total_str, sizeof(total_str), "%"PRIu64, total);
- } else {
- size_to_str(done, done_str, sizeof(done_str));
- size_to_str(total, total_str, sizeof(total_str));
- }
-
- buf = xmalloc(screen_width + 1);
- snprintf(buf, screen_width, "%5.1lf %% [", (double)done / total * 100);
-
- for (int i = 0; i < bar_length; i++) {
- if (total * (i + 1) / bar_length <= done)
- strcat(buf, "=");
- else if (total * i / bar_length <= done &&
- done < total * (i + 1) / bar_length)
- strcat(buf, ">");
- else
- strcat(buf, " ");
- }
- snprintf(buf + strlen(buf), screen_width - strlen(buf),
- "] %s / %s", done_str, total_str);
-
- /* fill the rest of buffer with blank characters */
- memset(buf + strlen(buf), ' ', screen_width - strlen(buf));
- buf[screen_width] = '\0';
- printf("%s", buf);
-
- if (done == total)
- printf("\n");
-
- fflush(stdout);
-
- free(buf);
-}
diff --git a/collie/farm/farm.c b/collie/farm/farm.c
deleted file mode 100644
index ff8be39..0000000
--- a/collie/farm/farm.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Copyright (C) 2011 Taobao Inc.
- * Copyright (C) 2013 Zelin.io
- *
- * Liu Yuan <namei.unix at gmail.com>
- * Kai Zhang <kyle at zelin.io>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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 <pthread.h>
-
-#include "farm.h"
-#include "list.h"
-
-static char farm_object_dir[PATH_MAX];
-static char farm_dir[PATH_MAX];
-
-static struct sd_lock vdi_list_lock = SD_LOCK_INITIALIZER;
-struct vdi_entry {
- char name[SD_MAX_VDI_LEN];
- uint64_t vdi_size;
- uint32_t vdi_id;
- uint32_t snap_id;
- uint8_t nr_copies;
- struct list_head list;
-};
-static LIST_HEAD(last_vdi_list);
-
-struct snapshot_work {
- struct trunk_entry entry;
- struct strbuf *trunk_buf;
- struct work work;
-};
-static struct work_queue *wq;
-static uatomic_bool work_error;
-
-static struct vdi_entry *find_vdi(const char *name)
-{
- struct vdi_entry *vdi;
-
- list_for_each_entry(vdi, &last_vdi_list, list) {
- if (!strcmp(vdi->name, name))
- return vdi;
- }
- return NULL;
-}
-
-static struct vdi_entry *new_vdi(const char *name, uint64_t vdi_size,
- uint32_t vdi_id, uint32_t snap_id,
- uint8_t nr_copies)
-{
- struct vdi_entry *vdi;
- vdi = xmalloc(sizeof(struct vdi_entry));
- pstrcpy(vdi->name, sizeof(vdi->name), name);
- vdi->vdi_size = vdi_size;
- vdi->vdi_id = vdi_id;
- vdi->snap_id = snap_id;
- vdi->nr_copies = nr_copies;
- INIT_LIST_HEAD(&vdi->list);
- return vdi;
-}
-
-static void insert_vdi(struct sd_inode *new)
-{
- struct vdi_entry *vdi;
- vdi = find_vdi(new->name);
- if (!vdi) {
- vdi = new_vdi(new->name,
- new->vdi_size,
- new->vdi_id,
- new->snap_id,
- new->nr_copies);
- list_add(&vdi->list, &last_vdi_list);
- } else if (vdi->snap_id < new->snap_id) {
- vdi->vdi_size = new->vdi_size;
- vdi->vdi_id = new->vdi_id;
- vdi->snap_id = new->snap_id;
- vdi->nr_copies = new->nr_copies;
- }
-}
-
-static int create_active_vdis(void)
-{
- struct vdi_entry *vdi;
- uint32_t new_vid;
- list_for_each_entry(vdi, &last_vdi_list, list) {
- if (do_vdi_create(vdi->name,
- vdi->vdi_size,
- vdi->vdi_id, &new_vid,
- false, vdi->nr_copies) < 0)
- return -1;
- }
- return 0;
-}
-
-static void free_vdi_list(void)
-{
- struct vdi_entry *vdi, *next;
- list_for_each_entry_safe(vdi, next, &last_vdi_list, list)
- free(vdi);
-}
-
-char *get_object_directory(void)
-{
- return farm_object_dir;
-}
-
-static int create_directory(const char *p)
-{
- int ret = -1;
- struct strbuf buf = STRBUF_INIT;
-
- strbuf_addstr(&buf, p);
- if (xmkdir(buf.buf, 0755) < 0) {
- if (errno == EEXIST)
- sd_err("Path is not a directory: %s", p);
- goto out;
- }
-
- if (!strlen(farm_dir))
- strbuf_copyout(&buf, farm_dir, sizeof(farm_dir));
-
- strbuf_addstr(&buf, "/objects");
- if (xmkdir(buf.buf, 0755) < 0)
- goto out;
-
- for (int i = 0; i < 256; i++) {
- strbuf_addf(&buf, "/%02x", i);
- if (xmkdir(buf.buf, 0755) < 0)
- goto out;
-
- strbuf_remove(&buf, buf.len - 3, 3);
- }
-
- if (!strlen(farm_object_dir))
- strbuf_copyout(&buf, farm_object_dir, sizeof(farm_object_dir));
-
- ret = 0;
-out:
- if (ret)
- sd_err("Fail to create directory: %m");
- strbuf_release(&buf);
- return ret;
-}
-
-static int get_trunk_sha1(uint32_t idx, const char *tag, unsigned char *outsha1)
-{
- int nr_logs = -1, ret = -1;
- struct snap_log *log_buf, *log_free = NULL;
- struct snap_file *snap_buf = NULL;
-
- log_free = log_buf = snap_log_read(&nr_logs);
- if (nr_logs < 0)
- goto out;
-
- for (int i = 0; i < nr_logs; i++, log_buf++) {
- if (log_buf->idx != idx && strcmp(log_buf->tag, tag))
- continue;
- snap_buf = snap_file_read(log_buf->sha1);
- if (!snap_buf)
- goto out;
- memcpy(outsha1, snap_buf->trunk_sha1, SHA1_DIGEST_SIZE);
- ret = 0;
- goto out;
- }
-out:
- free(log_free);
- free(snap_buf);
- return ret;
-}
-
-static int notify_vdi_add(uint32_t vdi_id, uint32_t nr_copies)
-{
- int ret = -1;
- struct sd_req hdr;
- char *buf = NULL;
-
- sd_init_req(&hdr, SD_OP_NOTIFY_VDI_ADD);
- hdr.vdi_state.new_vid = vdi_id;
- hdr.vdi_state.copies = nr_copies;
- hdr.vdi_state.set_bitmap = true;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, buf);
-
- if (ret)
- sd_err("Fail to notify vdi add event(%"PRIx32", %d)", vdi_id,
- nr_copies);
-
- free(buf);
- return ret;
-}
-
-int farm_init(const char *path)
-{
- int ret = -1;
-
- if (create_directory(path) < 0)
- goto out;
- if (snap_init(farm_dir) < 0)
- goto out;
- return 0;
-out:
- if (ret)
- sd_err("Fail to init farm.");
- return ret;
-}
-
-bool farm_contain_snapshot(uint32_t idx, const char *tag)
-{
- unsigned char trunk_sha1[SHA1_DIGEST_SIZE];
- return (get_trunk_sha1(idx, tag, trunk_sha1) == 0);
-}
-
-static void do_save_object(struct work *work)
-{
- void *buf;
- size_t size;
- struct snapshot_work *sw;
-
- if (uatomic_is_true(&work_error))
- return;
-
- sw = container_of(work, struct snapshot_work, work);
-
- size = get_objsize(sw->entry.oid);
- buf = xmalloc(size);
-
- if (sd_read_object(sw->entry.oid, buf, size, 0, true) < 0)
- goto error;
-
- if (slice_write(buf, size, sw->entry.sha1) < 0)
- goto error;
-
- free(buf);
- return;
-error:
- free(buf);
- sd_err("Fail to save object, oid %"PRIx64, sw->entry.oid);
- uatomic_set_true(&work_error);
-}
-
-static void farm_show_progress(uint64_t done, uint64_t total)
-{
- return show_progress(done, total, true);
-}
-
-static void save_object_done(struct work *work)
-{
- struct snapshot_work *sw = container_of(work, struct snapshot_work,
- work);
- static unsigned long saved;
-
- if (uatomic_is_true(&work_error))
- goto out;
-
- strbuf_add(sw->trunk_buf, &sw->entry, sizeof(struct trunk_entry));
- farm_show_progress(uatomic_add_return(&saved, 1), object_tree_size());
-out:
- free(sw);
-}
-
-static int queue_save_snapshot_work(uint64_t oid, int nr_copies, void *data)
-{
- struct snapshot_work *sw = xzalloc(sizeof(struct snapshot_work));
- struct strbuf *trunk_buf = data;
-
- sw->entry.oid = oid;
- sw->entry.nr_copies = nr_copies;
- sw->trunk_buf = trunk_buf;
- sw->work.fn = do_save_object;
- sw->work.done = save_object_done;
- queue_work(wq, &sw->work);
-
- return 0;
-}
-
-int farm_save_snapshot(const char *tag)
-{
- unsigned char snap_sha1[SHA1_DIGEST_SIZE];
- unsigned char trunk_sha1[SHA1_DIGEST_SIZE];
- struct strbuf trunk_buf;
- void *snap_log = NULL;
- int log_nr, idx, ret = -1;
- uint64_t nr_objects = object_tree_size();
-
- snap_log = snap_log_read(&log_nr);
- if (!snap_log)
- goto out;
-
- idx = log_nr + 1;
-
- strbuf_init(&trunk_buf, sizeof(struct trunk_entry) * nr_objects);
-
- wq = create_work_queue("save snapshot", WQ_ORDERED);
- if (for_each_object_in_tree(queue_save_snapshot_work,
- &trunk_buf) < 0)
- goto out;
-
- work_queue_wait(wq);
- if (uatomic_is_true(&work_error))
- goto out;
-
- if (trunk_file_write(nr_objects, (struct trunk_entry *)trunk_buf.buf,
- trunk_sha1) < 0)
- goto out;
-
- if (snap_file_write(idx, trunk_sha1, snap_sha1) < 0)
- goto out;
-
- if (snap_log_write(idx, tag, snap_sha1) < 0)
- goto out;
-
- ret = 0;
-out:
- strbuf_release(&trunk_buf);
- free(snap_log);
- return ret;
-}
-
-static void do_load_object(struct work *work)
-{
- void *buffer = NULL;
- size_t size;
- struct snapshot_work *sw;
- static unsigned long loaded;
-
- if (uatomic_is_true(&work_error))
- return;
-
- sw = container_of(work, struct snapshot_work, work);
-
- buffer = slice_read(sw->entry.sha1, &size);
-
- if (!buffer)
- goto error;
-
- if (sd_write_object(sw->entry.oid, 0, buffer, size, 0, 0,
- sw->entry.nr_copies, true, true) != 0)
- goto error;
-
- if (is_vdi_obj(sw->entry.oid)) {
- if (notify_vdi_add(oid_to_vid(sw->entry.oid),
- sw->entry.nr_copies) < 0)
- goto error;
-
- sd_write_lock(&vdi_list_lock);
- insert_vdi(buffer);
- sd_unlock(&vdi_list_lock);
- }
-
- farm_show_progress(uatomic_add_return(&loaded, 1), trunk_get_count());
- free(buffer);
- return;
-error:
- free(buffer);
- sd_err("Fail to load object, oid %"PRIx64, sw->entry.oid);
- uatomic_set_true(&work_error);
-}
-
-static void load_object_done(struct work *work)
-{
- struct snapshot_work *sw = container_of(work, struct snapshot_work,
- work);
-
- free(sw);
-}
-
-static int queue_load_snapshot_work(struct trunk_entry *entry, void *data)
-{
- struct snapshot_work *sw = xzalloc(sizeof(struct snapshot_work));
-
- memcpy(&sw->entry, entry, sizeof(struct trunk_entry));
- sw->work.fn = do_load_object;
- sw->work.done = load_object_done;
- queue_work(wq, &sw->work);
-
- return 0;
-}
-
-int farm_load_snapshot(uint32_t idx, const char *tag)
-{
- int ret = -1;
- unsigned char trunk_sha1[SHA1_DIGEST_SIZE];
-
- if (get_trunk_sha1(idx, tag, trunk_sha1) < 0)
- goto out;
-
- wq = create_work_queue("load snapshot", WQ_DYNAMIC);
- if (for_each_entry_in_trunk(trunk_sha1, queue_load_snapshot_work,
- NULL) < 0)
- goto out;
-
- work_queue_wait(wq);
- if (uatomic_is_true(&work_error))
- goto out;
-
- if (create_active_vdis() < 0)
- goto out;
-
- ret = 0;
-out:
- free_vdi_list();
- return ret;
-}
diff --git a/collie/farm/farm.h b/collie/farm/farm.h
deleted file mode 100644
index 4c03a83..0000000
--- a/collie/farm/farm.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef FARM_H
-#define FARM_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <memory.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/mman.h>
-#include <linux/limits.h>
-
-#include "collie.h"
-#include "sheep.h"
-#include "strbuf.h"
-#include "sha1.h"
-
-struct trunk_entry {
- uint64_t oid;
- int nr_copies;
- unsigned char sha1[SHA1_DIGEST_SIZE];
-};
-
-struct trunk_file {
- uint64_t nr_entries;
- struct trunk_entry *entries;
-};
-
-struct snap_file {
- int idx;
- unsigned char trunk_sha1[SHA1_DIGEST_SIZE];
-};
-
-struct snap_log {
- uint32_t idx;
- char tag[SD_MAX_SNAPSHOT_TAG_LEN];
- uint64_t time;
- unsigned char sha1[SHA1_DIGEST_SIZE];
-};
-
-/* farm.c */
-int farm_init(const char *path);
-bool farm_contain_snapshot(uint32_t idx, const char *tag);
-int farm_save_snapshot(const char *tag);
-int farm_load_snapshot(uint32_t idx, const char *tag);
-char *get_object_directory(void);
-
-/* trunk.c */
-int trunk_init(void);
-int trunk_file_write(uint64_t nr_entries, struct trunk_entry *entries,
- unsigned char *trunk_sha1);
-int for_each_entry_in_trunk(unsigned char *trunk_sha1,
- int (*func)(struct trunk_entry *entry, void *data),
- void *data);
-uint64_t trunk_get_count(void);
-
-/* snap.c */
-int snap_init(const char *path);
-struct snap_file *snap_file_read(unsigned char *sha1);
-int snap_file_write(uint32_t idx, unsigned char *trunk_sha1,
- unsigned char *outsha1);
-void *snap_log_read(int *out_nr);
-int snap_log_write(uint32_t idx, const char *tag, unsigned char *sha1);
-
-/* sha1_file.c */
-int sha1_file_write(void *buf, size_t len, unsigned char *sha1);
-void *sha1_file_read(const unsigned char *sha1, size_t *size);
-
-/* object_tree.c */
-int object_tree_size(void);
-void object_tree_insert(uint64_t oid, int nr_copies);
-void object_tree_free(void);
-void object_tree_print(void);
-int for_each_object_in_tree(int (*func)(uint64_t oid, int nr_copies,
- void *data), void *data);
-/* slice.c */
-int slice_write(void *buf, size_t len, unsigned char *outsha1);
-void *slice_read(const unsigned char *sha1, size_t *outsize);
-
-#endif
diff --git a/collie/farm/object_tree.c b/collie/farm/object_tree.c
deleted file mode 100644
index 00cad2d..0000000
--- a/collie/farm/object_tree.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2013 Zelin.io
- *
- * Kai Zhang <kyle at zelin.io>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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 "farm.h"
-#include "rbtree.h"
-
-struct object_tree_entry {
- uint64_t oid;
- int nr_copies;
- struct rb_node node;
- struct list_head list;
-};
-
-struct object_tree {
- int nr_objs;
- struct rb_root root;
- struct list_head list;
-};
-
-static struct object_tree tree = {
- .nr_objs = 0,
- .root = RB_ROOT,
- .list = LIST_HEAD_INIT(tree.list)
-};
-static struct object_tree_entry *cached_entry;
-
-static struct object_tree_entry *do_insert(struct rb_root *root,
- struct object_tree_entry *new)
-{
- struct rb_node **p = &root->rb_node;
- struct rb_node *parent = NULL;
- struct object_tree_entry *entry;
-
- while (*p) {
- parent = *p;
- entry = rb_entry(parent, struct object_tree_entry, node);
-
- if (new->oid < entry->oid)
- p = &(*p)->rb_left;
- else if (new->oid > entry->oid)
- p = &(*p)->rb_right;
- else
- return entry; /* already has this entry */
- }
- rb_link_node(&new->node, parent, p);
- rb_insert_color(&new->node, root);
-
- return NULL; /* insert sucessfully */
-}
-
-void object_tree_insert(uint64_t oid, int nr_copies)
-{
- struct rb_root *root = &tree.root;
- struct object_tree_entry *p = NULL;
-
- if (!cached_entry)
- cached_entry = xzalloc(sizeof(*cached_entry));
- cached_entry->oid = oid;
- cached_entry->nr_copies = nr_copies;
- rb_init_node(&cached_entry->node);
- p = do_insert(root, cached_entry);
- if (!p) {
- list_add(&cached_entry->list, &tree.list);
- tree.nr_objs++;
- cached_entry = NULL;
- }
-}
-
-void object_tree_print(void)
-{
- struct rb_node *p = rb_first(&tree.root);
- struct object_tree_entry *entry;
- printf("nr_objs: %d\n", tree.nr_objs);
-
- while (p) {
- entry = rb_entry(p, struct object_tree_entry, node);
- printf("Obj id: %"PRIx64"\n", entry->oid);
- p = rb_next(p);
- }
-}
-
-void object_tree_free(void)
-{
- struct object_tree_entry *entry, *next;
- list_for_each_entry_safe(entry, next, &tree.list, list)
- free(entry);
-
- free(cached_entry);
-}
-
-int object_tree_size(void)
-{
- return tree.nr_objs;
-}
-
-int for_each_object_in_tree(int (*func)(uint64_t oid, int nr_copies,
- void *data), void *data)
-{
- struct rb_node *p = rb_first(&tree.root);
- struct object_tree_entry *entry;
- int ret = -1;
-
- while (p) {
- entry = rb_entry(p, struct object_tree_entry, node);
-
- if (func(entry->oid, entry->nr_copies, data) < 0)
- goto out;
-
- p = rb_next(p);
- }
- ret = 0;
-out:
- return ret;
-}
diff --git a/collie/farm/sha1_file.c b/collie/farm/sha1_file.c
deleted file mode 100644
index 3ba2519..0000000
--- a/collie/farm/sha1_file.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2011 Taobao Inc.
- *
- * Liu Yuan <namei.unix at gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * sha1_file provide us some useful features:
- *
- * - Regardless of object type, all objects are all in deflated with zlib,
- * and have a header that not only specifies their tag, but also size
- * information about the data in the object.
- *
- * - the general consistency of an object can always be tested independently
- * of the contents or the type of the object: all objects can be validated
- * by verifying that their hashes match the content of the file.
- */
-#include <sys/types.h>
-
-#include "farm.h"
-#include "util.h"
-
-static void fill_sha1_path(char *pathbuf, const unsigned char *sha1)
-{
- int i;
- for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
- static const char hex[] = "0123456789abcdef";
- unsigned int val = sha1[i];
- char *pos = pathbuf + i*2 + (i > 0);
- *pos++ = hex[val >> 4];
- *pos = hex[val & 0xf];
- }
-}
-
-static char *sha1_to_path(const unsigned char *sha1)
-{
- static __thread char buf[PATH_MAX];
- const char *objdir;
- int len;
-
- objdir = get_object_directory();
- len = strlen(objdir);
-
- /* '/' + sha1(2) + '/' + sha1(38) + '\0' */
- memcpy(buf, objdir, len);
- buf[len] = '/';
- buf[len+3] = '/';
- buf[len+42] = '\0';
- fill_sha1_path(buf + len + 1, sha1);
- return buf;
-}
-
-static int sha1_buffer_write(const unsigned char *sha1,
- void *buf, unsigned int size)
-{
- char *filename = sha1_to_path(sha1);
- int fd, ret = 0, len;
-
- fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
- if (fd < 0) {
- if (errno != EEXIST) {
- sd_err("failed to open file %s with error: %m",
- filename);
- ret = -1;
- }
- goto err_open;
- }
- len = xwrite(fd, buf, size);
- if (len != size) {
- sd_err("%m");
- close(fd);
- return -1;
- }
-
- close(fd);
-err_open:
- return ret;
-}
-
-int sha1_file_write(void *buf, size_t len, unsigned char *outsha1)
-{
- unsigned char sha1[SHA1_DIGEST_SIZE];
-
- sha1_from_buffer(buf, len, sha1);
- if (sha1_buffer_write(sha1, buf, len) < 0)
- return -1;
- if (outsha1)
- memcpy(outsha1, sha1, SHA1_DIGEST_SIZE);
- return 0;
-}
-
-static int verify_sha1_file(const unsigned char *sha1,
- void *buf, unsigned long len)
-{
- unsigned char tmp[SHA1_DIGEST_SIZE];
-
- sha1_from_buffer(buf, len, tmp);
- if (memcmp((char *)tmp, (char *)sha1, SHA1_DIGEST_SIZE) != 0) {
- sd_err("failed, %s != %s", sha1_to_hex(sha1), sha1_to_hex(tmp));
- return -1;
- }
- return 0;
-}
-
-void *sha1_file_read(const unsigned char *sha1, size_t *size)
-{
- char *filename = sha1_to_path(sha1);
- int fd = open(filename, O_RDONLY);
- struct stat st;
- void *buf = NULL;
-
- if (fd < 0) {
- perror(filename);
- return NULL;
- }
- if (fstat(fd, &st) < 0) {
- sd_err("%m");
- goto out;
- }
-
- buf = xmalloc(st.st_size);
- if (!buf)
- goto out;
-
- if (xread(fd, buf, st.st_size) != st.st_size) {
- free(buf);
- buf = NULL;
- goto out;
- }
-
- if (verify_sha1_file(sha1, buf, st.st_size) < 0) {
- free(buf);
- buf = NULL;
- goto out;
- }
-
- *size = st.st_size;
-out:
- close(fd);
- return buf;
-}
diff --git a/collie/farm/slice.c b/collie/farm/slice.c
deleted file mode 100644
index 53941c1..0000000
--- a/collie/farm/slice.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * copyright (c) 2013 taobao inc.
- *
- * liu yuan <namei.unix at gmail.com>
- *
- * this program is free software; you can redistribute it and/or
- * modify it under the terms of the gnu general public license version
- * 2 as published by the free software foundation.
- *
- * you should have received a copy of the gnu general public license
- * along with this program. if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Slice is a fixed chunk of one object to be stored in farm. We slice
- * the object into smaller chunks to get better deduplication.
- */
-
-#include <pthread.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "farm.h"
-#include "strbuf.h"
-#include "util.h"
-#include "sheepdog_proto.h"
-
-struct slice {
- unsigned char sha1[SHA1_DIGEST_SIZE];
-};
-
-struct slice_file {
- uint32_t nr_slices;
- struct slice *slices;
-};
-
-/* 128k, best empirical value from some tests, but no rationale */
-#define SLICE_SIZE (1024*128)
-
-int slice_write(void *buf, size_t len, unsigned char *outsha1)
-{
- int count = DIV_ROUND_UP(len, SLICE_SIZE);
- size_t slen = count * SHA1_DIGEST_SIZE;
- char *sbuf = xmalloc(slen);
- char *p = buf;
-
- for (int i = 0; i < count; i++, p += SLICE_SIZE) {
- unsigned char sha1[SHA1_DIGEST_SIZE];
- size_t wlen = (ssize_t)len - SLICE_SIZE > 0 ? SLICE_SIZE : len;
- len -= SLICE_SIZE;
-
- if (sha1_file_write(p, wlen, sha1) < 0)
- goto err;
- memcpy(sbuf + i * SHA1_DIGEST_SIZE, sha1, SHA1_DIGEST_SIZE);
- }
-
- if (sha1_file_write(sbuf, slen, outsha1) < 0)
- goto err;
- free(sbuf);
- return 0;
-err:
- free(sbuf);
- return -1;
-}
-
-static struct slice_file *slice_file_read(const unsigned char *sha1)
-{
- size_t size;
- struct slice_file *slice_file = NULL;
- void *buf = sha1_file_read(sha1, &size);
-
- if (!buf)
- return NULL;
- slice_file = xmalloc(sizeof(struct slice_file));
- slice_file->nr_slices = size / SHA1_DIGEST_SIZE;
- slice_file->slices = buf;
-
- return slice_file;
-}
-
-void *slice_read(const unsigned char *sha1, size_t *outsize)
-{
- struct slice_file *file = slice_file_read(sha1);
- struct strbuf buf = STRBUF_INIT;
- void *object;
-
- if (!file)
- goto err;
-
- *outsize = 0;
- for (uint32_t i = 0; i < file->nr_slices; i++) {
- size_t size;
- void *sbuf;
-
- sbuf = sha1_file_read(file->slices[i].sha1, &size);
- if (!sbuf)
- goto err;
- strbuf_add(&buf, sbuf, size);
- *outsize += size;
- }
-
- object = xmalloc(*outsize);
- strbuf_copyout(&buf, object, *outsize);
- strbuf_release(&buf);
- return object;
-err:
- strbuf_release(&buf);
- return NULL;
-}
diff --git a/collie/farm/snap.c b/collie/farm/snap.c
deleted file mode 100644
index 8c46484..0000000
--- a/collie/farm/snap.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2011 Taobao Inc.
- * Copyright (C) 2013 Zelin.io
- *
- * Liu Yuan <namei.unix at gmail.com>
- * Kai Zhang <kyle at zelin.io>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/* Snap object is the meta data that describes the cluster snapshot. */
-
-#include <time.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "farm.h"
-
-static char snap_log_path[PATH_MAX];
-
-int snap_init(const char *farm_dir)
-{
- int fd, ret = -1;
- struct strbuf buf = STRBUF_INIT;
-
- strbuf_addstr(&buf, farm_dir);
- strbuf_addf(&buf, "/%s", "user_snap");
-
- if (!strlen(snap_log_path))
- strbuf_copyout(&buf, snap_log_path, sizeof(snap_log_path));
-
- fd = open(snap_log_path, O_CREAT | O_EXCL, 0666);
- if (fd < 0) {
- if (errno != EEXIST) {
- sd_err("%m");
- goto out;
- }
- }
-
- ret = 0;
- close(fd);
-out:
- strbuf_release(&buf);
- return ret;
-}
-
-int snap_log_write(uint32_t idx, const char *tag, unsigned char *sha1)
-{
- int fd, ret = -1;
- struct strbuf buf = STRBUF_INIT;
- struct snap_log log = { .idx = idx,
- .time = time(NULL) };
- pstrcpy(log.tag, SD_MAX_SNAPSHOT_TAG_LEN, tag);
- memcpy(log.sha1, sha1, SHA1_DIGEST_SIZE);
-
- fd = open(snap_log_path, O_WRONLY | O_APPEND);
- if (fd < 0) {
- sd_err("%m");
- goto out;
- }
-
- strbuf_reset(&buf);
- strbuf_add(&buf, &log, sizeof(log));
- ret = xwrite(fd, buf.buf, buf.len);
- if (ret != buf.len)
- goto out_close;
-
- ret = 0;
-out_close:
- close(fd);
-out:
- strbuf_release(&buf);
- return ret;
-}
-
-void *snap_log_read(int *out_nr)
-{
- struct stat st;
- void *buffer = NULL;
- int len, fd;
-
- fd = open(snap_log_path, O_RDONLY);
- if (fd < 0) {
- sd_err("%m");
- goto out;
- }
- if (fstat(fd, &st) < 0) {
- sd_err("%m");
- goto out_close;
- }
-
- len = st.st_size;
- buffer = xmalloc(len);
- len = xread(fd, buffer, len);
- if (len != st.st_size) {
- free(buffer);
- buffer = NULL;
- goto out_close;
- }
- *out_nr = len / sizeof(struct snap_log);
-out_close:
- close(fd);
-out:
- return buffer;
-}
-
-struct snap_file *snap_file_read(unsigned char *sha1)
-{
- size_t size;
- return sha1_file_read(sha1, &size);
-}
-
-int snap_file_write(uint32_t idx, unsigned char *trunk_sha1,
- unsigned char *outsha1)
-{
- struct snap_file snap;
- snap.idx = idx;
- memcpy(snap.trunk_sha1, trunk_sha1, SHA1_DIGEST_SIZE);
-
- return sha1_file_write(&snap, sizeof(struct snap_file),
- outsha1);
-}
diff --git a/collie/farm/trunk.c b/collie/farm/trunk.c
deleted file mode 100644
index 91f293e..0000000
--- a/collie/farm/trunk.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2011 Taobao Inc.
- * Copyright (C) 2013 Zelin.io
- *
- * Liu Yuan <namei.unix at gmail.com>
- * Kai Zhang <kyle at zelin.io>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Trunk object is meta data that describes the structure of the data objects
- * at the time of snapshot being taken. It ties data objects together into a
- * flat directory structure.
- */
-#include <pthread.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "farm.h"
-#include "strbuf.h"
-#include "list.h"
-#include "util.h"
-#include "sheepdog_proto.h"
-
-static uint64_t total_count;
-
-int trunk_file_write(uint64_t nr_entries, struct trunk_entry *entries,
- unsigned char *trunk_sha1)
-{
- size_t size = sizeof(struct trunk_entry) * nr_entries;
- return sha1_file_write(entries, size, trunk_sha1);
-}
-
-static struct trunk_file *trunk_file_read(unsigned char *sha1)
-{
- size_t size;
- struct trunk_file *trunk = NULL;
- void *buf = sha1_file_read(sha1, &size);
-
- if (!buf)
- return NULL;
- trunk = xmalloc(sizeof(struct trunk_file));
- trunk->nr_entries = size / sizeof(struct trunk_entry);
- trunk->entries = buf;
-
- return trunk;
-}
-
-int for_each_entry_in_trunk(unsigned char *trunk_sha1,
- int (*func)(struct trunk_entry *entry, void *data),
- void *data)
-{
- struct trunk_file *trunk;
- struct trunk_entry *entry;
- int ret = -1;
-
- trunk = trunk_file_read(trunk_sha1);
- if (!trunk)
- goto out;
-
- total_count = trunk->nr_entries;
- entry = trunk->entries;
- for (uint64_t i = 0; i < trunk->nr_entries; i++, entry++) {
- if (func(entry, data) < 0)
- goto out;
- }
-
- ret = 0;
-out:
- free(trunk->entries);
- free(trunk);
- return ret;
-}
-
-uint64_t trunk_get_count(void)
-{
- return total_count;
-}
diff --git a/collie/node.c b/collie/node.c
deleted file mode 100644
index 028d804..0000000
--- a/collie/node.c
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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 "collie.h"
-
-static struct node_cmd_data {
- bool all_nodes;
- bool recovery_progress;
-} node_cmd_data;
-
-static void cal_total_vdi_size(uint32_t vid, const char *name, const char *tag,
- uint32_t snapid, uint32_t flags,
- const struct sd_inode *i, void *data)
-{
- uint64_t *size = data;
-
- if (!vdi_is_snapshot(i))
- *size += i->vdi_size;
-}
-
-static int node_list(int argc, char **argv)
-{
- int i;
-
- if (!raw_output)
- printf(" Id Host:Port V-Nodes Zone\n");
- for (i = 0; i < sd_nodes_nr; i++) {
- const char *host = addr_to_str(sd_nodes[i].nid.addr,
- sd_nodes[i].nid.port);
-
- printf(raw_output ? "%d %s %d %u\n" : "%4d %-20s\t%2d%11u\n",
- i, host, sd_nodes[i].nr_vnodes, sd_nodes[i].zone);
- }
-
- return EXIT_SUCCESS;
-}
-
-static int node_info(int argc, char **argv)
-{
- int i, ret, success = 0;
- uint64_t total_size = 0, total_avail = 0, total_vdi_size = 0;
- char total_str[UINT64_DECIMAL_SIZE], use_str[UINT64_DECIMAL_SIZE],
- avail_str[UINT64_DECIMAL_SIZE], vdi_size_str[UINT64_DECIMAL_SIZE];
-
- if (!raw_output)
- printf("Id\tSize\tUsed\tAvail\tUse%%\n");
-
- for (i = 0; i < sd_nodes_nr; i++) {
- struct sd_req req;
- struct sd_rsp *rsp = (struct sd_rsp *)&req;
- char store_str[UINT64_DECIMAL_SIZE],
- used_str[UINT64_DECIMAL_SIZE],
- free_str[UINT64_DECIMAL_SIZE];
-
- sd_init_req(&req, SD_OP_STAT_SHEEP);
-
- ret = send_light_req(&req, sd_nodes[i].nid.addr,
- sd_nodes[i].nid.port);
-
- size_to_str(rsp->node.store_size, store_str, sizeof(store_str));
- size_to_str(rsp->node.store_free, free_str, sizeof(free_str));
- size_to_str(rsp->node.store_size - rsp->node.store_free,
- used_str, sizeof(used_str));
- if (!ret) {
- int ratio = (int)(((double)(rsp->node.store_size -
- rsp->node.store_free) /
- rsp->node.store_size) * 100);
- printf(raw_output ? "%d %s %s %s %d%%\n" :
- "%2d\t%s\t%s\t%s\t%3d%%\n",
- i, store_str, used_str, free_str,
- rsp->node.store_size == 0 ? 0 : ratio);
- success++;
- }
-
- total_size += rsp->node.store_size;
- total_avail += rsp->node.store_free;
- }
-
- if (success == 0) {
- sd_err("Cannot get information from any nodes");
- return EXIT_SYSFAIL;
- }
-
- if (parse_vdi(cal_total_vdi_size, SD_INODE_HEADER_SIZE,
- &total_vdi_size) < 0)
- return EXIT_SYSFAIL;
-
- size_to_str(total_size, total_str, sizeof(total_str));
- size_to_str(total_avail, avail_str, sizeof(avail_str));
- size_to_str(total_size - total_avail, use_str, sizeof(use_str));
- size_to_str(total_vdi_size, vdi_size_str, sizeof(vdi_size_str));
- printf(raw_output ? "Total %s %s %s %d%% %s\n"
- : "Total\t%s\t%s\t%s\t%3d%%\n\n"
- "Total virtual image size\t%s\n",
- total_str, use_str, avail_str,
- (int)(((double)(total_size - total_avail) / total_size) * 100),
- vdi_size_str);
-
- return EXIT_SUCCESS;
-}
-
-static int get_recovery_state(struct recovery_state *state)
-{
- int ret;
- struct sd_req req;
-
- sd_init_req(&req, SD_OP_STAT_RECOVERY);
- req.data_length = sizeof(*state);
-
- ret = collie_exec_req(sdhost, sdport, &req, state);
- if (ret < 0) {
- sd_err("Failed to execute request");
- return -1;
- }
-
- return 0;
-}
-
-static int node_recovery_progress(void)
-{
- int result;
- unsigned int prev_nr_total;
- struct recovery_state rstate;
-
- /*
- * ToDos
- *
- * 1. Calculate size of actually copied objects.
- * For doing this, not so trivial changes for recovery process are
- * required.
- *
- * 2. Print remaining physical time.
- * Even if it is not so acculate, the information is helpful for
- * administrators.
- */
-
- result = get_recovery_state(&rstate);
- if (result < 0)
- return EXIT_SYSFAIL;
-
- if (!rstate.in_recovery)
- return EXIT_SUCCESS;
-
- do {
- prev_nr_total = rstate.nr_total;
-
- result = get_recovery_state(&rstate);
- if (result < 0)
- break;
-
- if (!rstate.in_recovery) {
- show_progress(prev_nr_total, prev_nr_total, true);
- break;
- }
-
- switch (rstate.state) {
- case RW_PREPARE_LIST:
- printf("\rpreparing a checked object list...");
- break;
- case RW_NOTIFY_COMPLETION:
- printf("\rnotifying a completion of recovery...");
- break;
- case RW_RECOVER_OBJ:
- show_progress(rstate.nr_finished, rstate.nr_total,
- true);
- break;
- default:
- panic("unknown state of recovery: %d", rstate.state);
- break;
- }
-
- sleep(1);
- } while (true);
-
- return result < 0 ? EXIT_SYSFAIL : EXIT_SUCCESS;
-}
-
-static int node_recovery(int argc, char **argv)
-{
- int i, ret;
-
- if (node_cmd_data.recovery_progress)
- return node_recovery_progress();
-
- if (!raw_output) {
- printf("Nodes In Recovery:\n");
- printf(" Id Host:Port V-Nodes Zone"
- " Progress\n");
- }
-
- for (i = 0; i < sd_nodes_nr; i++) {
- struct sd_req req;
- struct recovery_state state;
-
- memset(&state, 0, sizeof(state));
-
- sd_init_req(&req, SD_OP_STAT_RECOVERY);
- req.data_length = sizeof(state);
-
- ret = collie_exec_req(sd_nodes[i].nid.addr,
- sd_nodes[i].nid.port, &req, &state);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- if (state.in_recovery) {
- const char *host = addr_to_str(sd_nodes[i].nid.addr,
- sd_nodes[i].nid.port);
- if (raw_output)
- printf("%d %s %d %d %"PRIu64" %"PRIu64"\n", i,
- host, sd_nodes[i].nr_vnodes,
- sd_nodes[i].zone, state.nr_finished,
- state.nr_total);
- else
- printf("%4d %-20s%5d%11d%11.1f%%\n", i, host,
- sd_nodes[i].nr_vnodes, sd_nodes[i].zone,
- 100 * (float)state.nr_finished
- / state.nr_total);
- }
- }
-
- return EXIT_SUCCESS;
-}
-
-static int node_kill(int argc, char **argv)
-{
- int node_id, ret;
- struct sd_req req;
- const char *p = argv[optind++];
-
- if (!is_numeric(p)) {
- sd_err("Invalid node id '%s', please specify a numeric value",
- p);
- exit(EXIT_USAGE);
- }
-
- node_id = strtol(p, NULL, 10);
- if (node_id < 0 || node_id >= sd_nodes_nr) {
- sd_err("Invalid node id '%d'", node_id);
- exit(EXIT_USAGE);
- }
-
- sd_init_req(&req, SD_OP_KILL_NODE);
-
- ret = send_light_req(&req, sd_nodes[node_id].nid.addr,
- sd_nodes[node_id].nid.port);
- if (ret) {
- sd_err("Failed to execute request");
- exit(EXIT_FAILURE);
- }
-
- return EXIT_SUCCESS;
-}
-
-static int node_md_info(struct node_id *nid)
-{
- struct sd_md_info info = {};
- char size_str[UINT64_DECIMAL_SIZE], used_str[UINT64_DECIMAL_SIZE],
- avail_str[UINT64_DECIMAL_SIZE];
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- int ret, i;
-
- sd_init_req(&hdr, SD_OP_MD_INFO);
- hdr.data_length = sizeof(info);
-
- ret = collie_exec_req(nid->addr, nid->port, &hdr, &info);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("failed to get multi-disk infomation: %s",
- sd_strerror(rsp->result));
- return EXIT_FAILURE;
- }
-
- for (i = 0; i < info.nr; i++) {
- uint64_t size = info.disk[i].free + info.disk[i].used;
- int ratio = (int)(((double)info.disk[i].used / size) * 100);
-
- size_to_str(size, size_str, sizeof(size_str));
- size_to_str(info.disk[i].used, used_str, sizeof(used_str));
- size_to_str(info.disk[i].free, avail_str, sizeof(avail_str));
- fprintf(stdout, "%2d\t%s\t%s\t%s\t%3d%%\t%s\n",
- info.disk[i].idx, size_str, used_str, avail_str, ratio,
- info.disk[i].path);
- }
- return EXIT_SUCCESS;
-}
-
-static int md_info(int argc, char **argv)
-{
- int i, ret;
-
- fprintf(stdout, "Id\tSize\tUsed\tAvail\tUse%%\tPath\n");
-
- if (!node_cmd_data.all_nodes) {
- struct node_id nid = {.port = sdport};
-
- memcpy(nid.addr, sdhost, sizeof(nid.addr));
-
- return node_md_info(&nid);
- }
-
- for (i = 0; i < sd_nodes_nr; i++) {
- fprintf(stdout, "Node %d:\n", i);
- ret = node_md_info(&sd_nodes[i].nid);
- if (ret != EXIT_SUCCESS)
- return EXIT_FAILURE;
- }
- return EXIT_SUCCESS;
-}
-
-static int do_plug_unplug(char *disks, bool plug)
-{
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- int ret;
-
- if (!strlen(disks)) {
- sd_err("Empty path isn't allowed");
- return EXIT_FAILURE;
- }
-
- if (plug)
- sd_init_req(&hdr, SD_OP_MD_PLUG);
- else
- sd_init_req(&hdr, SD_OP_MD_UNPLUG);
- hdr.flags = SD_FLAG_CMD_WRITE;
- hdr.data_length = strlen(disks) + 1;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, disks);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("Failed to execute request, look for sheep.log"
- " for more information");
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-static int md_plug(int argc, char **argv)
-{
- return do_plug_unplug(argv[optind], true);
-}
-
-static int md_unplug(int argc, char **argv)
-{
- return do_plug_unplug(argv[optind], false);
-}
-
-static struct subcommand node_md_cmd[] = {
- {"info", NULL, NULL, "show multi-disk information",
- NULL, CMD_NEED_NODELIST, md_info},
- {"plug", NULL, NULL, "plug more disk(s) into node",
- NULL, CMD_NEED_ARG, md_plug},
- {"unplug", NULL, NULL, "unplug disk(s) from node",
- NULL, CMD_NEED_ARG, md_unplug},
- {NULL},
-};
-
-static int node_md(int argc, char **argv)
-{
- return do_generic_subcommand(node_md_cmd, argc, argv);
-}
-
-
-static int node_parser(int ch, char *opt)
-{
- switch (ch) {
- case 'A':
- node_cmd_data.all_nodes = true;
- break;
- case 'P':
- node_cmd_data.recovery_progress = true;
- break;
- }
-
- return 0;
-}
-
-static struct sd_option node_options[] = {
- {'A', "all", false, "show md information of all the nodes"},
- {'P', "progress", false, "show progress of recovery in the node"},
-
- { 0, NULL, false, NULL },
-};
-
-static struct subcommand node_cmd[] = {
- {"kill", "<node id>", "aprh", "kill node", NULL,
- CMD_NEED_ARG | CMD_NEED_NODELIST, node_kill},
- {"list", NULL, "aprh", "list nodes", NULL,
- CMD_NEED_NODELIST, node_list},
- {"info", NULL, "aprh", "show information about each node", NULL,
- CMD_NEED_NODELIST, node_info},
- {"recovery", NULL, "aphPr", "show recovery information of nodes", NULL,
- CMD_NEED_NODELIST, node_recovery, node_options},
- {"md", "[disks]", "apAh", "See 'collie node md' for more information",
- node_md_cmd, CMD_NEED_ARG, node_md, node_options},
- {NULL,},
-};
-
-struct command node_command = {
- "node",
- node_cmd,
- node_parser
-};
diff --git a/collie/trace.c b/collie/trace.c
deleted file mode 100644
index 1271e7c..0000000
--- a/collie/trace.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * Copyright (C) 2011 Taobao Inc.
- *
- * Liu Yuan <namei.unix at gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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 <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-
-#include "collie.h"
-#include "rbtree.h"
-#include "list.h"
-
-static inline void print_thread_name(struct trace_graph_item *item)
-{
- printf("%-*s|", TRACE_THREAD_LEN, item->tname);
-}
-
-static inline void print_time(struct trace_graph_item *item)
-{
- if (item->type == TRACE_GRAPH_RETURN) {
- unsigned duration = item->return_time - item->entry_time;
- unsigned quot = duration / 1000, rem = duration % 1000;
-
- printf("%8u.%-3u|", quot, rem);
- } else if (item->type == TRACE_GRAPH_ENTRY) {
- printf(" |");
- }
-}
-
-static inline void print_finale(struct trace_graph_item *item)
-{
- int i;
-
- for (i = 0; i < item->depth; i++)
- printf(" ");
- if (item->type == TRACE_GRAPH_ENTRY)
- printf("%s() {\n", item->fname);
- else
- printf("}\n");
-}
-
-static void print_trace_item(struct trace_graph_item *item)
-{
- print_thread_name(item);
- print_time(item);
- print_finale(item);
-}
-
-static void cat_trace_file(void *buf, size_t size)
-{
- struct trace_graph_item *item = (struct trace_graph_item *)buf;
- size_t sz = size / sizeof(struct trace_graph_item), i;
-
- printf(" Thread Name | Time(us) | Function Graph\n");
- printf("--------------------------------------------------\n");
- for (i = 0; i < sz; i++)
- print_trace_item(item++);
- return;
-}
-
-static const char *tracefile = "/tmp/tracefile";
-
-static int trace_read_buffer(void)
-{
- int ret, tfd;
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
-#define TRACE_BUF_LEN (1024 * 1024 * 20)
- char *buf = xzalloc(TRACE_BUF_LEN);
-
- tfd = open(tracefile, O_CREAT | O_RDWR | O_APPEND | O_TRUNC, 0644);
- if (tfd < 0) {
- sd_err("can't create tracefile");
- return EXIT_SYSFAIL;
- }
-
-read_buffer:
- sd_init_req(&hdr, SD_OP_TRACE_READ_BUF);
- hdr.data_length = TRACE_BUF_LEN;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, buf);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- if (rsp->result == SD_RES_AGAIN)
- goto read_buffer;
-
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("Trace failed: %s", sd_strerror(rsp->result));
- return EXIT_FAILURE;
- }
-
- xwrite(tfd, buf, rsp->data_length);
- if (rsp->data_length == TRACE_BUF_LEN) {
- memset(buf, 0, TRACE_BUF_LEN);
- goto read_buffer;
- }
-
- free(buf);
- return EXIT_SUCCESS;
-}
-
-static int trace_enable(int argc, char **argv)
-{
- const char *tracer = argv[optind];
- int ret;
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
-
- sd_init_req(&hdr, SD_OP_TRACE_ENABLE);
- hdr.flags = SD_FLAG_CMD_WRITE;
- hdr.data_length = strlen(tracer) + 1;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, (void *)tracer);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- switch (rsp->result) {
- case SD_RES_SUCCESS:
- break;
- case SD_RES_NO_SUPPORT:
- sd_err("no such tracer %s", tracer);
- return EXIT_FAILURE;
- case SD_RES_INVALID_PARMS:
- sd_err("tracer %s is already enabled", tracer);
- return EXIT_FAILURE;
- default:
- sd_err("unknown error (%s)", sd_strerror(rsp->result));
- return EXIT_SYSFAIL;
- }
-
- return EXIT_SUCCESS;
-}
-
-static int trace_disable(int argc, char **argv)
-{
- const char *tracer = argv[optind];
- int ret;
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
-
- sd_init_req(&hdr, SD_OP_TRACE_DISABLE);
- hdr.flags = SD_FLAG_CMD_WRITE;
- hdr.data_length = strlen(tracer) + 1;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, (void *)tracer);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- switch (rsp->result) {
- case SD_RES_SUCCESS:
- break;
- case SD_RES_NO_SUPPORT:
- sd_err("no such tracer %s", tracer);
- return EXIT_FAILURE;
- case SD_RES_INVALID_PARMS:
- sd_err("tracer %s is not enabled", tracer);
- return EXIT_FAILURE;
- default:
- sd_err("unknown error (%s)", sd_strerror(rsp->result));
- return EXIT_SYSFAIL;
- }
-
- return trace_read_buffer();
-}
-
-static int trace_status(int argc, char **argv)
-{
- char buf[4096]; /* must have enough space to store tracer list */
- int ret;
- struct sd_req hdr;
-
- sd_init_req(&hdr, SD_OP_TRACE_STATUS);
- hdr.data_length = sizeof(buf);
-
- ret = collie_exec_req(sdhost, sdport, &hdr, buf);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- printf("%s", buf);
-
- return EXIT_SUCCESS;
-}
-
-static void *map_trace_file(struct stat *st)
-{
- int fd = open(tracefile, O_RDONLY);
- void *map;
-
- if (fd < 0) {
- sd_err("%m");
- return NULL;
- }
-
- if (fstat(fd, st) < 0) {
- sd_err("%m");
- close(fd);
- return NULL;
- }
-
- if (st->st_size == 0) {
- sd_err("trace file is empty");
- return NULL;
- }
-
- map = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- close(fd);
- if (map == MAP_FAILED) {
- sd_err("%m");
- return NULL;
- }
-
- return map;
-}
-
-static int graph_cat(int argc, char **argv)
-{
- struct stat st;
- void *map = map_trace_file(&st);
-
- if (!map)
- return EXIT_FAILURE;
-
- cat_trace_file(map, st.st_size);
- munmap(map, st.st_size);
-
- return EXIT_SUCCESS;
-}
-
-struct graph_stat_entry {
- struct rb_node rb;
- struct list_head list;
- char fname[TRACE_FNAME_LEN];
- uint64_t duration;
- uint16_t nr_calls;
-};
-
-static struct rb_root stat_tree_root;
-
-static LIST_HEAD(stat_list);
-
-static struct graph_stat_entry *
-stat_tree_insert(struct graph_stat_entry *new)
-{
- struct rb_node **p = &stat_tree_root.rb_node;
- struct rb_node *parent = NULL;
- struct graph_stat_entry *entry;
-
- while (*p) {
- int cmp;
-
- parent = *p;
- entry = rb_entry(parent, struct graph_stat_entry, rb);
- cmp = strcmp(new->fname, entry->fname);
-
- if (cmp < 0)
- p = &(*p)->rb_left;
- else if (cmp > 0)
- p = &(*p)->rb_right;
- else {
- entry->duration += new->duration;
- entry->nr_calls++;
- return entry;
- }
- }
- rb_link_node(&new->rb, parent, p);
- rb_insert_color(&new->rb, &stat_tree_root);
-
- return NULL; /* insert successfully */
-}
-
-static void prepare_stat_tree(struct trace_graph_item *item)
-{
- struct graph_stat_entry *new;
-
- if (item->type != TRACE_GRAPH_RETURN)
- return;
- new = xmalloc(sizeof(*new));
- pstrcpy(new->fname, sizeof(new->fname), item->fname);
- new->duration = item->return_time - item->entry_time;
- new->nr_calls = 1;
- INIT_LIST_HEAD(&new->list);
- if (stat_tree_insert(new)) {
- free(new);
- return;
- }
- list_add(&new->list, &stat_list);
-}
-
-static void stat_list_print(void)
-{
- struct graph_stat_entry *entry;
-
- list_for_each_entry(entry, &stat_list, list) {
- float total = (float)entry->duration / 1000000000;
- float per = (float)entry->duration / entry->nr_calls / 1000000;
-
- printf("%10.3f %10.3f %5"PRIu16" %-*s\n", total, per,
- entry->nr_calls, TRACE_FNAME_LEN, entry->fname);
- }
-}
-
-static int stat_list_cmp(void *priv, struct list_head *a, struct list_head *b)
-{
- struct graph_stat_entry *ga = container_of(a, struct graph_stat_entry,
- list);
- struct graph_stat_entry *gb = container_of(b, struct graph_stat_entry,
- list);
- /* '-' is for reverse sort, largest first */
- return -intcmp(ga->duration, gb->duration);
-}
-
-static void stat_trace_file(void *buf, size_t size)
-{
- struct trace_graph_item *item = (struct trace_graph_item *)buf;
- size_t sz = size / sizeof(struct trace_graph_item), i;
-
- printf(" Total (s) Per Call (ms) Calls Name\n");
- for (i = 0; i < sz; i++)
- prepare_stat_tree(item++);
- list_sort(NULL, &stat_list, stat_list_cmp);
- stat_list_print();
-}
-
-static int graph_stat(int argc, char **argv)
-{
- struct stat st;
- void *map = map_trace_file(&st);
-
- if (!map)
- return EXIT_FAILURE;
-
- stat_trace_file(map, st.st_size);
- munmap(map, st.st_size);
- return EXIT_SUCCESS;
-}
-
-static int trace_parser(int ch, char *opt)
-{
- return 0;
-}
-
-static struct subcommand graph_cmd[] = {
- {"cat", NULL, NULL, "cat the output of graph tracer",
- NULL, 0, graph_cat},
- {"stat", NULL, NULL, "get the stat of the graph calls",
- NULL, 0, graph_stat},
- {NULL,},
-};
-
-static int trace_graph(int argc, char **argv)
-{
- return do_generic_subcommand(graph_cmd, argc, argv);
-}
-
-/* Subcommand list of trace */
-static struct subcommand trace_cmd[] = {
- {"enable", "<tracer>", "aph", "enable tracer", NULL,
- CMD_NEED_ARG, trace_enable},
- {"disable", "<tracer>", "aph", "disable tracer", NULL,
- CMD_NEED_ARG, trace_disable},
- {"status", NULL, "aph", "show tracer statuses", NULL,
- 0, trace_status},
- {"graph", NULL, "aph", "run collie trace graph for more information",
- graph_cmd, CMD_NEED_ARG, trace_graph},
- {NULL},
-};
-
-struct command trace_command = {
- "trace",
- trace_cmd,
- trace_parser
-};
diff --git a/collie/treeview.c b/collie/treeview.c
deleted file mode 100644
index baf0f00..0000000
--- a/collie/treeview.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2009-2011 Nippon Telegraph and Telephone Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-
-#include "util.h"
-#include "treeview.h"
-
-#ifndef MAX_DEPTH
-#define MAX_DEPTH 100
-#endif
-
-struct vdi_tree {
- char name[1024];
- char label[256];
- uint32_t vid;
- uint32_t pvid;
- bool highlight;
- struct list_head children;
- struct list_head siblings;
-};
-
-static int *width, *more;
-static struct vdi_tree *root;
-
-static struct vdi_tree *find_vdi(struct vdi_tree *parent, uint32_t vid,
- const char *name)
-{
- struct vdi_tree *vdi, *ret;
-
- list_for_each_entry(vdi, &parent->children, siblings) {
- if (vdi->vid == vid && !strcmp(vdi->name, name))
- return vdi;
-
- ret = find_vdi(vdi, vid, name);
- if (ret)
- return ret;
- }
- return NULL;
-}
-
-static struct vdi_tree *new_vdi(const char *name, const char *label,
- uint64_t vid, uint64_t pvid, bool highlight)
-{
- struct vdi_tree *vdi;
-
- vdi = xmalloc(sizeof(struct vdi_tree));
- pstrcpy(vdi->name, sizeof(vdi->name), name);
- pstrcpy(vdi->label, sizeof(vdi->label), label);
- vdi->vid = vid;
- vdi->pvid = pvid;
- vdi->highlight = highlight;
- INIT_LIST_HEAD(&vdi->children);
- return vdi;
-}
-
-void init_tree(void)
-{
- root = new_vdi("", "", 0, 0, 0);
-}
-
-void add_vdi_tree(const char *name, const char *label, uint32_t vid,
- uint32_t pvid, bool highlight)
-{
- struct vdi_tree *vdi, *parent;
-
- vdi = new_vdi(name, label, vid, pvid, highlight);
- if (!vdi)
- return;
-
- parent = find_vdi(root, pvid, name);
- if (!parent)
- parent = root;
-
- list_add_tail(&vdi->siblings, &parent->children);
-}
-
-static void compaction(struct vdi_tree *parent)
-{
- struct vdi_tree *vdi, *e, *new_parent;
-
- list_for_each_entry_safe(vdi, e, &parent->children, siblings) {
- new_parent = find_vdi(root, vdi->pvid, vdi->name);
- if (new_parent && parent != new_parent)
- list_move_tail(&vdi->siblings, &new_parent->children);
-
- compaction(vdi);
- }
-}
-
-static int get_depth(struct vdi_tree *parent)
-{
- struct vdi_tree *vdi;
- int max_depth = 0, depth;
-
- list_for_each_entry(vdi, &parent->children, siblings) {
- depth = get_depth(vdi);
- if (max_depth < depth)
- max_depth = depth;
- }
- return max_depth + 1;
-}
-
-static void spaces(int n)
-{
- while (n--)
- putchar(' ');
-}
-
-static void indent(int level, bool first, bool last)
-{
- int lvl;
-
- if (first)
- printf(last ? "---" : "-+-");
- else {
- for (lvl = 0; lvl < level - 1; lvl++) {
- spaces(width[lvl] + 1);
- printf(more[lvl + 1] ? "| " : " ");
- }
-
- spaces(width[level - 1] + 1);
- printf(last ? "`-" : "|-");
- }
-}
-
-static void _dump_tree(struct vdi_tree *current, int level, bool first, bool last)
-{
- struct vdi_tree *vdi;
-
- indent(level, first, last);
-
- if (current->highlight)
- printf(TEXT_BOLD);
-
- printf("%s", current->label);
-
- if (current->highlight)
- printf(TEXT_NORMAL);
-
- if (list_empty(¤t->children)) {
- putchar('\n');
- return;
- }
-
- more[level] = !last;
- width[level] = strlen(current->label);
-
- list_for_each_entry(vdi, ¤t->children, siblings) {
- _dump_tree(vdi, level + 1,
- &vdi->siblings == current->children.next,
- vdi->siblings.next == ¤t->children);
- }
-}
-
-void dump_tree(void)
-{
- struct vdi_tree *vdi;
- int depth;
-
- compaction(root);
-
- depth = get_depth(root);
-
- width = malloc(sizeof(int) * depth);
- more = malloc(sizeof(int) * depth);
- if (!width || !more) {
- sd_err("Failed to allocate memory");
- return;
- }
-
- list_for_each_entry(vdi, &root->children, siblings) {
- printf("%s", vdi->name);
- more[0] = 0;
- width[0] = strlen(vdi->name);
- _dump_tree(vdi, 1, true, true);
- }
-}
diff --git a/collie/treeview.h b/collie/treeview.h
deleted file mode 100644
index 9787fbb..0000000
--- a/collie/treeview.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2009-2011 Nippon Telegraph and Telephone Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef __TREEVIEW__
-#define __TREEVIEW__
-
-#include <stdbool.h>
-
-void init_tree(void);
-void add_vdi_tree(const char *label, const char *tag, uint32_t vid,
- uint32_t pvid, bool highlight);
-void dump_tree(void);
-
-#endif
diff --git a/collie/vdi.c b/collie/vdi.c
deleted file mode 100644
index 1b48079..0000000
--- a/collie/vdi.c
+++ /dev/null
@@ -1,2160 +0,0 @@
-/*
- * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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 <ctype.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "collie.h"
-#include "treeview.h"
-#include "sha1.h"
-
-static struct sd_option vdi_options[] = {
- {'P', "prealloc", false, "preallocate all the data objects"},
- {'i', "index", true, "specify the index of data objects"},
- {'s', "snapshot", true, "specify a snapshot id or tag name"},
- {'x', "exclusive", false, "write in an exclusive mode"},
- {'d', "delete", false, "delete a key"},
- {'w', "writeback", false, "use writeback mode"},
- {'c', "copies", true, "specify the data redundancy (number of copies)"},
- {'F', "from", true, "create a differential backup from the snapshot"},
- {'f', "force", false, "do operation forcibly"},
- { 0, NULL, false, NULL },
-};
-
-static struct vdi_cmd_data {
- unsigned int index;
- int snapshot_id;
- char snapshot_tag[SD_MAX_VDI_TAG_LEN];
- bool exclusive;
- bool delete;
- bool prealloc;
- int nr_copies;
- bool writeback;
- int from_snapshot_id;
- char from_snapshot_tag[SD_MAX_VDI_TAG_LEN];
- bool force;
-} vdi_cmd_data = { ~0, };
-
-struct get_vdi_info {
- const char *name;
- const char *tag;
- uint32_t vid;
- uint32_t snapid;
- uint8_t nr_copies;
-};
-
-static int parse_option_size(const char *value, uint64_t *ret)
-{
- char *postfix;
- double sizef;
-
- sizef = strtod(value, &postfix);
- switch (*postfix) {
- case 'T':
- sizef *= 1024;
- case 'G':
- sizef *= 1024;
- case 'M':
- sizef *= 1024;
- case 'K':
- case 'k':
- sizef *= 1024;
- case 'b':
- case '\0':
- *ret = (uint64_t) sizef;
- break;
- default:
- sd_err("Invalid size '%s'", value);
- sd_err("You may use k, M, G or T suffixes for "
- "kilobytes, megabytes, gigabytes and terabytes.");
- return -1;
- }
-
- return 0;
-}
-
-static void vdi_show_progress(uint64_t done, uint64_t total)
-{
- return show_progress(done, total, false);
-}
-
-static void print_vdi_list(uint32_t vid, const char *name, const char *tag,
- uint32_t snapid, uint32_t flags,
- const struct sd_inode *i, void *data)
-{
- int idx;
- bool is_clone = false;
- uint64_t my_objs, cow_objs;
- char vdi_size_str[16], my_objs_str[16], cow_objs_str[16];
- time_t ti;
- struct tm tm;
- char dbuf[128];
- struct get_vdi_info *info = data;
-
- if (info && strcmp(name, info->name) != 0)
- return;
-
- ti = i->create_time >> 32;
- if (raw_output) {
- snprintf(dbuf, sizeof(dbuf), "%" PRIu64, (uint64_t) ti);
- } else {
- localtime_r(&ti, &tm);
- strftime(dbuf, sizeof(dbuf),
- "%Y-%m-%d %H:%M", &tm);
- }
-
- my_objs = 0;
- cow_objs = 0;
- for (idx = 0; idx < MAX_DATA_OBJS; idx++) {
- if (!i->data_vdi_id[idx])
- continue;
- if (is_data_obj_writeable(i, idx))
- my_objs++;
- else
- cow_objs++;
- }
-
- size_to_str(i->vdi_size, vdi_size_str, sizeof(vdi_size_str));
- size_to_str(my_objs * SD_DATA_OBJ_SIZE, my_objs_str, sizeof(my_objs_str));
- size_to_str(cow_objs * SD_DATA_OBJ_SIZE, cow_objs_str, sizeof(cow_objs_str));
-
- if (i->snap_id == 1 && i->parent_vdi_id != 0)
- is_clone = true;
-
- if (raw_output) {
- printf("%c ", vdi_is_snapshot(i) ? 's' : (is_clone ? 'c' : '='));
- while (*name) {
- if (isspace(*name) || *name == '\\')
- putchar('\\');
- putchar(*name++);
- }
- printf(" %d %s %s %s %s %" PRIx32 " %d %s\n", snapid,
- vdi_size_str, my_objs_str, cow_objs_str, dbuf, vid,
- i->nr_copies, i->tag);
- } else {
- printf("%c %-8s %5d %7s %7s %7s %s %7" PRIx32 " %5d %13s\n",
- vdi_is_snapshot(i) ? 's' : (is_clone ? 'c' : ' '),
- name, snapid, vdi_size_str, my_objs_str, cow_objs_str,
- dbuf, vid, i->nr_copies, i->tag);
- }
-}
-
-static void print_vdi_tree(uint32_t vid, const char *name, const char *tag,
- uint32_t snapid, uint32_t flags,
- const struct sd_inode *i, void *data)
-{
- time_t ti;
- struct tm tm;
- char buf[128];
-
- if (vdi_is_snapshot(i)) {
- ti = i->create_time >> 32;
- localtime_r(&ti, &tm);
-
- strftime(buf, sizeof(buf),
- "[%Y-%m-%d %H:%M]", &tm);
- } else
- pstrcpy(buf, sizeof(buf), "(you are here)");
-
- add_vdi_tree(name, buf, vid, i->parent_vdi_id,
- highlight && !vdi_is_snapshot(i));
-}
-
-static void print_vdi_graph(uint32_t vid, const char *name, const char *tag,
- uint32_t snapid, uint32_t flags,
- const struct sd_inode *i, void *data)
-{
- time_t ti;
- struct tm tm;
- char dbuf[128], tbuf[128], size_str[128];
-
- ti = i->create_time >> 32;
- localtime_r(&ti, &tm);
-
- strftime(dbuf, sizeof(dbuf), "%Y-%m-%d", &tm);
- strftime(tbuf, sizeof(tbuf), "%H:%M:%S", &tm);
- size_to_str(i->vdi_size, size_str, sizeof(size_str));
-
- printf(" \"%x\" -> \"%x\";\n", i->parent_vdi_id, vid);
- printf(" \"%x\" [\n"
- " group = \"%s\",\n"
- " label = \"",
- vid, name);
- printf("Name: %10s\\n"
- "Tag: %10x\\n"
- "Size: %10s\\n"
- "Date: %10s\\n"
- "Time: %10s",
- name, snapid, size_str, dbuf, tbuf);
-
- if (vdi_is_snapshot(i))
- printf("\"\n ];\n\n");
- else
- printf("\",\n color=\"red\"\n ];\n\n");
-
-}
-
-static void get_oid(uint32_t vid, const char *name, const char *tag,
- uint32_t snapid, uint32_t flags,
- const struct sd_inode *i, void *data)
-{
- struct get_vdi_info *info = data;
-
- if (info->name) {
- if (info->tag && info->tag[0]) {
- if (!strcmp(name, info->name) &&
- !strcmp(tag, info->tag)) {
- info->vid = vid;
- info->nr_copies = i->nr_copies;
- }
- } else if (info->snapid) {
- if (!strcmp(name, info->name) &&
- snapid == info->snapid) {
- info->vid = vid;
- info->nr_copies = i->nr_copies;
- }
- } else {
- if (!strcmp(name, info->name)) {
- info->vid = vid;
- info->nr_copies = i->nr_copies;
- }
- }
- }
-}
-
-typedef int (*obj_parser_func_t)(const char *sheep, uint64_t oid,
- struct sd_rsp *rsp, char *buf, void *data);
-
-static int do_print_obj(const char *sheep, uint64_t oid, struct sd_rsp *rsp,
- char *buf, void *data)
-{
- switch (rsp->result) {
- case SD_RES_SUCCESS:
- printf("%s has the object (should be %d copies)\n",
- sheep, rsp->obj.copies);
- break;
- case SD_RES_NO_OBJ:
- printf("%s doesn't have the object\n", sheep);
- break;
- case SD_RES_OLD_NODE_VER:
- case SD_RES_NEW_NODE_VER:
- sd_err("The node list has changed: please try again");
- break;
- default:
- sd_err("%s: hit an unexpected error (%s)", sheep,
- sd_strerror(rsp->result));
- break;
- }
-
- return 0;
-}
-
-struct get_data_oid_info {
- bool success;
- uint64_t data_oid;
- unsigned idx;
-};
-
-static int get_data_oid(const char *sheep, uint64_t oid, struct sd_rsp *rsp,
- char *buf, void *data)
-{
- struct get_data_oid_info *info = data;
- struct sd_inode *inode = (struct sd_inode *)buf;
-
- switch (rsp->result) {
- case SD_RES_SUCCESS:
- if (info->success)
- break;
- info->success = true;
- if (inode->data_vdi_id[info->idx]) {
- info->data_oid = vid_to_data_oid(inode->data_vdi_id[info->idx], info->idx);
- return 1;
- }
- break;
- case SD_RES_NO_OBJ:
- break;
- case SD_RES_OLD_NODE_VER:
- case SD_RES_NEW_NODE_VER:
- sd_err("The node list has changed: please try again");
- break;
- default:
- sd_err("%s: hit an unexpected error (%s)", sheep,
- sd_strerror(rsp->result));
- break;
- }
-
- return 0;
-}
-
-static void parse_objs(uint64_t oid, obj_parser_func_t func, void *data, unsigned size)
-{
- int i, ret, cb_ret;
- char *buf;
-
- buf = xzalloc(size);
- for (i = 0; i < sd_nodes_nr; i++) {
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
-
- sd_init_req(&hdr, SD_OP_READ_PEER);
- hdr.data_length = size;
- hdr.flags = 0;
- hdr.epoch = sd_epoch;
-
- hdr.obj.oid = oid;
-
- ret = collie_exec_req(sd_nodes[i].nid.addr,
- sd_nodes[i].nid.port, &hdr, buf);
- if (ret < 0)
- continue;
-
- untrim_zero_blocks(buf, rsp->obj.offset, rsp->data_length,
- size);
-
- cb_ret = func(addr_to_str(sd_nodes[i].nid.addr,
- sd_nodes[i].nid.port),
- oid, rsp, buf, data);
- if (cb_ret)
- break;
- }
-
- free(buf);
-}
-
-
-static int vdi_list(int argc, char **argv)
-{
- const char *vdiname = argv[optind];
-
- if (!raw_output)
- printf(" Name Id Size Used Shared Creation time VDI id Copies Tag\n");
-
- if (vdiname) {
- struct get_vdi_info info;
- memset(&info, 0, sizeof(info));
- info.name = vdiname;
- if (parse_vdi(print_vdi_list, SD_INODE_SIZE, &info) < 0)
- return EXIT_SYSFAIL;
- return EXIT_SUCCESS;
- } else {
- if (parse_vdi(print_vdi_list, SD_INODE_SIZE, NULL) < 0)
- return EXIT_SYSFAIL;
- return EXIT_SUCCESS;
- }
-}
-
-static int vdi_tree(int argc, char **argv)
-{
- init_tree();
- if (parse_vdi(print_vdi_tree, SD_INODE_HEADER_SIZE, NULL) < 0)
- return EXIT_SYSFAIL;
- dump_tree();
-
- return EXIT_SUCCESS;
-}
-
-static int vdi_graph(int argc, char **argv)
-{
- /* print a header */
- printf("digraph G {\n");
- printf(" node [shape = \"box\", fontname = \"Courier\"];\n\n");
- printf(" \"0\" [shape = \"ellipse\", label = \"root\"];\n\n");
-
- if (parse_vdi(print_vdi_graph, SD_INODE_HEADER_SIZE, NULL) < 0)
- return EXIT_SYSFAIL;
-
- /* print a footer */
- printf("}\n");
-
- return EXIT_SUCCESS;
-}
-
-static int find_vdi_name(const char *vdiname, uint32_t snapid, const char *tag,
- uint32_t *vid, int for_snapshot)
-{
- int ret;
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
-
- memset(buf, 0, sizeof(buf));
- pstrcpy(buf, SD_MAX_VDI_LEN, vdiname);
- if (tag)
- pstrcpy(buf + SD_MAX_VDI_LEN, SD_MAX_VDI_TAG_LEN, tag);
-
- if (for_snapshot)
- sd_init_req(&hdr, SD_OP_GET_VDI_INFO);
- else
- sd_init_req(&hdr, SD_OP_LOCK_VDI);
- hdr.data_length = SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN;
- hdr.flags = SD_FLAG_CMD_WRITE;
- hdr.vdi.snapid = snapid;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, buf);
- if (ret < 0)
- return -1;
-
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("Cannot get VDI info for %s %d %s: %s", vdiname, snapid,
- tag, sd_strerror(rsp->result));
- return -1;
- }
- *vid = rsp->vdi.vdi_id;
-
- return 0;
-}
-
-static int read_vdi_obj(const char *vdiname, int snapid, const char *tag,
- uint32_t *pvid, struct sd_inode *inode,
- size_t size)
-{
- int ret;
- uint32_t vid;
-
- ret = find_vdi_name(vdiname, snapid, tag, &vid, 0);
- if (ret < 0) {
- sd_err("Failed to open VDI %s", vdiname);
- return EXIT_FAILURE;
- }
-
- ret = sd_read_object(vid_to_vdi_oid(vid), inode, size, 0, true);
- if (ret != SD_RES_SUCCESS) {
- if (snapid) {
- sd_err("Failed to read a snapshot %s:%d", vdiname,
- snapid);
- } else if (tag && tag[0]) {
- sd_err("Failed to read a snapshot %s:%s", vdiname, tag);
- } else {
- sd_err("Failed to read a vdi %s", vdiname);
- }
- return EXIT_FAILURE;
- }
-
- if (pvid)
- *pvid = vid;
-
- return EXIT_SUCCESS;
-}
-
-int do_vdi_create(const char *vdiname, int64_t vdi_size,
- uint32_t base_vid, uint32_t *vdi_id, bool snapshot,
- int nr_copies)
-{
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- int ret;
- char buf[SD_MAX_VDI_LEN];
-
- memset(buf, 0, sizeof(buf));
- pstrcpy(buf, SD_MAX_VDI_LEN, vdiname);
-
- sd_init_req(&hdr, SD_OP_NEW_VDI);
- hdr.flags = SD_FLAG_CMD_WRITE;
- hdr.data_length = SD_MAX_VDI_LEN;
-
- hdr.vdi.base_vdi_id = base_vid;
- hdr.vdi.snapid = snapshot ? 1 : 0;
- hdr.vdi.vdi_size = vdi_size;
- hdr.vdi.copies = nr_copies;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, buf);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("Failed to create VDI %s: %s", vdiname,
- sd_strerror(rsp->result));
- return EXIT_FAILURE;
- }
-
- if (vdi_id)
- *vdi_id = rsp->vdi.vdi_id;
-
- return EXIT_SUCCESS;
-}
-
-static int vdi_create(int argc, char **argv)
-{
- const char *vdiname = argv[optind++];
- uint64_t size;
- uint32_t vid;
- uint64_t oid;
- int idx, max_idx, ret, nr_copies = vdi_cmd_data.nr_copies;
- struct sd_inode *inode = NULL;
-
- if (!argv[optind]) {
- sd_err("Please specify the VDI size");
- return EXIT_USAGE;
- }
- ret = parse_option_size(argv[optind], &size);
- if (ret < 0)
- return EXIT_USAGE;
- if (size > SD_MAX_VDI_SIZE) {
- sd_err("VDI size is too large");
- return EXIT_USAGE;
- }
-
- if (nr_copies > sd_nodes_nr) {
- sd_err("There are not enough nodes(%d) to hold the copies(%d)",
- sd_nodes_nr, nr_copies);
- return EXIT_USAGE;
- }
-
- ret = do_vdi_create(vdiname, size, 0, &vid, false,
- vdi_cmd_data.nr_copies);
- if (ret != EXIT_SUCCESS || !vdi_cmd_data.prealloc)
- goto out;
-
- inode = xmalloc(sizeof(*inode));
-
- ret = sd_read_object(vid_to_vdi_oid(vid), inode, sizeof(*inode), 0, true);
- if (ret != SD_RES_SUCCESS) {
- sd_err("Failed to read a newly created VDI object");
- ret = EXIT_FAILURE;
- goto out;
- }
- max_idx = DIV_ROUND_UP(size, SD_DATA_OBJ_SIZE);
-
- for (idx = 0; idx < max_idx; idx++) {
- vdi_show_progress(idx * SD_DATA_OBJ_SIZE, inode->vdi_size);
- oid = vid_to_data_oid(vid, idx);
-
- ret = sd_write_object(oid, 0, NULL, 0, 0, 0, inode->nr_copies,
- true, true);
- if (ret != SD_RES_SUCCESS) {
- ret = EXIT_FAILURE;
- goto out;
- }
-
- inode->data_vdi_id[idx] = vid;
- ret = sd_write_object(vid_to_vdi_oid(vid), 0, &vid, sizeof(vid),
- SD_INODE_HEADER_SIZE + sizeof(vid) * idx, 0,
- inode->nr_copies, false, true);
- if (ret) {
- ret = EXIT_FAILURE;
- goto out;
- }
- }
- vdi_show_progress(idx * SD_DATA_OBJ_SIZE, inode->vdi_size);
- ret = EXIT_SUCCESS;
-
- if (verbose) {
- if (raw_output)
- printf("%x\n", vid);
- else
- printf("VDI ID of newly created VDI: %x\n", vid);
- }
-
-out:
- free(inode);
- return ret;
-}
-
-static int vdi_snapshot(int argc, char **argv)
-{
- const char *vdiname = argv[optind++];
- uint32_t vid;
- int ret;
- char buf[SD_INODE_HEADER_SIZE];
- struct sd_inode *inode = (struct sd_inode *)buf;
-
- if (vdi_cmd_data.snapshot_id != 0) {
- sd_err("Please specify a non-integer value for "
- "a snapshot tag name");
- return EXIT_USAGE;
- }
-
- ret = read_vdi_obj(vdiname, 0, "", &vid, inode, SD_INODE_HEADER_SIZE);
- if (ret != EXIT_SUCCESS)
- return ret;
-
- ret = sd_write_object(vid_to_vdi_oid(vid), 0, vdi_cmd_data.snapshot_tag,
- SD_MAX_VDI_TAG_LEN,
- offsetof(struct sd_inode, tag),
- 0, inode->nr_copies, false, false);
- if (ret != SD_RES_SUCCESS)
- return EXIT_FAILURE;
-
- ret = do_vdi_create(vdiname, inode->vdi_size, vid, NULL, true,
- inode->nr_copies);
-
- if (ret == EXIT_SUCCESS && verbose) {
- if (raw_output)
- printf("%x\n", vid);
- else
- printf("VDI ID of newly created snapshot: %x\n", vid);
- }
-
- return ret;
-}
-
-static int vdi_clone(int argc, char **argv)
-{
- const char *src_vdi = argv[optind++], *dst_vdi;
- uint32_t base_vid, new_vid;
- uint64_t oid;
- int idx, max_idx, ret;
- struct sd_inode *inode = NULL;
- char *buf = NULL;
-
- dst_vdi = argv[optind];
- if (!dst_vdi) {
- sd_err("Destination VDI name must be specified");
- ret = EXIT_USAGE;
- goto out;
- }
-
- if (!vdi_cmd_data.snapshot_id && !vdi_cmd_data.snapshot_tag[0]) {
- sd_err("Only snapshot VDIs can be cloned");
- sd_err("Please specify the '-s' option");
- ret = EXIT_USAGE;
- goto out;
- }
-
- inode = xmalloc(sizeof(*inode));
-
- ret = read_vdi_obj(src_vdi, vdi_cmd_data.snapshot_id,
- vdi_cmd_data.snapshot_tag, &base_vid, inode,
- SD_INODE_SIZE);
- if (ret != EXIT_SUCCESS)
- goto out;
-
- ret = do_vdi_create(dst_vdi, inode->vdi_size, base_vid, &new_vid, false,
- vdi_cmd_data.nr_copies);
- if (ret != EXIT_SUCCESS || !vdi_cmd_data.prealloc)
- goto out;
-
- buf = xzalloc(SD_DATA_OBJ_SIZE);
- max_idx = DIV_ROUND_UP(inode->vdi_size, SD_DATA_OBJ_SIZE);
-
- for (idx = 0; idx < max_idx; idx++) {
- vdi_show_progress(idx * SD_DATA_OBJ_SIZE, inode->vdi_size);
- if (inode->data_vdi_id[idx]) {
- oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
- ret = sd_read_object(oid, buf, SD_DATA_OBJ_SIZE, 0, true);
- if (ret) {
- ret = EXIT_FAILURE;
- goto out;
- }
- } else
- memset(buf, 0, SD_DATA_OBJ_SIZE);
-
- oid = vid_to_data_oid(new_vid, idx);
- ret = sd_write_object(oid, 0, buf, SD_DATA_OBJ_SIZE, 0, 0,
- inode->nr_copies, true, true);
- if (ret != SD_RES_SUCCESS) {
- ret = EXIT_FAILURE;
- goto out;
- }
-
- ret = sd_write_object(vid_to_vdi_oid(new_vid), 0, &new_vid, sizeof(new_vid),
- SD_INODE_HEADER_SIZE + sizeof(new_vid) * idx, 0,
- inode->nr_copies, false, true);
- if (ret) {
- ret = EXIT_FAILURE;
- goto out;
- }
- }
- vdi_show_progress(idx * SD_DATA_OBJ_SIZE, inode->vdi_size);
- ret = EXIT_SUCCESS;
-
- if (verbose) {
- if (raw_output)
- printf("%x\n", new_vid);
- else
- printf("VDI ID of newly created clone: %x\n", new_vid);
- }
-out:
- free(inode);
- free(buf);
- return ret;
-}
-
-static int vdi_resize(int argc, char **argv)
-{
- const char *vdiname = argv[optind++];
- uint64_t new_size;
- uint32_t vid;
- int ret;
- char buf[SD_INODE_HEADER_SIZE];
- struct sd_inode *inode = (struct sd_inode *)buf;
-
- if (!argv[optind]) {
- sd_err("Please specify the new size for the VDI");
- return EXIT_USAGE;
- }
- ret = parse_option_size(argv[optind], &new_size);
- if (ret < 0)
- return EXIT_USAGE;
- if (new_size > SD_MAX_VDI_SIZE) {
- sd_err("New VDI size is too large");
- return EXIT_USAGE;
- }
-
- ret = read_vdi_obj(vdiname, 0, "", &vid, inode, SD_INODE_HEADER_SIZE);
- if (ret != EXIT_SUCCESS)
- return ret;
-
- if (new_size < inode->vdi_size) {
- sd_err("Shrinking VDIs is not implemented");
- return EXIT_USAGE;
- }
- inode->vdi_size = new_size;
-
- ret = sd_write_object(vid_to_vdi_oid(vid), 0, inode, SD_INODE_HEADER_SIZE, 0,
- 0, inode->nr_copies, false, true);
- if (ret != SD_RES_SUCCESS) {
- sd_err("Failed to update an inode header");
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-static int do_vdi_delete(const char *vdiname, int snap_id, const char *snap_tag)
-{
- int ret;
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- char data[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
- uint32_t vid;
-
- ret = find_vdi_name(vdiname, snap_id, snap_tag, &vid, 0);
- if (ret < 0) {
- sd_err("Failed to open VDI %s", vdiname);
- return EXIT_FAILURE;
- }
-
- sd_init_req(&hdr, SD_OP_DELETE_CACHE);
- hdr.obj.oid = vid_to_vdi_oid(vid);
-
- ret = send_light_req(&hdr, sdhost, sdport);
- if (ret) {
- sd_err("failed to execute request");
- return EXIT_FAILURE;
- }
-
- sd_init_req(&hdr, SD_OP_DEL_VDI);
- hdr.flags = SD_FLAG_CMD_WRITE;
- hdr.data_length = sizeof(data);
- hdr.vdi.snapid = snap_id;
- memset(data, 0, sizeof(data));
- pstrcpy(data, SD_MAX_VDI_LEN, vdiname);
- if (snap_tag)
- pstrcpy(data + SD_MAX_VDI_LEN, SD_MAX_VDI_TAG_LEN, snap_tag);
-
- ret = collie_exec_req(sdhost, sdport, &hdr, data);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("Failed to delete %s: %s", vdiname,
- sd_strerror(rsp->result));
- if (rsp->result == SD_RES_NO_VDI)
- return EXIT_MISSING;
- else
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-static int vdi_delete(int argc, char **argv)
-{
- char *vdiname = argv[optind];
-
- return do_vdi_delete(vdiname, vdi_cmd_data.snapshot_id,
- vdi_cmd_data.snapshot_tag);
-}
-
-static int vdi_rollback(int argc, char **argv)
-{
- const char *vdiname = argv[optind++];
- uint32_t base_vid, new_vid;
- int ret;
- char buf[SD_INODE_HEADER_SIZE];
- struct sd_inode *inode = (struct sd_inode *)buf;
-
- if (!vdi_cmd_data.snapshot_id && !vdi_cmd_data.snapshot_tag[0]) {
- sd_err("Please specify the '-s' option");
- return EXIT_USAGE;
- }
-
- ret = read_vdi_obj(vdiname, vdi_cmd_data.snapshot_id,
- vdi_cmd_data.snapshot_tag, &base_vid, inode,
- SD_INODE_HEADER_SIZE);
- if (ret != EXIT_SUCCESS)
- return ret;
-
- if (!vdi_cmd_data.force)
- confirm("This operation dicards any changes made since the"
- " previous\nsnapshot was taken. Continue? [yes/no]: ");
-
- ret = do_vdi_delete(vdiname, 0, NULL);
- if (ret != SD_RES_SUCCESS) {
- sd_err("Failed to delete the current state");
- return EXIT_FAILURE;
- }
-
- ret = do_vdi_create(vdiname, inode->vdi_size, base_vid, &new_vid,
- false, vdi_cmd_data.nr_copies);
-
- if (ret == EXIT_SUCCESS && verbose) {
- if (raw_output)
- printf("%x\n", new_vid);
- else
- printf("New VDI ID of rollbacked VDI: %x\n", new_vid);
- }
-
- return ret;
-}
-
-static int vdi_object(int argc, char **argv)
-{
- const char *vdiname = argv[optind];
- unsigned idx = vdi_cmd_data.index;
- struct get_vdi_info info;
- uint32_t vid;
-
- memset(&info, 0, sizeof(info));
- info.name = vdiname;
- info.tag = vdi_cmd_data.snapshot_tag;
- info.vid = 0;
- info.snapid = vdi_cmd_data.snapshot_id;
-
- if (parse_vdi(get_oid, SD_INODE_HEADER_SIZE, &info) < 0)
- return EXIT_SYSFAIL;
-
- vid = info.vid;
- if (vid == 0) {
- sd_err("VDI not found");
- return EXIT_MISSING;
- }
-
- if (idx == ~0) {
- printf("Looking for the inode object 0x%" PRIx32 " with %d nodes\n\n",
- vid, sd_nodes_nr);
- parse_objs(vid_to_vdi_oid(vid), do_print_obj, NULL, SD_INODE_SIZE);
- } else {
- struct get_data_oid_info oid_info = {0};
-
- oid_info.success = false;
- oid_info.idx = idx;
-
- if (idx >= MAX_DATA_OBJS) {
- printf("The offset is too large!\n");
- exit(EXIT_FAILURE);
- }
-
- parse_objs(vid_to_vdi_oid(vid), get_data_oid, &oid_info, SD_DATA_OBJ_SIZE);
-
- if (oid_info.success) {
- if (oid_info.data_oid) {
- printf("Looking for the object 0x%" PRIx64
- " (the inode vid 0x%" PRIx32 " idx %u) with %d nodes\n\n",
- oid_info.data_oid, vid, idx, sd_nodes_nr);
-
- parse_objs(oid_info.data_oid, do_print_obj, NULL, SD_DATA_OBJ_SIZE);
- } else
- printf("The inode object 0x%" PRIx32 " idx %u is not allocated\n",
- vid, idx);
- } else
- sd_err("Failed to read the inode object 0x%" PRIx32,
- vid);
- }
-
- return EXIT_SUCCESS;
-}
-
-static int do_track_object(uint64_t oid, uint8_t nr_copies)
-{
- int i, j, ret;
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- struct sd_vnode *vnodes;
- const struct sd_vnode *vnode_buf[SD_MAX_COPIES];
- struct epoch_log *logs;
- int vnodes_nr, nr_logs, log_length;
-
- log_length = sd_epoch * sizeof(struct epoch_log);
- logs = xmalloc(log_length);
- vnodes = xmalloc(sizeof(*vnodes) * SD_MAX_VNODES);
-
- sd_init_req(&hdr, SD_OP_STAT_CLUSTER);
- hdr.data_length = log_length;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, logs);
- if (ret < 0)
- goto error;
-
- if (rsp->result != SD_RES_SUCCESS) {
- printf("%s\n", sd_strerror(rsp->result));
- goto error;
- }
-
- nr_logs = rsp->data_length / sizeof(struct epoch_log);
- for (i = nr_logs - 1; i >= 0; i--) {
- printf("\nobj %"PRIx64" locations at epoch %d, copies = %d\n",
- oid, logs[i].epoch, nr_copies);
- printf("---------------------------------------------------\n");
-
- /*
- * When # of nodes is less than nr_copies, we only print
- * remaining nodes that holds all the remaining copies.
- */
- if (logs[i].nr_nodes < nr_copies) {
- for (j = 0; j < logs[i].nr_nodes; j++) {
- const struct node_id *n = &logs[i].nodes[j].nid;
-
- printf("%s\n", addr_to_str(n->addr, n->port));
- }
- continue;
- }
- vnodes_nr = nodes_to_vnodes(logs[i].nodes,
- logs[i].nr_nodes, vnodes);
- oid_to_vnodes(vnodes, vnodes_nr, oid, nr_copies, vnode_buf);
- for (j = 0; j < nr_copies; j++) {
- const struct node_id *n = &vnode_buf[j]->nid;
-
- printf("%s\n", addr_to_str(n->addr, n->port));
- }
- }
-
- free(logs);
- free(vnodes);
- return EXIT_SUCCESS;
-error:
- free(logs);
- free(vnodes);
- return EXIT_SYSFAIL;
-}
-
-static int vdi_track(int argc, char **argv)
-{
- const char *vdiname = argv[optind];
- unsigned idx = vdi_cmd_data.index;
- struct get_vdi_info info;
- struct get_data_oid_info oid_info = {0};
- uint32_t vid;
- uint8_t nr_copies;
-
- memset(&info, 0, sizeof(info));
- info.name = vdiname;
- info.tag = vdi_cmd_data.snapshot_tag;
- info.vid = 0;
- info.snapid = vdi_cmd_data.snapshot_id;
-
- if (parse_vdi(get_oid, SD_INODE_HEADER_SIZE, &info) < 0)
- return EXIT_SYSFAIL;
-
- vid = info.vid;
- nr_copies = info.nr_copies;
- if (vid == 0) {
- sd_err("VDI not found");
- return EXIT_MISSING;
- }
-
- if (idx == ~0) {
- printf("Tracking the inode object 0x%" PRIx32 " with %d nodes\n",
- vid, sd_nodes_nr);
- return do_track_object(vid_to_vdi_oid(vid), nr_copies);
- }
-
- oid_info.success = false;
- oid_info.idx = idx;
-
- if (idx >= MAX_DATA_OBJS) {
- printf("The offset is too large!\n");
- goto err;
- }
-
- parse_objs(vid_to_vdi_oid(vid), get_data_oid,
- &oid_info, SD_DATA_OBJ_SIZE);
-
- if (!oid_info.success) {
- sd_err("Failed to read the inode object 0x%" PRIx32, vid);
- goto err;
- }
- if (!oid_info.data_oid) {
- printf("The inode object 0x%"PRIx32" idx %u is not allocated\n",
- vid, idx);
- goto err;
- }
- printf("Tracking the object 0x%" PRIx64
- " (the inode vid 0x%" PRIx32 " idx %u)"
- " with %d nodes\n",
- oid_info.data_oid, vid, idx, sd_nodes_nr);
- return do_track_object(oid_info.data_oid, nr_copies);
-err:
- return EXIT_FAILURE;
-}
-
-static int find_vdi_attr_oid(const char *vdiname, const char *tag, uint32_t snapid,
- const char *key, void *value, unsigned int value_len,
- uint32_t *vid, uint64_t *oid, unsigned int *nr_copies,
- bool create, bool excl, bool delete)
-{
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- int ret;
- struct sheepdog_vdi_attr vattr;
-
- memset(&vattr, 0, sizeof(vattr));
- pstrcpy(vattr.name, SD_MAX_VDI_LEN, vdiname);
- pstrcpy(vattr.tag, SD_MAX_VDI_TAG_LEN, vdi_cmd_data.snapshot_tag);
- vattr.snap_id = vdi_cmd_data.snapshot_id;
- pstrcpy(vattr.key, SD_MAX_VDI_ATTR_KEY_LEN, key);
- if (value && value_len) {
- vattr.value_len = value_len;
- memcpy(vattr.value, value, value_len);
- }
-
- sd_init_req(&hdr, SD_OP_GET_VDI_ATTR);
- hdr.flags = SD_FLAG_CMD_WRITE;
- hdr.data_length = SD_ATTR_OBJ_SIZE;
- hdr.vdi.snapid = vdi_cmd_data.snapshot_id;
-
- if (create)
- hdr.flags |= SD_FLAG_CMD_CREAT;
- if (excl)
- hdr.flags |= SD_FLAG_CMD_EXCL;
- if (delete)
- hdr.flags |= SD_FLAG_CMD_DEL;
-
- ret = collie_exec_req(sdhost, sdport, &hdr, &vattr);
- if (ret < 0)
- return SD_RES_EIO;
-
- if (rsp->result != SD_RES_SUCCESS)
- return rsp->result;
-
- *vid = rsp->vdi.vdi_id;
- *oid = vid_to_attr_oid(rsp->vdi.vdi_id, rsp->vdi.attr_id);
- *nr_copies = rsp->vdi.copies;
-
- return SD_RES_SUCCESS;
-}
-
-static int vdi_setattr(int argc, char **argv)
-{
- int ret, value_len = 0;
- uint64_t attr_oid = 0;
- uint32_t vid = 0, nr_copies = 0;
- const char *vdiname = argv[optind++], *key;
- char *value;
- uint64_t offset;
-
- key = argv[optind++];
- if (!key) {
- sd_err("Please specify the attribute key");
- return EXIT_USAGE;
- }
-
- value = argv[optind++];
- if (!value && !vdi_cmd_data.delete) {
- value = xmalloc(SD_MAX_VDI_ATTR_VALUE_LEN);
-
- offset = 0;
-reread:
- ret = read(STDIN_FILENO, value + offset,
- SD_MAX_VDI_ATTR_VALUE_LEN - offset);
- if (ret < 0) {
- sd_err("Failed to read attribute value from stdin: %m");
- return EXIT_SYSFAIL;
- }
- if (ret > 0) {
- offset += ret;
- goto reread;
- }
- }
-
- if (value)
- value_len = strlen(value);
-
- ret = find_vdi_attr_oid(vdiname, vdi_cmd_data.snapshot_tag,
- vdi_cmd_data.snapshot_id, key, value,
- value_len, &vid, &attr_oid,
- &nr_copies, !vdi_cmd_data.delete,
- vdi_cmd_data.exclusive, vdi_cmd_data.delete);
- if (ret) {
- if (ret == SD_RES_VDI_EXIST) {
- sd_err("The attribute '%s' already exists", key);
- return EXIT_EXISTS;
- } else if (ret == SD_RES_NO_OBJ) {
- sd_err("Attribute '%s' not found", key);
- return EXIT_MISSING;
- } else if (ret == SD_RES_NO_VDI) {
- sd_err("VDI not found");
- return EXIT_MISSING;
- } else
- sd_err("Failed to set attribute: %s", sd_strerror(ret));
- return EXIT_FAILURE;
- }
-
- return EXIT_SUCCESS;
-}
-
-static int vdi_getattr(int argc, char **argv)
-{
- int ret;
- uint64_t oid, attr_oid = 0;
- uint32_t vid = 0, nr_copies = 0;
- const char *vdiname = argv[optind++], *key;
- struct sheepdog_vdi_attr vattr;
-
- key = argv[optind++];
- if (!key) {
- sd_err("Please specify the attribute key");
- return EXIT_USAGE;
- }
-
- ret = find_vdi_attr_oid(vdiname, vdi_cmd_data.snapshot_tag,
- vdi_cmd_data.snapshot_id, key, NULL, 0, &vid,
- &attr_oid, &nr_copies, false, false, false);
- if (ret == SD_RES_NO_OBJ) {
- sd_err("Attribute '%s' not found", key);
- return EXIT_MISSING;
- } else if (ret == SD_RES_NO_VDI) {
- sd_err("VDI not found");
- return EXIT_MISSING;
- } else if (ret) {
- sd_err("Failed to find attribute oid: %s", sd_strerror(ret));
- return EXIT_MISSING;
- }
-
- oid = attr_oid;
-
- ret = sd_read_object(oid, &vattr, SD_ATTR_OBJ_SIZE, 0, true);
- if (ret != SD_RES_SUCCESS) {
- sd_err("Failed to read attribute oid: %s", sd_strerror(ret));
- return EXIT_SYSFAIL;
- }
-
- xwrite(STDOUT_FILENO, vattr.value, vattr.value_len);
- return EXIT_SUCCESS;
-}
-
-static int vdi_read(int argc, char **argv)
-{
- const char *vdiname = argv[optind++];
- int ret, idx;
- struct sd_inode *inode = NULL;
- uint64_t offset = 0, oid, done = 0, total = (uint64_t) -1;
- unsigned int len;
- char *buf = NULL;
-
- if (argv[optind]) {
- ret = parse_option_size(argv[optind++], &offset);
- if (ret < 0)
- return EXIT_USAGE;
- if (argv[optind]) {
- ret = parse_option_size(argv[optind++], &total);
- if (ret < 0)
- return EXIT_USAGE;
- }
- }
-
- inode = malloc(sizeof(*inode));
- buf = xmalloc(SD_DATA_OBJ_SIZE);
-
- ret = read_vdi_obj(vdiname, vdi_cmd_data.snapshot_id,
- vdi_cmd_data.snapshot_tag, NULL, inode,
- SD_INODE_SIZE);
- if (ret != EXIT_SUCCESS)
- goto out;
-
- if (inode->vdi_size < offset) {
- sd_err("Read offset is beyond the end of the VDI");
- ret = EXIT_FAILURE;
- goto out;
- }
-
- total = min(total, inode->vdi_size - offset);
- idx = offset / SD_DATA_OBJ_SIZE;
- offset %= SD_DATA_OBJ_SIZE;
- while (done < total) {
- len = min(total - done, SD_DATA_OBJ_SIZE - offset);
-
- if (inode->data_vdi_id[idx]) {
- oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
- ret = sd_read_object(oid, buf, len, offset, false);
- if (ret != SD_RES_SUCCESS) {
- sd_err("Failed to read VDI");
- ret = EXIT_FAILURE;
- goto out;
- }
- } else
- memset(buf, 0, len);
-
- ret = xwrite(STDOUT_FILENO, buf, len);
- if (ret < 0) {
- sd_err("Failed to write to stdout: %m");
- ret = EXIT_SYSFAIL;
- goto out;
- }
-
- offset = 0;
- idx++;
- done += len;
- }
- fsync(STDOUT_FILENO);
- ret = EXIT_SUCCESS;
-out:
- free(inode);
- free(buf);
-
- return ret;
-}
-
-static int vdi_write(int argc, char **argv)
-{
- const char *vdiname = argv[optind++];
- uint32_t vid, flags;
- int ret, idx;
- struct sd_inode *inode = NULL;
- uint64_t offset = 0, oid, old_oid, done = 0, total = (uint64_t) -1;
- unsigned int len;
- char *buf = NULL;
- bool create;
-
- if (argv[optind]) {
- ret = parse_option_size(argv[optind++], &offset);
- if (ret < 0)
- return EXIT_USAGE;
- if (argv[optind]) {
- ret = parse_option_size(argv[optind++], &total);
- if (ret < 0)
- return EXIT_USAGE;
- }
- }
-
- inode = xmalloc(sizeof(*inode));
- buf = xmalloc(SD_DATA_OBJ_SIZE);
-
- ret = read_vdi_obj(vdiname, 0, "", &vid, inode, SD_INODE_SIZE);
- if (ret != EXIT_SUCCESS)
- goto out;
-
- if (inode->vdi_size < offset) {
- sd_err("Write offset is beyond the end of the VDI");
- ret = EXIT_FAILURE;
- goto out;
- }
-
- total = min(total, inode->vdi_size - offset);
- idx = offset / SD_DATA_OBJ_SIZE;
- offset %= SD_DATA_OBJ_SIZE;
- while (done < total) {
- create = false;
- old_oid = 0;
- flags = 0;
- len = min(total - done, SD_DATA_OBJ_SIZE - offset);
-
- if (!inode->data_vdi_id[idx])
- create = true;
- else if (!is_data_obj_writeable(inode, idx)) {
- create = true;
- old_oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
- }
-
- if (vdi_cmd_data.writeback)
- flags |= SD_FLAG_CMD_CACHE;
-
- ret = xread(STDIN_FILENO, buf, len);
- if (ret < 0) {
- sd_err("Failed to read from stdin: %m");
- ret = EXIT_SYSFAIL;
- goto out;
- } else if (ret < len) {
- /* exit after this buffer is sent */
- memset(buf + ret, 0, len - ret);
- total = done + len;
- }
-
- inode->data_vdi_id[idx] = inode->vdi_id;
- oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
- ret = sd_write_object(oid, old_oid, buf, len, offset, flags,
- inode->nr_copies, create, false);
- if (ret != SD_RES_SUCCESS) {
- sd_err("Failed to write VDI");
- ret = EXIT_FAILURE;
- goto out;
- }
-
- if (create) {
- ret = sd_write_object(vid_to_vdi_oid(vid), 0, &vid, sizeof(vid),
- SD_INODE_HEADER_SIZE + sizeof(vid) * idx,
- flags, inode->nr_copies, false, false);
- if (ret) {
- ret = EXIT_FAILURE;
- goto out;
- }
- }
-
- offset += len;
- if (offset == SD_DATA_OBJ_SIZE) {
- offset = 0;
- idx++;
- }
- done += len;
- }
- ret = EXIT_SUCCESS;
-out:
- free(inode);
- free(buf);
-
- return ret;
-}
-
-static void *read_object_from(const struct sd_vnode *vnode, uint64_t oid)
-{
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- int ret;
- void *buf;
- size_t size = get_objsize(oid);
-
- buf = xmalloc(size);
-
- sd_init_req(&hdr, SD_OP_READ_PEER);
- hdr.epoch = sd_epoch;
- hdr.flags = 0;
- hdr.data_length = size;
-
- hdr.obj.oid = oid;
-
- ret = collie_exec_req(vnode->nid.addr, vnode->nid.port, &hdr, buf);
-
- if (ret < 0)
- exit(EXIT_SYSFAIL);
-
- switch (rsp->result) {
- case SD_RES_SUCCESS:
- untrim_zero_blocks(buf, rsp->obj.offset, rsp->data_length,
- size);
- break;
- case SD_RES_NO_OBJ:
- free(buf);
- return NULL;
- default:
- sd_err("FATAL: failed to read %"PRIx64", %s", oid,
- sd_strerror(rsp->result));
- exit(EXIT_FAILURE);
- }
- return buf;
-}
-
-static void write_object_to(const struct sd_vnode *vnode, uint64_t oid,
- void *buf, bool create)
-{
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- int ret;
-
- if (create)
- sd_init_req(&hdr, SD_OP_CREATE_AND_WRITE_PEER);
- else
- sd_init_req(&hdr, SD_OP_WRITE_PEER);
- hdr.epoch = sd_epoch;
- hdr.flags = SD_FLAG_CMD_WRITE;
- hdr.data_length = get_objsize(oid);
- hdr.obj.oid = oid;
-
- ret = collie_exec_req(vnode->nid.addr, vnode->nid.port, &hdr, buf);
-
- if (ret < 0)
- exit(EXIT_SYSFAIL);
-
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("FATAL: failed to write %"PRIx64", %s", oid,
- sd_strerror(rsp->result));
- exit(EXIT_FAILURE);
- }
-}
-
-struct vdi_check_work {
- struct vdi_check_info *info;
- const struct sd_vnode *vnode;
- uint8_t hash[SHA1_DIGEST_SIZE];
- bool object_found;
- struct work work;
-};
-
-struct vdi_check_info {
- uint64_t oid;
- int nr_copies;
- uint64_t total;
- uint64_t *done;
- int refcnt;
- struct work_queue *wq;
- struct vdi_check_work *base;
- struct vdi_check_work vcw[0];
-};
-
-static void free_vdi_check_info(struct vdi_check_info *info)
-{
- if (info->done) {
- *info->done += SD_DATA_OBJ_SIZE;
- vdi_show_progress(*info->done, info->total);
- }
- free(info);
-}
-
-static void vdi_repair_work(struct work *work)
-{
- struct vdi_check_work *vcw = container_of(work, struct vdi_check_work,
- work);
- struct vdi_check_info *info = vcw->info;
- void *buf;
-
- buf = read_object_from(info->base->vnode, info->oid);
- write_object_to(vcw->vnode, info->oid, buf, !vcw->object_found);
- free(buf);
-}
-
-static void vdi_repair_main(struct work *work)
-{
- struct vdi_check_work *vcw = container_of(work, struct vdi_check_work,
- work);
- struct vdi_check_info *info = vcw->info;
-
- if (vcw->object_found)
- fprintf(stdout, "fixed replica %"PRIx64"\n", info->oid);
- else
- fprintf(stdout, "fixed missing %"PRIx64"\n", info->oid);
-
- info->refcnt--;
- if (info->refcnt == 0)
- free_vdi_check_info(info);
-}
-
-static void vdi_hash_check_work(struct work *work)
-{
- struct vdi_check_work *vcw = container_of(work, struct vdi_check_work,
- work);
- struct vdi_check_info *info = vcw->info;
- int ret;
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
-
- sd_init_req(&hdr, SD_OP_GET_HASH);
- hdr.obj.oid = info->oid;
- hdr.obj.tgt_epoch = sd_epoch;
-
- ret = collie_exec_req(vcw->vnode->nid.addr, vcw->vnode->nid.port, &hdr,
- NULL);
- if (ret < 0)
- exit(EXIT_SYSFAIL);
-
- switch (ret) {
- case SD_RES_SUCCESS:
- vcw->object_found = true;
- memcpy(vcw->hash, rsp->hash.digest, sizeof(vcw->hash));
- uatomic_set(&info->base, vcw);
- break;
- case SD_RES_NO_OBJ:
- vcw->object_found = false;
- break;
- default:
- sd_err("failed to read %" PRIx64 " from %s, %s", info->oid,
- addr_to_str(vcw->vnode->nid.addr, vcw->vnode->nid.port),
- sd_strerror(ret));
- exit(EXIT_FAILURE);
- }
-}
-
-static void vdi_hash_check_main(struct work *work)
-{
- struct vdi_check_work *vcw = container_of(work, struct vdi_check_work,
- work);
- struct vdi_check_info *info = vcw->info;
-
- info->refcnt--;
- if (info->refcnt > 0)
- return;
-
- if (info->base == NULL) {
- sd_err("no node has %" PRIx64, info->oid);
- exit(EXIT_FAILURE);
- }
-
- for (int i = 0; i < info->nr_copies; i++) {
- if (&info->vcw[i] == info->base)
- continue;
- /* need repair when object not found or consistency broken */
- if (!info->vcw[i].object_found ||
- memcmp(info->base->hash, info->vcw[i].hash,
- sizeof(info->base->hash)) != 0) {
- info->vcw[i].work.fn = vdi_repair_work;
- info->vcw[i].work.done = vdi_repair_main;
- info->refcnt++;
- queue_work(info->wq, &info->vcw[i].work);
- }
- }
-
- if (info->refcnt == 0)
- free_vdi_check_info(info);
-}
-
-static void queue_vdi_check_work(struct sd_inode *inode, uint64_t oid,
- uint64_t *done, struct work_queue *wq)
-{
- struct vdi_check_info *info;
- const struct sd_vnode *tgt_vnodes[SD_MAX_COPIES];
- int nr_copies = inode->nr_copies;
-
- info = xzalloc(sizeof(*info) + sizeof(info->vcw[0]) * nr_copies);
- info->oid = oid;
- info->nr_copies = nr_copies;
- info->total = inode->vdi_size;
- info->done = done;
- info->wq = wq;
-
- oid_to_vnodes(sd_vnodes, sd_vnodes_nr, oid, nr_copies, tgt_vnodes);
- for (int i = 0; i < nr_copies; i++) {
- info->vcw[i].info = info;
- info->vcw[i].vnode = tgt_vnodes[i];
- info->vcw[i].work.fn = vdi_hash_check_work;
- info->vcw[i].work.done = vdi_hash_check_main;
- info->refcnt++;
- queue_work(info->wq, &info->vcw[i].work);
- }
-}
-
-static int vdi_check(int argc, char **argv)
-{
- const char *vdiname = argv[optind++];
- int ret, max_idx;
- uint64_t done = 0, oid;
- uint32_t vid;
- struct sd_inode *inode = xmalloc(sizeof(*inode));
- struct work_queue *wq;
-
- ret = read_vdi_obj(vdiname, vdi_cmd_data.snapshot_id,
- vdi_cmd_data.snapshot_tag, &vid, inode,
- SD_INODE_SIZE);
- if (ret != EXIT_SUCCESS) {
- sd_err("FATAL: no inode objects");
- goto out;
- }
- if (sd_nodes_nr < inode->nr_copies) {
- sd_err("ABORT: Not enough active nodes for consistency-check");
- return EXIT_FAILURE;
- }
-
- wq = create_work_queue("vdi check", WQ_DYNAMIC);
-
- queue_vdi_check_work(inode, vid_to_vdi_oid(vid), NULL, wq);
-
- max_idx = DIV_ROUND_UP(inode->vdi_size, SD_DATA_OBJ_SIZE);
- vdi_show_progress(done, inode->vdi_size);
- for (int idx = 0; idx < max_idx; idx++) {
- vid = inode->data_vdi_id[idx];
- if (vid) {
- oid = vid_to_data_oid(vid, idx);
- queue_vdi_check_work(inode, oid, &done, wq);
- } else {
- done += SD_DATA_OBJ_SIZE;
- vdi_show_progress(done, inode->vdi_size);
- }
- }
-
- work_queue_wait(wq);
-
- fprintf(stdout, "finish check&repair %s\n", vdiname);
- return EXIT_SUCCESS;
-out:
- return ret;
-}
-
-/* vdi backup format */
-
-#define VDI_BACKUP_FORMAT_VERSION 1
-#define VDI_BACKUP_MAGIC 0x11921192
-
-struct backup_hdr {
- uint32_t version;
- uint32_t magic;
-};
-
-struct obj_backup {
- uint32_t idx;
- uint32_t offset;
- uint32_t length;
- uint32_t reserved;
- uint8_t data[SD_DATA_OBJ_SIZE];
-};
-
-/* discards redundant area from backup data */
-static void compact_obj_backup(struct obj_backup *backup, uint8_t *from_data)
-{
- uint8_t *p1, *p2;
-
- p1 = backup->data;
- p2 = from_data;
- while (backup->length > 0 && memcmp(p1, p2, SECTOR_SIZE) == 0) {
- p1 += SECTOR_SIZE;
- p2 += SECTOR_SIZE;
- backup->offset += SECTOR_SIZE;
- backup->length -= SECTOR_SIZE;
- }
-
- p1 = backup->data + SD_DATA_OBJ_SIZE - SECTOR_SIZE;
- p2 = from_data + SD_DATA_OBJ_SIZE - SECTOR_SIZE;
- while (backup->length > 0 && memcmp(p1, p2, SECTOR_SIZE) == 0) {
- p1 -= SECTOR_SIZE;
- p2 -= SECTOR_SIZE;
- backup->length -= SECTOR_SIZE;
- }
-}
-
-static int get_obj_backup(int idx, uint32_t from_vid, uint32_t to_vid,
- struct obj_backup *backup)
-{
- int ret;
- uint8_t *from_data = xzalloc(SD_DATA_OBJ_SIZE);
-
- backup->idx = idx;
- backup->offset = 0;
- backup->length = SD_DATA_OBJ_SIZE;
-
- if (to_vid) {
- ret = sd_read_object(vid_to_data_oid(to_vid, idx), backup->data,
- SD_DATA_OBJ_SIZE, 0, true);
- if (ret != SD_RES_SUCCESS) {
- sd_err("Failed to read object %" PRIx32 ", %d", to_vid,
- idx);
- return EXIT_FAILURE;
- }
- } else
- memset(backup->data, 0, SD_DATA_OBJ_SIZE);
-
- if (from_vid) {
- ret = sd_read_object(vid_to_data_oid(from_vid, idx), from_data,
- SD_DATA_OBJ_SIZE, 0, true);
- if (ret != SD_RES_SUCCESS) {
- sd_err("Failed to read object %" PRIx32 ", %d",
- from_vid, idx);
- return EXIT_FAILURE;
- }
- }
-
- compact_obj_backup(backup, from_data);
-
- free(from_data);
-
- return EXIT_SUCCESS;
-}
-
-static int vdi_backup(int argc, char **argv)
-{
- const char *vdiname = argv[optind++];
- int ret = EXIT_SUCCESS, idx, nr_objs;
- struct sd_inode *from_inode = xzalloc(sizeof(*from_inode));
- struct sd_inode *to_inode = xzalloc(sizeof(*to_inode));
- struct backup_hdr hdr = {
- .version = VDI_BACKUP_FORMAT_VERSION,
- .magic = VDI_BACKUP_MAGIC,
- };
- struct obj_backup *backup = xzalloc(sizeof(*backup));
-
- if ((!vdi_cmd_data.snapshot_id && !vdi_cmd_data.snapshot_tag[0]) ||
- (!vdi_cmd_data.from_snapshot_id &&
- !vdi_cmd_data.from_snapshot_tag[0])) {
- sd_err("Please specify snapshots with '-F' and '-s' options");
- ret = EXIT_USAGE;
- goto out;
- }
-
- ret = read_vdi_obj(vdiname, vdi_cmd_data.from_snapshot_id,
- vdi_cmd_data.from_snapshot_tag, NULL,
- from_inode, SD_INODE_SIZE);
- if (ret != EXIT_SUCCESS)
- goto out;
-
- ret = read_vdi_obj(vdiname, vdi_cmd_data.snapshot_id,
- vdi_cmd_data.snapshot_tag, NULL, to_inode,
- SD_INODE_SIZE);
- if (ret != EXIT_SUCCESS)
- goto out;
-
- nr_objs = DIV_ROUND_UP(to_inode->vdi_size, SD_DATA_OBJ_SIZE);
-
- ret = xwrite(STDOUT_FILENO, &hdr, sizeof(hdr));
- if (ret < 0) {
- sd_err("failed to write backup header, %m");
- ret = EXIT_SYSFAIL;
- goto out;
- }
-
- for (idx = 0; idx < nr_objs; idx++) {
- uint32_t from_vid = from_inode->data_vdi_id[idx];
- uint32_t to_vid = to_inode->data_vdi_id[idx];
-
- if (to_vid == 0 && from_vid == 0)
- continue;
-
- ret = get_obj_backup(idx, from_vid, to_vid, backup);
- if (ret != EXIT_SUCCESS)
- goto out;
-
- if (backup->length == 0)
- continue;
-
- ret = xwrite(STDOUT_FILENO, backup,
- sizeof(*backup) - sizeof(backup->data));
- if (ret < 0) {
- sd_err("failed to write backup data, %m");
- ret = EXIT_SYSFAIL;
- goto out;
- }
- ret = xwrite(STDOUT_FILENO, backup->data + backup->offset,
- backup->length);
- if (ret < 0) {
- sd_err("failed to write backup data, %m");
- ret = EXIT_SYSFAIL;
- goto out;
- }
- }
-
- /* write end marker */
- memset(backup, 0, sizeof(*backup) - sizeof(backup->data));
- backup->idx = UINT32_MAX;
- ret = xwrite(STDOUT_FILENO, backup,
- sizeof(*backup) - sizeof(backup->data));
- if (ret < 0) {
- sd_err("failed to write end marker, %m");
- ret = EXIT_SYSFAIL;
- goto out;
- }
-
- fsync(STDOUT_FILENO);
-out:
- free(from_inode);
- free(to_inode);
- free(backup);
- return ret;
-}
-
-/* restore backup data to vdi */
-static int restore_obj(struct obj_backup *backup, uint32_t vid,
- struct sd_inode *parent_inode)
-{
- int ret;
- uint32_t parent_vid = parent_inode->data_vdi_id[backup->idx];
- uint64_t parent_oid = 0;
-
- if (parent_vid)
- parent_oid = vid_to_data_oid(parent_vid, backup->idx);
-
- /* send a copy-on-write request */
- ret = sd_write_object(vid_to_data_oid(vid, backup->idx), parent_oid,
- backup->data, backup->length, backup->offset,
- 0, parent_inode->nr_copies, true, true);
- if (ret != SD_RES_SUCCESS)
- return ret;
-
- return sd_write_object(vid_to_vdi_oid(vid), 0, &vid, sizeof(vid),
- SD_INODE_HEADER_SIZE + sizeof(vid) * backup->idx,
- 0, parent_inode->nr_copies, false, true);
-}
-
-static uint32_t do_restore(const char *vdiname, int snapid, const char *tag)
-{
- int ret;
- uint32_t vid;
- struct backup_hdr hdr;
- struct obj_backup *backup = xzalloc(sizeof(*backup));
- struct sd_inode *inode = xzalloc(sizeof(*inode));
-
- ret = xread(STDIN_FILENO, &hdr, sizeof(hdr));
- if (ret != sizeof(hdr))
- sd_err("failed to read backup header, %m");
-
- if (hdr.version != VDI_BACKUP_FORMAT_VERSION ||
- hdr.magic != VDI_BACKUP_MAGIC) {
- sd_err("The backup file is corrupted");
- ret = EXIT_SYSFAIL;
- goto out;
- }
-
- ret = read_vdi_obj(vdiname, snapid, tag, NULL, inode, SD_INODE_SIZE);
- if (ret != EXIT_SUCCESS)
- goto out;
-
- ret = do_vdi_create(vdiname, inode->vdi_size, inode->vdi_id, &vid,
- false, inode->nr_copies);
- if (ret != EXIT_SUCCESS) {
- sd_err("Failed to read VDI");
- goto out;
- }
-
- while (true) {
- ret = xread(STDIN_FILENO, backup,
- sizeof(*backup) - sizeof(backup->data));
- if (ret != sizeof(*backup) - sizeof(backup->data)) {
- sd_err("failed to read backup data");
- ret = EXIT_SYSFAIL;
- break;
- }
-
- if (backup->idx == UINT32_MAX) {
- ret = EXIT_SUCCESS;
- break;
- }
-
- ret = xread(STDIN_FILENO, backup->data, backup->length);
- if (ret != backup->length) {
- sd_err("failed to read backup data");
- ret = EXIT_SYSFAIL;
- break;
- }
-
- ret = restore_obj(backup, vid, inode);
- if (ret != SD_RES_SUCCESS) {
- sd_err("failed to restore backup");
- do_vdi_delete(vdiname, 0, NULL);
- ret = EXIT_FAILURE;
- break;
- }
- }
-out:
- free(backup);
- free(inode);
-
- return ret;
-}
-
-static int vdi_restore(int argc, char **argv)
-{
- const char *vdiname = argv[optind++];
- int ret;
- char buf[SD_INODE_HEADER_SIZE] = {0};
- struct sd_inode *current_inode = xzalloc(sizeof(*current_inode));
- struct sd_inode *parent_inode = (struct sd_inode *)buf;
- bool need_current_recovery = false;
-
- if (!vdi_cmd_data.snapshot_id && !vdi_cmd_data.snapshot_tag[0]) {
- sd_err("We can restore a backup file only to snapshots");
- sd_err("Please specify the '-s' option");
- ret = EXIT_USAGE;
- goto out;
- }
-
- /*
- * delete the current vdi temporarily first to avoid making
- * the current state become snapshot
- */
- ret = read_vdi_obj(vdiname, 0, "", NULL, current_inode,
- SD_INODE_HEADER_SIZE);
- if (ret != EXIT_SUCCESS)
- goto out;
-
- ret = sd_read_object(vid_to_vdi_oid(current_inode->parent_vdi_id),
- parent_inode, SD_INODE_HEADER_SIZE, 0, true);
- if (ret != SD_RES_SUCCESS) {
- printf("error\n");
- goto out;
- }
-
- if (is_stdin_console()) {
- sd_err("stdin must be pipe");
- ret = EXIT_USAGE;
- goto out;
- }
-
- ret = do_vdi_delete(vdiname, 0, NULL);
- if (ret != EXIT_SUCCESS) {
- sd_err("Failed to delete the current state");
- goto out;
- }
- need_current_recovery = true;
-
- /* restore backup data */
- ret = do_restore(vdiname, vdi_cmd_data.snapshot_id,
- vdi_cmd_data.snapshot_tag);
-out:
- if (need_current_recovery) {
- int recovery_ret;
- /* recreate the current vdi object */
- recovery_ret = do_vdi_create(vdiname, current_inode->vdi_size,
- current_inode->parent_vdi_id, NULL,
- true, current_inode->nr_copies);
- if (recovery_ret != EXIT_SUCCESS) {
- sd_err("failed to resume the current vdi");
- ret = recovery_ret;
- }
- }
- free(current_inode);
- return ret;
-}
-
-static int vdi_cache_flush(int argc, char **argv)
-{
- const char *vdiname = argv[optind++];
- struct sd_req hdr;
- uint32_t vid;
- int ret = EXIT_SUCCESS;
-
- ret = find_vdi_name(vdiname, vdi_cmd_data.snapshot_id,
- vdi_cmd_data.snapshot_tag, &vid, 0);
- if (ret < 0) {
- sd_err("Failed to open VDI %s", vdiname);
- ret = EXIT_FAILURE;
- goto out;
- }
-
- sd_init_req(&hdr, SD_OP_FLUSH_VDI);
- hdr.obj.oid = vid_to_vdi_oid(vid);
-
- ret = send_light_req(&hdr, sdhost, sdport);
- if (ret) {
- sd_err("failed to execute request");
- return EXIT_FAILURE;
- }
-out:
- return ret;
-}
-
-static int vdi_cache_delete(int argc, char **argv)
-{
- const char *vdiname = argv[optind++];
- struct sd_req hdr;
- uint32_t vid;
- int ret = EXIT_SUCCESS;
-
- ret = find_vdi_name(vdiname, vdi_cmd_data.snapshot_id,
- vdi_cmd_data.snapshot_tag, &vid, 0);
- if (ret < 0) {
- sd_err("Failed to open VDI %s", vdiname);
- ret = EXIT_FAILURE;
- goto out;
- }
-
- sd_init_req(&hdr, SD_OP_DELETE_CACHE);
- hdr.obj.oid = vid_to_vdi_oid(vid);
-
- ret = send_light_req(&hdr, sdhost, sdport);
- if (ret) {
- sd_err("failed to execute request");
- return EXIT_FAILURE;
- }
-out:
- return ret;
-}
-
-static int vid_to_name_tag(uint32_t vid, char *name, char *tag)
-{
- struct sd_inode inode;
- int ret;
-
- ret = sd_read_object(vid_to_vdi_oid(vid), &inode, SD_INODE_HEADER_SIZE,
- 0, true);
- if (ret != SD_RES_SUCCESS)
- return ret;
-
- pstrcpy(name, SD_MAX_VDI_LEN, inode.name);
- pstrcpy(tag, SD_MAX_VDI_TAG_LEN, inode.tag);
-
- return SD_RES_SUCCESS;
-}
-
-static int vdi_cache_info(int argc, char **argv)
-{
- struct object_cache_info info = {};
- struct sd_req hdr;
- struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
- char size_str[UINT64_DECIMAL_SIZE], used_str[UINT64_DECIMAL_SIZE];
- int ret, i;
-
- sd_init_req(&hdr, SD_OP_GET_CACHE_INFO);
- hdr.data_length = sizeof(info);
- ret = collie_exec_req(sdhost, sdport, &hdr, &info);
- if (ret < 0)
- return EXIT_SYSFAIL;
-
- if (rsp->result != SD_RES_SUCCESS) {
- sd_err("failed to get cache infomation: %s",
- sd_strerror(rsp->result));
- return EXIT_FAILURE;
- }
-
- fprintf(stdout, "Name\tTag\tTotal\tDirty\tClean\n");
- for (i = 0; i < info.count; i++) {
- char total_str[UINT64_DECIMAL_SIZE],
- dirty_str[UINT64_DECIMAL_SIZE],
- clean_str[UINT64_DECIMAL_SIZE];
- uint64_t total = info.caches[i].total * SD_DATA_OBJ_SIZE,
- dirty = info.caches[i].dirty * SD_DATA_OBJ_SIZE,
- clean = total - dirty;
- char name[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
-
- size_to_str(total, total_str, sizeof(total_str));
- size_to_str(dirty, dirty_str, sizeof(dirty_str));
- size_to_str(clean, clean_str, sizeof(clean_str));
- ret = vid_to_name_tag(info.caches[i].vid, name, tag);
- if (ret != SD_RES_SUCCESS)
- return EXIT_FAILURE;
- fprintf(stdout, "%s\t%s\t%s\t%s\t%s\n",
- name, tag, total_str, dirty_str, clean_str);
- }
-
- size_to_str(info.size, size_str, sizeof(size_str));
- size_to_str(info.used, used_str, sizeof(used_str));
- fprintf(stdout, "\nCache size %s, used %s\n", size_str, used_str);
-
- return EXIT_SUCCESS;
-}
-
-static struct subcommand vdi_cache_cmd[] = {
- {"flush", NULL, NULL, "flush the cache of the vdi specified.",
- NULL, CMD_NEED_ARG, vdi_cache_flush},
- {"delete", NULL, NULL, "delete the cache of the vdi specified in all nodes.",
- NULL, CMD_NEED_ARG, vdi_cache_delete},
- {"info", NULL, NULL, "show usage of the cache",
- NULL, 0, vdi_cache_info},
- {NULL,},
-};
-
-static int vdi_cache(int argc, char **argv)
-{
- return do_generic_subcommand(vdi_cache_cmd, argc, argv);
-}
-
-static struct subcommand vdi_cmd[] = {
- {"check", "<vdiname>", "saph", "check and repair image's consistency",
- NULL, CMD_NEED_NODELIST|CMD_NEED_ARG,
- vdi_check, vdi_options},
- {"create", "<vdiname> <size>", "Pcaphrv", "create an image",
- NULL, CMD_NEED_NODELIST|CMD_NEED_ARG,
- vdi_create, vdi_options},
- {"snapshot", "<vdiname>", "saphrv", "create a snapshot",
- NULL, CMD_NEED_ARG,
- vdi_snapshot, vdi_options},
- {"clone", "<src vdi> <dst vdi>", "sPcaphrv", "clone an image",
- NULL, CMD_NEED_ARG,
- vdi_clone, vdi_options},
- {"delete", "<vdiname>", "saph", "delete an image",
- NULL, CMD_NEED_ARG,
- vdi_delete, vdi_options},
- {"rollback", "<vdiname>", "saphfrv", "rollback to a snapshot",
- NULL, CMD_NEED_ARG,
- vdi_rollback, vdi_options},
- {"list", "[vdiname]", "aprh", "list images",
- NULL, 0, vdi_list, vdi_options},
- {"tree", NULL, "aph", "show images in tree view format",
- NULL, 0, vdi_tree, vdi_options},
- {"graph", NULL, "aph", "show images in Graphviz dot format",
- NULL, 0, vdi_graph, vdi_options},
- {"object", "<vdiname>", "isaph", "show object information in the image",
- NULL, CMD_NEED_NODELIST|CMD_NEED_ARG,
- vdi_object, vdi_options},
- {"track", "<vdiname>", "isaph", "show the object epoch trace in the image",
- NULL, CMD_NEED_NODELIST|CMD_NEED_ARG,
- vdi_track, vdi_options},
- {"setattr", "<vdiname> <key> [value]", "dxaph", "set a VDI attribute",
- NULL, CMD_NEED_ARG,
- vdi_setattr, vdi_options},
- {"getattr", "<vdiname> <key>", "aph", "get a VDI attribute",
- NULL, CMD_NEED_ARG,
- vdi_getattr, vdi_options},
- {"resize", "<vdiname> <new size>", "aph", "resize an image",
- NULL, CMD_NEED_ARG,
- vdi_resize, vdi_options},
- {"read", "<vdiname> [<offset> [<len>]]", "saph", "read data from an image",
- NULL, CMD_NEED_ARG,
- vdi_read, vdi_options},
- {"write", "<vdiname> [<offset> [<len>]]", "apwh", "write data to an image",
- NULL, CMD_NEED_ARG,
- vdi_write, vdi_options},
- {"backup", "<vdiname> <backup>", "sFaph", "create an incremental backup between two snapshots",
- NULL, CMD_NEED_NODELIST|CMD_NEED_ARG,
- vdi_backup, vdi_options},
- {"restore", "<vdiname> <backup>", "saph", "restore snapshot images from a backup",
- NULL, CMD_NEED_NODELIST|CMD_NEED_ARG,
- vdi_restore, vdi_options},
- {"cache", "<vdiname>", "saph", "Run 'collie vdi cache' for more information",
- vdi_cache_cmd, CMD_NEED_ARG,
- vdi_cache, vdi_options},
- {NULL,},
-};
-
-static int vdi_parser(int ch, char *opt)
-{
- char *p;
- int nr_copies;
-
- switch (ch) {
- case 'P':
- vdi_cmd_data.prealloc = true;
- break;
- case 'i':
- vdi_cmd_data.index = strtol(opt, &p, 10);
- if (opt == p) {
- sd_err("The index must be an integer");
- exit(EXIT_FAILURE);
- }
- break;
- case 's':
- vdi_cmd_data.snapshot_id = strtol(opt, &p, 10);
- if (opt == p) {
- vdi_cmd_data.snapshot_id = 0;
- pstrcpy(vdi_cmd_data.snapshot_tag,
- sizeof(vdi_cmd_data.snapshot_tag), opt);
- } else if (vdi_cmd_data.snapshot_id == 0) {
- fprintf(stderr,
- "The snapshot id must be larger than zero\n");
- exit(EXIT_FAILURE);
- }
- break;
- case 'x':
- vdi_cmd_data.exclusive = true;
- break;
- case 'd':
- vdi_cmd_data.delete = true;
- break;
- case 'w':
- vdi_cmd_data.writeback = true;
- break;
- case 'c':
- nr_copies = strtol(opt, &p, 10);
- if (opt == p || nr_copies < 0 || nr_copies > SD_MAX_COPIES) {
- sd_err("Invalid copies number, must be "
- "an integer between 0 and %d", SD_MAX_COPIES);
- exit(EXIT_FAILURE);
- }
- vdi_cmd_data.nr_copies = nr_copies;
- break;
- case 'F':
- vdi_cmd_data.from_snapshot_id = strtol(opt, &p, 10);
- if (opt == p) {
- vdi_cmd_data.from_snapshot_id = 0;
- pstrcpy(vdi_cmd_data.from_snapshot_tag,
- sizeof(vdi_cmd_data.from_snapshot_tag), opt);
- }
- break;
- case 'f':
- vdi_cmd_data.force = true;
- break;
- }
-
- return 0;
-}
-
-struct command vdi_command = {
- "vdi",
- vdi_cmd,
- vdi_parser
-};
diff --git a/configure.ac b/configure.ac
index 9831379..991a869 100644
--- a/configure.ac
+++ b/configure.ac
@@ -28,7 +28,7 @@ AC_INIT([sheepdog], m4_default(git_version, sheepdog_version),
[sheepdog at lists.wpkg.org])
AM_INIT_AUTOMAKE([-Wno-portability])
-AC_CONFIG_SRCDIR([collie/collie.c])
+AC_CONFIG_SRCDIR([dog/dog.c])
AC_CONFIG_HEADER([include/config.h])
AC_CANONICAL_HOST
@@ -127,7 +127,7 @@ AC_CHECK_FUNCS([alarm alphasort atexit bzero dup2 endgrent endpwent fcntl \
strerror strrchr strspn strstr])
AC_CONFIG_FILES([Makefile
- collie/Makefile
+ dog/Makefile
sheep/Makefile
sheepfs/Makefile
include/Makefile
@@ -137,7 +137,7 @@ AC_CONFIG_FILES([Makefile
shepherd/Makefile
tests/unit/Makefile
tests/unit/mock/Makefile
- tests/unit/collie/Makefile
+ tests/unit/dog/Makefile
tests/unit/sheep/Makefile
tools/Makefile])
diff --git a/debian/sheepdog.bash-completion b/debian/sheepdog.bash-completion
index 3406bc5..ba7fc2b 100644
--- a/debian/sheepdog.bash-completion
+++ b/debian/sheepdog.bash-completion
@@ -1 +1 @@
-script/bash_completion_collie collie
+script/bash_completion_dog dog
diff --git a/dog/Makefile.am b/dog/Makefile.am
new file mode 100644
index 0000000..fc826d9
--- /dev/null
+++ b/dog/Makefile.am
@@ -0,0 +1,56 @@
+#
+# Copyright 2010 Red Hat, Inc.
+#
+# This program 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.
+#
+# This program 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; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CFLAGS =
+
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include
+
+sbin_PROGRAMS = dog
+
+dog_SOURCES = farm/object_tree.c farm/sha1_file.c farm/snap.c \
+ farm/trunk.c farm/farm.c farm/slice.c \
+ dog.c common.c treeview.c vdi.c node.c cluster.c
+
+if BUILD_TRACE
+dog_SOURCES += trace.c
+override CFLAGS := $(subst -pg,,$(CFLAGS))
+endif
+
+dog_LDADD = ../lib/libsheepdog.a -lpthread
+dog_DEPENDENCIES = ../lib/libsheepdog.a
+
+noinst_HEADERS = treeview.h dog.h farm/farm.h
+
+EXTRA_DIST =
+
+all-local:
+ @echo Built dog
+
+clean-local:
+ rm -f dog *.o gmon.out *.da *.bb *.bbg
+
+# support for GNU Flymake
+check-syntax:
+ $(COMPILE) -fsyntax-only $(CHK_SOURCES)
+
+check-style:
+ @$(CHECK_STYLE) $(dog_SOURCES) $(noinst_HEADERS)
+
+coverage:
+ @lcov -d . -c -o dog.info
diff --git a/dog/cluster.c b/dog/cluster.c
new file mode 100644
index 0000000..4c7654d
--- /dev/null
+++ b/dog/cluster.c
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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 <time.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "dog.h"
+#include "farm/farm.h"
+
+static struct sd_option cluster_options[] = {
+ {'b', "store", true, "specify backend store"},
+ {'c', "copies", true, "specify the default data redundancy (number of copies)"},
+ {'f', "force", false, "do not prompt for confirmation"},
+
+ { 0, NULL, false, NULL },
+};
+
+static struct cluster_cmd_data {
+ int copies;
+ bool force;
+ char name[STORE_LEN];
+} cluster_cmd_data;
+
+#define DEFAULT_STORE "plain"
+
+static int list_store(void)
+{
+ int ret;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ char buf[512] = { 0 };
+
+ sd_init_req(&hdr, SD_OP_GET_STORE_LIST);
+ hdr.data_length = 512;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, buf);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("Restore failed: %s", sd_strerror(rsp->result));
+ return EXIT_FAILURE;
+ }
+
+ printf("Available stores:\n");
+ printf("---------------------------------------\n");
+ printf("%s\n", buf);
+ return EXIT_SYSFAIL;
+}
+
+static bool no_vdi(const unsigned long *vdis)
+{
+ return find_next_bit(vdis, SD_NR_VDIS, 0) == SD_NR_VDIS;
+}
+
+#define FORMAT_PRINT \
+ " __\n" \
+ " ()'`;\n" \
+ " /\\|`\n" \
+ " / | Caution! The cluster is not empty.\n" \
+ "(/_)_|_ Are you sure you want to continue? [yes/no]: "
+
+static int cluster_format(int argc, char **argv)
+{
+ int ret;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ struct timeval tv;
+ char store_name[STORE_LEN];
+ static DECLARE_BITMAP(vdi_inuse, SD_NR_VDIS);
+
+ sd_init_req(&hdr, SD_OP_READ_VDIS);
+ hdr.data_length = sizeof(vdi_inuse);
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, &vdi_inuse);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ if (!no_vdi(vdi_inuse))
+ confirm(FORMAT_PRINT);
+
+ gettimeofday(&tv, NULL);
+
+ sd_init_req(&hdr, SD_OP_MAKE_FS);
+ hdr.cluster.copies = cluster_cmd_data.copies;
+ hdr.cluster.ctime = (uint64_t) tv.tv_sec << 32 | tv.tv_usec * 1000;
+
+ if (strlen(cluster_cmd_data.name))
+ pstrcpy(store_name, STORE_LEN, cluster_cmd_data.name);
+ else
+ pstrcpy(store_name, STORE_LEN, DEFAULT_STORE);
+ hdr.data_length = strlen(store_name) + 1;
+ hdr.flags |= SD_FLAG_CMD_WRITE;
+
+ printf("using backend %s store\n", store_name);
+ ret = dog_exec_req(sdhost, sdport, &hdr, store_name);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("Format failed: %s", sd_strerror(rsp->result));
+ if (rsp->result == SD_RES_NO_STORE)
+ return list_store();
+ else
+ return EXIT_SYSFAIL;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int cluster_info(int argc, char **argv)
+{
+ int i, ret;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ struct epoch_log *logs;
+ int nr_logs, log_length;
+ time_t ti, ct;
+ struct tm tm;
+ char time_str[128];
+
+ log_length = sd_epoch * sizeof(struct epoch_log);
+ logs = xmalloc(log_length);
+
+ sd_init_req(&hdr, SD_OP_STAT_CLUSTER);
+ hdr.data_length = log_length;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, logs);
+ if (ret < 0)
+ goto error;
+
+ if (!raw_output)
+ printf("Cluster status: ");
+ if (rsp->result == SD_RES_SUCCESS)
+ printf("running, auto-recovery %s\n", logs->disable_recovery ?
+ "disabled" : "enabled");
+ else
+ printf("%s\n", sd_strerror(rsp->result));
+
+ if (!raw_output && rsp->data_length > 0) {
+ ct = logs[0].ctime >> 32;
+ printf("\nCluster created at %s\n", ctime(&ct));
+ printf("Epoch Time Version\n");
+ }
+
+ nr_logs = rsp->data_length / sizeof(struct epoch_log);
+ for (i = 0; i < nr_logs; i++) {
+ int j;
+ const struct sd_node *entry;
+
+ ti = logs[i].time;
+ if (raw_output) {
+ snprintf(time_str, sizeof(time_str), "%" PRIu64, (uint64_t) ti);
+ } else {
+ localtime_r(&ti, &tm);
+ strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm);
+ }
+
+ printf(raw_output ? "%s %d" : "%s %6d", time_str, logs[i].epoch);
+ printf(" [");
+ for (j = 0; j < logs[i].nr_nodes; j++) {
+ entry = logs[i].nodes + j;
+ printf("%s%s",
+ (j == 0) ? "" : ", ",
+ addr_to_str(entry->nid.addr, entry->nid.port));
+ }
+ printf("]\n");
+ }
+
+ free(logs);
+ return EXIT_SUCCESS;
+error:
+ free(logs);
+ return EXIT_SYSFAIL;
+}
+
+static int cluster_shutdown(int argc, char **argv)
+{
+ int ret;
+ struct sd_req hdr;
+
+ sd_init_req(&hdr, SD_OP_SHUTDOWN);
+
+ ret = send_light_req(&hdr, sdhost, sdport);
+ if (ret) {
+ sd_err("failed to execute request");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static void print_list(void *buf, unsigned len)
+{
+ struct snap_log *log_buf = (struct snap_log *)buf;
+ unsigned nr = len / sizeof(struct snap_log);
+
+ printf("Index\t\tTag\t\tSnapshot Time\n");
+ for (unsigned i = 0; i < nr; i++, log_buf++) {
+ time_t *t = (time_t *)&log_buf->time;
+ printf("%d\t\t", log_buf->idx);
+ printf("%s\t\t", log_buf->tag);
+ printf("%s", ctime(t));
+ }
+}
+
+static int list_snapshot(int argc, char **argv)
+{
+ char *path = argv[optind++];
+ void *buf = NULL;
+ int log_nr;
+ int ret = EXIT_SYSFAIL;
+
+ if (farm_init(path) != SD_RES_SUCCESS)
+ goto out;
+
+ buf = snap_log_read(&log_nr);
+ if (!buf)
+ goto out;
+
+ print_list(buf, log_nr * sizeof(struct snap_log));
+ ret = EXIT_SUCCESS;
+out:
+ if (ret)
+ sd_err("Fail to list snapshot.");
+ free(buf);
+ return ret;
+}
+
+static void fill_object_tree(uint32_t vid, const char *name, const char *tag,
+ uint32_t snapid, uint32_t flags,
+ const struct sd_inode *i, void *data)
+{
+ uint64_t vdi_oid = vid_to_vdi_oid(vid), vmstate_oid;
+ int nr_vmstate_object;
+
+ /* ignore active vdi */
+ if (!vdi_is_snapshot(i))
+ return;
+
+ /* fill vdi object id */
+ object_tree_insert(vdi_oid, i->nr_copies);
+
+ /* fill data object id */
+ for (uint64_t idx = 0; idx < MAX_DATA_OBJS; idx++) {
+ if (i->data_vdi_id[idx]) {
+ uint64_t oid = vid_to_data_oid(i->data_vdi_id[idx],
+ idx);
+ object_tree_insert(oid, i->nr_copies);
+ }
+ }
+
+ /* fill vmstate object id */
+ nr_vmstate_object = DIV_ROUND_UP(i->vm_state_size, SD_DATA_OBJ_SIZE);
+ for (int idx = 0; idx < nr_vmstate_object; idx++) {
+ vmstate_oid = vid_to_vmstate_oid(vid, idx);
+ object_tree_insert(vmstate_oid, i->nr_copies);
+ }
+}
+
+static int save_snapshot(int argc, char **argv)
+{
+ char *tag = argv[optind++];
+ char *path, *p;
+ int ret = EXIT_SYSFAIL, uninitialized_var(unused);
+
+ unused = strtol(tag, &p, 10);
+ if (tag != p) {
+ sd_err("Tag should not start with number.");
+ return EXIT_USAGE;
+ }
+
+ if (!argv[optind]) {
+ sd_err("Please specify the path to save snapshot.");
+ return EXIT_USAGE;
+ }
+ path = argv[optind];
+
+ if (farm_init(path) != SD_RES_SUCCESS)
+ goto out;
+
+ if (farm_contain_snapshot(0, tag)) {
+ sd_err("Snapshot tag has already been used for another"
+ " snapshot, please, use another one.");
+ goto out;
+ }
+
+ if (parse_vdi(fill_object_tree, SD_INODE_SIZE, NULL) != SD_RES_SUCCESS)
+ goto out;
+
+ if (farm_save_snapshot(tag) != SD_RES_SUCCESS)
+ goto out;
+
+ ret = EXIT_SUCCESS;
+out:
+ if (ret)
+ sd_err("Fail to save snapshot to path: %s.", path);
+ object_tree_free();
+ return ret;
+}
+
+static int load_snapshot(int argc, char **argv)
+{
+ char *tag = argv[optind++];
+ char *path, *p;
+ uint32_t idx;
+ int ret = EXIT_SYSFAIL;
+
+ idx = strtol(tag, &p, 10);
+ if (tag == p)
+ idx = 0;
+
+ if (!argv[optind]) {
+ sd_err("Please specify the path to save snapshot.");
+ return EXIT_USAGE;
+ }
+ path = argv[optind];
+
+ if (farm_init(path) != SD_RES_SUCCESS)
+ goto out;
+
+ if (!farm_contain_snapshot(idx, tag)) {
+ sd_err("Snapshot index or tag does not exist.");
+ goto out;
+ }
+
+ if (cluster_format(0, NULL) != SD_RES_SUCCESS)
+ goto out;
+
+ if (farm_load_snapshot(idx, tag) != SD_RES_SUCCESS)
+ goto out;
+
+ ret = EXIT_SUCCESS;
+out:
+ if (ret)
+ sd_err("Fail to load snapshot");
+ return ret;
+}
+
+#define RECOVER_PRINT \
+ "Caution! Please try starting all the cluster nodes normally before\n" \
+ "running this command.\n\n" \
+ "The cluster may need to be force recovered if:\n" \
+ " - the master node fails to start because of epoch mismatch; or\n" \
+ " - some nodes fail to start after a cluster shutdown.\n\n" \
+ "Are you sure you want to continue? [yes/no]: "
+
+static int cluster_force_recover(int argc, char **argv)
+{
+ int ret;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ char str[123] = {'\0'};
+ struct sd_node nodes[SD_MAX_NODES];
+
+ if (!cluster_cmd_data.force) {
+ int i, l;
+ printf(RECOVER_PRINT);
+ ret = scanf("%s", str);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+ l = strlen(str);
+ for (i = 0; i < l; i++)
+ str[i] = tolower(str[i]);
+ if (strncmp(str, "yes", 3) != 0)
+ return EXIT_SUCCESS;
+ }
+
+ sd_init_req(&hdr, SD_OP_FORCE_RECOVER);
+ hdr.data_length = sizeof(nodes);
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, nodes);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("failed to execute request, %s",
+ sd_strerror(rsp->result));
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int cluster_disable_recover(int argc, char **argv)
+{
+ int ret;
+ struct sd_req hdr;
+
+ sd_init_req(&hdr, SD_OP_DISABLE_RECOVER);
+
+ ret = send_light_req(&hdr, sdhost, sdport);
+ if (ret)
+ return EXIT_FAILURE;
+
+ printf("Cluster recovery: disable\n");
+ return EXIT_SUCCESS;
+}
+
+static int cluster_enable_recover(int argc, char **argv)
+{
+ int ret;
+ struct sd_req hdr;
+
+ sd_init_req(&hdr, SD_OP_ENABLE_RECOVER);
+
+ ret = send_light_req(&hdr, sdhost, sdport);
+ if (ret)
+ return EXIT_FAILURE;
+
+ printf("Cluster recovery: enable\n");
+ return EXIT_SUCCESS;
+}
+
+/* Subcommand list of recover */
+static struct subcommand cluster_recover_cmd[] = {
+ {"force", NULL, NULL, "force recover cluster immediately",
+ NULL, 0, cluster_force_recover},
+ {"enable", NULL, NULL, "enable automatic recovery and "
+ "run once recover if necessary",
+ NULL, 0, cluster_enable_recover},
+ {"disable", NULL, NULL, "disable automatic recovery",
+ NULL, 0, cluster_disable_recover},
+ {NULL},
+};
+
+static int cluster_recover(int argc, char **argv)
+{
+ return do_generic_subcommand(cluster_recover_cmd, argc, argv);
+}
+
+/* Subcommand list of snapshot */
+static struct subcommand cluster_snapshot_cmd[] = {
+ {"save", NULL, "h", "save snapshot to localpath",
+ NULL, CMD_NEED_ARG|CMD_NEED_NODELIST,
+ save_snapshot, NULL},
+ {"list", NULL, "h", "list snapshot of localpath",
+ NULL, CMD_NEED_ARG, list_snapshot, NULL},
+ {"load", NULL, "h", "load snapshot from localpath",
+ NULL, CMD_NEED_ARG, load_snapshot, NULL},
+ {NULL},
+};
+
+static int cluster_snapshot(int argc, char **argv)
+{
+ return do_generic_subcommand(cluster_snapshot_cmd, argc, argv);
+}
+
+static int cluster_reweight(int argc, char **argv)
+{
+ int ret;
+ struct sd_req hdr;
+
+ sd_init_req(&hdr, SD_OP_REWEIGHT);
+ ret = send_light_req(&hdr, sdhost, sdport);
+ if (ret)
+ return EXIT_FAILURE;
+ return EXIT_SUCCESS;
+}
+
+static struct subcommand cluster_cmd[] = {
+ {"info", NULL, "aprh", "show cluster information",
+ NULL, CMD_NEED_NODELIST, cluster_info, cluster_options},
+ {"format", NULL, "bcaph", "create a Sheepdog store",
+ NULL, 0, cluster_format, cluster_options},
+ {"shutdown", NULL, "aph", "stop Sheepdog",
+ NULL, 0, cluster_shutdown, cluster_options},
+ {"snapshot", "<tag|idx> <path>", "aph", "snapshot/restore the cluster",
+ cluster_snapshot_cmd, CMD_NEED_ARG,
+ cluster_snapshot, cluster_options},
+ {"recover", NULL, "afph",
+ "See 'dog cluster recover' for more information",
+ cluster_recover_cmd, CMD_NEED_ARG,
+ cluster_recover, cluster_options},
+ {"reweight", NULL, "aph", "reweight the cluster", NULL, 0,
+ cluster_reweight, cluster_options},
+ {NULL,},
+};
+
+static int cluster_parser(int ch, char *opt)
+{
+ int copies;
+ char *p;
+
+ switch (ch) {
+ case 'b':
+ pstrcpy(cluster_cmd_data.name, sizeof(cluster_cmd_data.name),
+ opt);
+ break;
+ case 'c':
+ copies = strtol(opt, &p, 10);
+ if (opt == p || copies < 1) {
+ sd_err("There must be at least one copy of data");
+ exit(EXIT_FAILURE);
+ } else if (copies > SD_MAX_COPIES) {
+ sd_err("Redundancy may not exceed %d copies",
+ SD_MAX_COPIES);
+ exit(EXIT_FAILURE);
+ }
+ cluster_cmd_data.copies = copies;
+ break;
+ case 'f':
+ cluster_cmd_data.force = true;
+ break;
+ }
+
+ return 0;
+}
+
+struct command cluster_command = {
+ "cluster",
+ cluster_cmd,
+ cluster_parser
+};
diff --git a/dog/common.c b/dog/common.c
new file mode 100644
index 0000000..14d3b1d
--- /dev/null
+++ b/dog/common.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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 "dog.h"
+#include "sha1.h"
+#include "sockfd_cache.h"
+
+char *size_to_str(uint64_t _size, char *str, int str_size)
+{
+ const char *units[] = {"MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
+ int i = 0;
+ double size;
+
+ if (raw_output) {
+ snprintf(str, str_size, "%" PRIu64, _size);
+ return str;
+ }
+
+ size = (double)_size;
+ size /= 1024 * 1024;
+ while (i < ARRAY_SIZE(units) - 1 && size >= 1024) {
+ i++;
+ size /= 1024;
+ }
+
+ if (size >= 10)
+ snprintf(str, str_size, "%.0lf %s", size, units[i]);
+ else
+ snprintf(str, str_size, "%.1lf %s", size, units[i]);
+
+ return str;
+}
+
+int sd_read_object(uint64_t oid, void *data, unsigned int datalen,
+ uint64_t offset, bool direct)
+{
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ int ret;
+
+ sd_init_req(&hdr, SD_OP_READ_OBJ);
+ hdr.data_length = datalen;
+
+ hdr.obj.oid = oid;
+ hdr.obj.offset = offset;
+ if (direct)
+ hdr.flags |= SD_FLAG_CMD_DIRECT;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, data);
+ if (ret < 0) {
+ sd_err("Failed to read object %" PRIx64, oid);
+ return SD_RES_EIO;
+ }
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("Failed to read object %" PRIx64 " %s", oid,
+ sd_strerror(rsp->result));
+ return rsp->result;
+ }
+
+ untrim_zero_blocks(data, rsp->obj.offset, rsp->data_length, datalen);
+
+ return SD_RES_SUCCESS;
+}
+
+int sd_write_object(uint64_t oid, uint64_t cow_oid, void *data,
+ unsigned int datalen, uint64_t offset, uint32_t flags,
+ int copies, bool create, bool direct)
+{
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ int ret;
+
+ if (create)
+ sd_init_req(&hdr, SD_OP_CREATE_AND_WRITE_OBJ);
+ else
+ sd_init_req(&hdr, SD_OP_WRITE_OBJ);
+
+ hdr.data_length = datalen;
+ hdr.flags = flags | SD_FLAG_CMD_WRITE;
+ if (cow_oid)
+ hdr.flags |= SD_FLAG_CMD_COW;
+ if (direct)
+ hdr.flags |= SD_FLAG_CMD_DIRECT;
+
+ hdr.obj.copies = copies;
+ hdr.obj.oid = oid;
+ hdr.obj.cow_oid = cow_oid;
+ hdr.obj.offset = offset;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, data);
+ if (ret < 0) {
+ sd_err("Failed to write object %" PRIx64, oid);
+ return SD_RES_EIO;
+ }
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("Failed to write object %" PRIx64 ": %s", oid,
+ sd_strerror(rsp->result));
+ return rsp->result;
+ }
+
+ return SD_RES_SUCCESS;
+}
+
+#define FOR_EACH_VDI(nr, vdis) FOR_EACH_BIT(nr, vdis, SD_NR_VDIS)
+
+int parse_vdi(vdi_parser_func_t func, size_t size, void *data)
+{
+ int ret;
+ unsigned long nr;
+ static struct sd_inode i;
+ struct sd_req req;
+ static DECLARE_BITMAP(vdi_inuse, SD_NR_VDIS);
+ unsigned int rlen = sizeof(vdi_inuse);
+
+ sd_init_req(&req, SD_OP_READ_VDIS);
+ req.data_length = sizeof(vdi_inuse);
+
+ ret = dog_exec_req(sdhost, sdport, &req, &vdi_inuse);
+ if (ret < 0)
+ goto out;
+
+ FOR_EACH_VDI(nr, vdi_inuse) {
+ uint64_t oid;
+ uint32_t snapid;
+
+ oid = vid_to_vdi_oid(nr);
+
+ memset(&i, 0, sizeof(i));
+ ret = sd_read_object(oid, &i, SD_INODE_HEADER_SIZE, 0, true);
+ if (ret != SD_RES_SUCCESS) {
+ sd_err("Failed to read inode header");
+ continue;
+ }
+
+ if (i.name[0] == '\0') /* this VDI has been deleted */
+ continue;
+
+ if (size > SD_INODE_HEADER_SIZE) {
+ rlen = DIV_ROUND_UP(i.vdi_size, SD_DATA_OBJ_SIZE) *
+ sizeof(i.data_vdi_id[0]);
+ if (rlen > size - SD_INODE_HEADER_SIZE)
+ rlen = size - SD_INODE_HEADER_SIZE;
+
+ ret = sd_read_object(oid, ((char *)&i) + SD_INODE_HEADER_SIZE,
+ rlen, SD_INODE_HEADER_SIZE, true);
+
+ if (ret != SD_RES_SUCCESS) {
+ sd_err("Failed to read inode");
+ continue;
+ }
+ }
+
+ snapid = vdi_is_snapshot(&i) ? i.snap_id : 0;
+ func(i.vdi_id, i.name, i.tag, snapid, 0, &i, data);
+ }
+
+out:
+ return ret;
+}
+
+int dog_exec_req(const uint8_t *addr, int port, struct sd_req *hdr,
+ void *buf)
+{
+ struct node_id nid = {};
+ struct sockfd *sfd;
+ int ret;
+
+ memcpy(nid.addr, addr, sizeof(nid.addr));
+ nid.port = port;
+
+ sfd = sockfd_cache_get(&nid);
+ if (!sfd)
+ return -1;
+
+ /*
+ * Retry forever for dog because
+ * 1. We can't get the newest epoch
+ * 2. Some operations might take unexpected long time
+ */
+ ret = exec_req(sfd->fd, hdr, buf, NULL, 0, UINT32_MAX);
+
+ sockfd_cache_put(&nid, sfd);
+
+ return ret ? -1 : 0;
+}
+
+/* Light request only contains header, without body content. */
+int send_light_req(struct sd_req *hdr, const uint8_t *addr, int port)
+{
+ int ret = dog_exec_req(addr, port, hdr, NULL);
+
+ if (ret == -1)
+ return -1;
+
+ if (ret != SD_RES_SUCCESS) {
+ sd_err("Response's result: %s", sd_strerror(ret));
+ return -1;
+ }
+
+ return 0;
+}
+
+int do_generic_subcommand(struct subcommand *sub, int argc, char **argv)
+{
+ int i, ret;
+
+ for (i = 0; sub[i].name; i++) {
+ if (!strcmp(sub[i].name, argv[optind])) {
+ unsigned long flags = sub[i].flags;
+
+ if (flags & CMD_NEED_NODELIST) {
+ ret = update_node_list(SD_MAX_NODES);
+ if (ret < 0) {
+ sd_err("Failed to get node list");
+ exit(EXIT_SYSFAIL);
+ }
+ }
+
+ if (flags & CMD_NEED_ARG && argc < 5)
+ subcommand_usage(argv[1], argv[2], EXIT_USAGE);
+ optind++;
+ ret = sub[i].fn(argc, argv);
+ if (ret == EXIT_USAGE)
+ subcommand_usage(argv[1], argv[2], EXIT_USAGE);
+ return ret;
+ }
+ }
+
+ subcommand_usage(argv[1], argv[2], EXIT_FAILURE);
+ return EXIT_FAILURE;
+}
+
+void confirm(const char *message)
+{
+ char input[8] = "";
+ char *ret;
+
+ printf("%s", message);
+ ret = fgets(input, sizeof(input), stdin);
+ if (ret == NULL || strncasecmp(input, "yes", 3) != 0)
+ exit(EXIT_SUCCESS);
+}
+
+void work_queue_wait(struct work_queue *q)
+{
+ while (!work_queue_empty(q))
+ event_loop(-1);
+}
+
+#define DEFAULT_SCREEN_WIDTH 80
+
+static int get_screen_width(void)
+{
+ struct winsize wsz;
+
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &wsz) < 0)
+ return DEFAULT_SCREEN_WIDTH;
+
+ return wsz.ws_col;
+}
+
+/*
+ * Show prograss bar as follows.
+ *
+ * 45.0 % [===============> ] 180 MB / 400 MB
+ */
+void show_progress(uint64_t done, uint64_t total, bool raw)
+{
+ char done_str[256], total_str[256];
+ int screen_width = get_screen_width();
+ int bar_length = screen_width - 30;
+ char *buf;
+
+ if (!is_stdout_console())
+ return;
+ if (screen_width <= 0)
+ return;
+
+ printf("\r"); /* move to the beginning of the line */
+
+ if (raw) {
+ snprintf(done_str, sizeof(done_str), "%"PRIu64, done);
+ snprintf(total_str, sizeof(total_str), "%"PRIu64, total);
+ } else {
+ size_to_str(done, done_str, sizeof(done_str));
+ size_to_str(total, total_str, sizeof(total_str));
+ }
+
+ buf = xmalloc(screen_width + 1);
+ snprintf(buf, screen_width, "%5.1lf %% [", (double)done / total * 100);
+
+ for (int i = 0; i < bar_length; i++) {
+ if (total * (i + 1) / bar_length <= done)
+ strcat(buf, "=");
+ else if (total * i / bar_length <= done &&
+ done < total * (i + 1) / bar_length)
+ strcat(buf, ">");
+ else
+ strcat(buf, " ");
+ }
+ snprintf(buf + strlen(buf), screen_width - strlen(buf),
+ "] %s / %s", done_str, total_str);
+
+ /* fill the rest of buffer with blank characters */
+ memset(buf + strlen(buf), ' ', screen_width - strlen(buf));
+ buf[screen_width] = '\0';
+ printf("%s", buf);
+
+ if (done == total)
+ printf("\n");
+
+ fflush(stdout);
+
+ free(buf);
+}
diff --git a/dog/dog.c b/dog/dog.c
new file mode 100644
index 0000000..cca8e66
--- /dev/null
+++ b/dog/dog.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2009-2011 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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 <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include "sheepdog_proto.h"
+#include "sheep.h"
+#include "dog.h"
+#include "util.h"
+#include "sockfd_cache.h"
+
+#define EPOLL_SIZE 4096
+
+static const char program_name[] = "dog";
+/* default sdhost is "127.0.0.1" */
+uint8_t sdhost[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1 };
+int sdport = SD_LISTEN_PORT;
+bool highlight = true;
+bool raw_output;
+bool verbose;
+
+static const struct sd_option dog_options[] = {
+
+ /* common options for all dog commands */
+ {'a', "address", true, "specify the daemon address (default: localhost)"},
+ {'p', "port", true, "specify the daemon port"},
+ {'r', "raw", false, "raw output mode: omit headers, separate fields with\n"
+ " single spaces and print all sizes in decimal bytes"},
+ {'v', "verbose", false, "print more information than default"},
+ {'h', "help", false, "display this help and exit"},
+
+ { 0, NULL, false, NULL },
+};
+
+static void usage(const struct command *commands, int status);
+
+uint32_t sd_epoch;
+
+struct sd_node sd_nodes[SD_MAX_NODES];
+struct sd_vnode sd_vnodes[SD_MAX_VNODES];
+int sd_nodes_nr, sd_vnodes_nr;
+
+int update_node_list(int max_nodes)
+{
+ int ret;
+ unsigned int size;
+ char *buf = NULL;
+ struct sd_node *ent;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+
+ size = sizeof(*ent) * max_nodes;
+ buf = xzalloc(size);
+ sd_init_req(&hdr, SD_OP_GET_NODE_LIST);
+
+ hdr.data_length = size;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, buf);
+ if (ret < 0)
+ goto out;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("Failed to update node list: %s",
+ sd_strerror(rsp->result));
+ ret = -1;
+ goto out;
+ }
+
+ size = rsp->data_length;
+ sd_nodes_nr = size / sizeof(*ent);
+ if (sd_nodes_nr == 0) {
+ sd_err("There are no active sheep daemons");
+ exit(EXIT_FAILURE);
+ }
+
+ /* FIXME */
+ if (sd_nodes_nr > max_nodes) {
+ ret = -1;
+ goto out;
+ }
+
+ memcpy(sd_nodes, buf, size);
+ sd_vnodes_nr = nodes_to_vnodes(sd_nodes, sd_nodes_nr, sd_vnodes);
+ sd_epoch = hdr.epoch;
+out:
+ if (buf)
+ free(buf);
+
+ return ret;
+}
+
+static int (*command_parser)(int, char *);
+static int (*command_fn)(int, char **);
+static const char *command_opts;
+static const char *command_arg;
+static const char *command_desc;
+static struct sd_option *command_options;
+
+static const struct sd_option *find_opt(int ch)
+{
+ const struct sd_option *opt;
+
+ /* search for common options */
+ sd_for_each_option(opt, dog_options) {
+ if (opt->ch == ch)
+ return opt;
+ }
+
+ /* search for self options */
+ if (command_options) {
+ sd_for_each_option(opt, command_options) {
+ if (opt->ch == ch)
+ return opt;
+ }
+ }
+
+ sd_err("Internal error");
+ exit(EXIT_SYSFAIL);
+}
+
+static void init_commands(const struct command **commands)
+{
+ static struct command *cmds;
+ struct command command_list[] = {
+ vdi_command,
+ node_command,
+ cluster_command,
+ trace_command,
+ {NULL,}
+ };
+
+ if (!cmds) {
+ cmds = (struct command *)xmalloc(sizeof(command_list));
+ memcpy(cmds, command_list, sizeof(command_list));
+ }
+
+ *commands = cmds;
+ return;
+}
+
+static const struct subcommand *find_subcmd(const char *cmd, const char *subcmd)
+{
+ int i, j;
+ const struct command *commands;
+ const struct subcommand *sub;
+
+ init_commands(&commands);
+
+ for (i = 0; commands[i].name; i++) {
+ if (!strcmp(commands[i].name, cmd)) {
+ sub = commands[i].sub;
+ for (j = 0; sub[j].name; j++) {
+ if (!strcmp(sub[j].name, subcmd))
+ return &sub[j];
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static unsigned long setup_commands(const struct command *commands,
+ char *cmd, char *subcmd)
+{
+ int i;
+ bool found = false;
+ struct subcommand *s;
+ unsigned long flags = 0;
+
+ for (i = 0; commands[i].name; i++) {
+ if (!strcmp(commands[i].name, cmd)) {
+ found = true;
+ if (commands[i].parser)
+ command_parser = commands[i].parser;
+ break;
+ }
+ }
+
+ if (!found) {
+ if (cmd && strcmp(cmd, "help") && strcmp(cmd, "--help") &&
+ strcmp(cmd, "-h")) {
+ sd_err("Invalid command '%s'", cmd);
+ usage(commands, EXIT_USAGE);
+ }
+ usage(commands, 0);
+ }
+
+ for (s = commands[i].sub; subcmd && s->name; s++) {
+ if (!strcmp(s->name, subcmd)) {
+ command_fn = s->fn;
+ command_opts = s->opts;
+ command_arg = s->arg;
+ command_desc = s->desc;
+ command_options = s->options;
+ flags = s->flags;
+ break;
+ }
+ }
+
+ if (!command_fn) {
+ if (subcmd && strcmp(subcmd, "help") &&
+ strcmp(subcmd, "--help") && strcmp(subcmd, "-h"))
+ sd_err("Invalid command '%s %s'", cmd, subcmd);
+ sd_err("Available %s commands:", cmd);
+ for (s = commands[i].sub; s->name; s++)
+ sd_err(" %s %s", cmd, s->name);
+ exit(EXIT_USAGE);
+ }
+
+ return flags;
+}
+
+static void usage(const struct command *commands, int status)
+{
+ int i;
+ struct subcommand *s;
+ char name[64];
+
+ if (status)
+ sd_err("Try '%s --help' for more information.", program_name);
+ else {
+ printf("Sheepdog administrator utility\n");
+ printf("Usage: %s <command> <subcommand> [options]\n", program_name);
+ printf("\nAvailable commands:\n");
+ for (i = 0; commands[i].name; i++) {
+ for (s = commands[i].sub; s->name; s++) {
+ snprintf(name, sizeof(name), "%s %s",
+ commands[i].name, s->name);
+ printf(" %-24s%s\n", name, s->desc);
+ }
+ }
+ printf("\n");
+ printf("For more information, run "
+ "'%s <command> <subcommand> --help'.\n", program_name);
+ }
+ exit(status);
+}
+
+void subcommand_usage(char *cmd, char *subcmd, int status)
+{
+ int i, n, len = strlen(command_opts);
+ const struct sd_option *sd_opt;
+ const struct subcommand *sub, *subsub;
+ char name[64];
+
+ printf("Usage: %s %s %s", program_name, cmd, subcmd);
+
+ /* Show subcmd's subcommands if necessary */
+ sub = find_subcmd(cmd, subcmd);
+ subsub = sub->sub;
+ if (subsub) {
+ n = 0;
+ while (subsub[n].name)
+ n++;
+ if (n == 1)
+ printf(" %s", subsub[0].name);
+ else if (n > 1) {
+ printf(" {%s", subsub[0].name);
+ for (i = 1; i < n; i++)
+ printf("|%s", subsub[i].name);
+ printf("}");
+ }
+ }
+
+ for (i = 0; i < len; i++) {
+ sd_opt = find_opt(command_opts[i]);
+ if (sd_opt->has_arg)
+ printf(" [-%c %s]", sd_opt->ch, sd_opt->name);
+ else
+ printf(" [-%c]", sd_opt->ch);
+ }
+ if (command_arg)
+ printf(" %s", command_arg);
+
+ printf("\n");
+ if (subsub) {
+ printf("Available subcommands:\n");
+ for (i = 0; subsub[i].name; i++)
+ printf(" %-24s%s\n", subsub[i].name, subsub[i].desc);
+
+ }
+
+ printf("Options:\n");
+ for (i = 0; i < len; i++) {
+ sd_opt = find_opt(command_opts[i]);
+ snprintf(name, sizeof(name), "-%c, --%s",
+ sd_opt->ch, sd_opt->name);
+ printf(" %-24s%s\n", name, sd_opt->desc);
+ }
+
+ exit(status);
+}
+
+static const struct sd_option *build_sd_options(const char *opts)
+{
+ static struct sd_option sd_opts[256], *p;
+ int i, len = strlen(opts);
+
+ p = sd_opts;
+ for (i = 0; i < len; i++)
+ *p++ = *find_opt(opts[i]);
+ memset(p, 0, sizeof(struct sd_option));
+
+ return sd_opts;
+}
+
+static void crash_handler(int signo)
+{
+ sd_err("dog exits unexpectedly (%s).", strsignal(signo));
+
+ sd_backtrace();
+
+ /*
+ * OOM raises SIGABRT in xmalloc but the administrator expects
+ * that dog exits with EXIT_SYSFAIL. We have to give up
+ * dumping a core file in this case.
+ */
+ if (signo == SIGABRT)
+ exit(EXIT_SYSFAIL);
+
+ reraise_crash_signal(signo, EXIT_SYSFAIL);
+}
+
+static size_t get_nr_nodes(void)
+{
+ return sd_nodes_nr;
+}
+
+int main(int argc, char **argv)
+{
+ int ch, longindex, ret;
+ unsigned long flags;
+ struct option *long_options;
+ const struct command *commands;
+ const char *short_options;
+ char *p;
+ const struct sd_option *sd_opts;
+
+ install_crash_handler(crash_handler);
+
+ init_commands(&commands);
+
+ if (argc < 2)
+ usage(commands, 0);
+
+ flags = setup_commands(commands, argv[1], argv[2]);
+
+ optind = 3;
+
+ sd_opts = build_sd_options(command_opts);
+ long_options = build_long_options(sd_opts);
+ short_options = build_short_options(sd_opts);
+
+ while ((ch = getopt_long(argc, argv, short_options, long_options,
+ &longindex)) >= 0) {
+
+ switch (ch) {
+ case 'a':
+ if (!str_to_addr(optarg, sdhost)) {
+ sd_err("Invalid ip address %s", optarg);
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'p':
+ sdport = strtol(optarg, &p, 10);
+ if (optarg == p || sdport < 1 || sdport > UINT16_MAX) {
+ sd_err("Invalid port number '%s'", optarg);
+ exit(EXIT_USAGE);
+ }
+ break;
+ case 'r':
+ raw_output = true;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'h':
+ subcommand_usage(argv[1], argv[2], EXIT_SUCCESS);
+ break;
+ case '?':
+ usage(commands, EXIT_USAGE);
+ break;
+ default:
+ if (command_parser)
+ command_parser(ch, optarg);
+ else
+ usage(commands, EXIT_USAGE);
+ break;
+ }
+ }
+
+ if (!is_stdout_console() || raw_output)
+ highlight = false;
+
+ if (flags & CMD_NEED_NODELIST) {
+ ret = update_node_list(SD_MAX_NODES);
+ if (ret < 0) {
+ sd_err("Failed to get node list");
+ exit(EXIT_SYSFAIL);
+ }
+ }
+
+ if (flags & CMD_NEED_ARG && argc == optind)
+ subcommand_usage(argv[1], argv[2], EXIT_USAGE);
+
+ if (init_event(EPOLL_SIZE) < 0)
+ exit(EXIT_SYSFAIL);
+
+ if (init_work_queue(get_nr_nodes) != 0) {
+ sd_err("Failed to init work queue");
+ exit(EXIT_SYSFAIL);
+ }
+
+ if (sockfd_init()) {
+ sd_err("sockfd_init() failed");
+ exit(EXIT_SYSFAIL);
+ }
+
+ ret = command_fn(argc, argv);
+ if (ret == EXIT_USAGE)
+ subcommand_usage(argv[1], argv[2], EXIT_USAGE);
+ return ret;
+}
diff --git a/dog/dog.h b/dog/dog.h
new file mode 100644
index 0000000..92dd4d2
--- /dev/null
+++ b/dog/dog.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __DOG_H__
+#define __DOG_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include "sheepdog_proto.h"
+#include "sheep.h"
+#include "exits.h"
+#include "option.h"
+#include "work.h"
+#include "event.h"
+#include "config.h"
+
+#define CMD_NEED_NODELIST (1 << 0)
+#define CMD_NEED_ARG (1 << 1)
+
+#define UINT64_DECIMAL_SIZE 21
+
+struct command {
+ const char *name;
+ struct subcommand *sub;
+ int (*parser)(int, char *);
+};
+
+struct subcommand {
+ const char *name;
+ const char *arg;
+ const char *opts;
+ const char *desc;
+ struct subcommand *sub;
+ unsigned long flags;
+ int (*fn)(int, char **);
+ struct sd_option *options;
+};
+void subcommand_usage(char *cmd, char *subcmd, int status);
+
+extern uint8_t sdhost[16];
+extern int sdport;
+extern bool highlight;
+extern bool raw_output;
+extern bool verbose;
+
+extern uint32_t sd_epoch;
+extern struct sd_node sd_nodes[SD_MAX_NODES];
+extern struct sd_vnode sd_vnodes[SD_MAX_VNODES];
+extern int sd_nodes_nr, sd_vnodes_nr;
+
+bool is_current(const struct sd_inode *i);
+char *size_to_str(uint64_t _size, char *str, int str_size);
+typedef void (*vdi_parser_func_t)(uint32_t vid, const char *name,
+ const char *tag, uint32_t snapid,
+ uint32_t flags,
+ const struct sd_inode *i, void *data);
+int parse_vdi(vdi_parser_func_t func, size_t size, void *data);
+int sd_read_object(uint64_t oid, void *data, unsigned int datalen,
+ uint64_t offset, bool direct);
+int sd_write_object(uint64_t oid, uint64_t cow_oid, void *data,
+ unsigned int datalen, uint64_t offset, uint32_t flags,
+ int copies, bool create, bool direct);
+int dog_exec_req(const uint8_t *addr, int port, struct sd_req *hdr,
+ void *data);
+int send_light_req(struct sd_req *hdr, const uint8_t *addr, int port);
+int do_generic_subcommand(struct subcommand *sub, int argc, char **argv);
+int update_node_list(int max_nodes);
+void confirm(const char *message);
+void work_queue_wait(struct work_queue *q);
+int do_vdi_create(const char *vdiname, int64_t vdi_size,
+ uint32_t base_vid, uint32_t *vdi_id, bool snapshot,
+ int nr_copies);
+void show_progress(uint64_t done, uint64_t total, bool raw);
+
+extern struct command vdi_command;
+extern struct command node_command;
+extern struct command cluster_command;
+
+#ifdef HAVE_TRACE
+ extern struct command trace_command;
+#else
+ #define trace_command {}
+#endif /* HAVE_TRACE */
+
+#endif
diff --git a/dog/farm/farm.c b/dog/farm/farm.c
new file mode 100644
index 0000000..1969927
--- /dev/null
+++ b/dog/farm/farm.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2011 Taobao Inc.
+ * Copyright (C) 2013 Zelin.io
+ *
+ * Liu Yuan <namei.unix at gmail.com>
+ * Kai Zhang <kyle at zelin.io>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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 <pthread.h>
+
+#include "farm.h"
+#include "list.h"
+
+static char farm_object_dir[PATH_MAX];
+static char farm_dir[PATH_MAX];
+
+static struct sd_lock vdi_list_lock = SD_LOCK_INITIALIZER;
+struct vdi_entry {
+ char name[SD_MAX_VDI_LEN];
+ uint64_t vdi_size;
+ uint32_t vdi_id;
+ uint32_t snap_id;
+ uint8_t nr_copies;
+ struct list_head list;
+};
+static LIST_HEAD(last_vdi_list);
+
+struct snapshot_work {
+ struct trunk_entry entry;
+ struct strbuf *trunk_buf;
+ struct work work;
+};
+static struct work_queue *wq;
+static uatomic_bool work_error;
+
+static struct vdi_entry *find_vdi(const char *name)
+{
+ struct vdi_entry *vdi;
+
+ list_for_each_entry(vdi, &last_vdi_list, list) {
+ if (!strcmp(vdi->name, name))
+ return vdi;
+ }
+ return NULL;
+}
+
+static struct vdi_entry *new_vdi(const char *name, uint64_t vdi_size,
+ uint32_t vdi_id, uint32_t snap_id,
+ uint8_t nr_copies)
+{
+ struct vdi_entry *vdi;
+ vdi = xmalloc(sizeof(struct vdi_entry));
+ pstrcpy(vdi->name, sizeof(vdi->name), name);
+ vdi->vdi_size = vdi_size;
+ vdi->vdi_id = vdi_id;
+ vdi->snap_id = snap_id;
+ vdi->nr_copies = nr_copies;
+ INIT_LIST_HEAD(&vdi->list);
+ return vdi;
+}
+
+static void insert_vdi(struct sd_inode *new)
+{
+ struct vdi_entry *vdi;
+ vdi = find_vdi(new->name);
+ if (!vdi) {
+ vdi = new_vdi(new->name,
+ new->vdi_size,
+ new->vdi_id,
+ new->snap_id,
+ new->nr_copies);
+ list_add(&vdi->list, &last_vdi_list);
+ } else if (vdi->snap_id < new->snap_id) {
+ vdi->vdi_size = new->vdi_size;
+ vdi->vdi_id = new->vdi_id;
+ vdi->snap_id = new->snap_id;
+ vdi->nr_copies = new->nr_copies;
+ }
+}
+
+static int create_active_vdis(void)
+{
+ struct vdi_entry *vdi;
+ uint32_t new_vid;
+ list_for_each_entry(vdi, &last_vdi_list, list) {
+ if (do_vdi_create(vdi->name,
+ vdi->vdi_size,
+ vdi->vdi_id, &new_vid,
+ false, vdi->nr_copies) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static void free_vdi_list(void)
+{
+ struct vdi_entry *vdi, *next;
+ list_for_each_entry_safe(vdi, next, &last_vdi_list, list)
+ free(vdi);
+}
+
+char *get_object_directory(void)
+{
+ return farm_object_dir;
+}
+
+static int create_directory(const char *p)
+{
+ int ret = -1;
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_addstr(&buf, p);
+ if (xmkdir(buf.buf, 0755) < 0) {
+ if (errno == EEXIST)
+ sd_err("Path is not a directory: %s", p);
+ goto out;
+ }
+
+ if (!strlen(farm_dir))
+ strbuf_copyout(&buf, farm_dir, sizeof(farm_dir));
+
+ strbuf_addstr(&buf, "/objects");
+ if (xmkdir(buf.buf, 0755) < 0)
+ goto out;
+
+ for (int i = 0; i < 256; i++) {
+ strbuf_addf(&buf, "/%02x", i);
+ if (xmkdir(buf.buf, 0755) < 0)
+ goto out;
+
+ strbuf_remove(&buf, buf.len - 3, 3);
+ }
+
+ if (!strlen(farm_object_dir))
+ strbuf_copyout(&buf, farm_object_dir, sizeof(farm_object_dir));
+
+ ret = 0;
+out:
+ if (ret)
+ sd_err("Fail to create directory: %m");
+ strbuf_release(&buf);
+ return ret;
+}
+
+static int get_trunk_sha1(uint32_t idx, const char *tag, unsigned char *outsha1)
+{
+ int nr_logs = -1, ret = -1;
+ struct snap_log *log_buf, *log_free = NULL;
+ struct snap_file *snap_buf = NULL;
+
+ log_free = log_buf = snap_log_read(&nr_logs);
+ if (nr_logs < 0)
+ goto out;
+
+ for (int i = 0; i < nr_logs; i++, log_buf++) {
+ if (log_buf->idx != idx && strcmp(log_buf->tag, tag))
+ continue;
+ snap_buf = snap_file_read(log_buf->sha1);
+ if (!snap_buf)
+ goto out;
+ memcpy(outsha1, snap_buf->trunk_sha1, SHA1_DIGEST_SIZE);
+ ret = 0;
+ goto out;
+ }
+out:
+ free(log_free);
+ free(snap_buf);
+ return ret;
+}
+
+static int notify_vdi_add(uint32_t vdi_id, uint32_t nr_copies)
+{
+ int ret = -1;
+ struct sd_req hdr;
+ char *buf = NULL;
+
+ sd_init_req(&hdr, SD_OP_NOTIFY_VDI_ADD);
+ hdr.vdi_state.new_vid = vdi_id;
+ hdr.vdi_state.copies = nr_copies;
+ hdr.vdi_state.set_bitmap = true;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, buf);
+
+ if (ret)
+ sd_err("Fail to notify vdi add event(%"PRIx32", %d)", vdi_id,
+ nr_copies);
+
+ free(buf);
+ return ret;
+}
+
+int farm_init(const char *path)
+{
+ int ret = -1;
+
+ if (create_directory(path) < 0)
+ goto out;
+ if (snap_init(farm_dir) < 0)
+ goto out;
+ return 0;
+out:
+ if (ret)
+ sd_err("Fail to init farm.");
+ return ret;
+}
+
+bool farm_contain_snapshot(uint32_t idx, const char *tag)
+{
+ unsigned char trunk_sha1[SHA1_DIGEST_SIZE];
+ return (get_trunk_sha1(idx, tag, trunk_sha1) == 0);
+}
+
+static void do_save_object(struct work *work)
+{
+ void *buf;
+ size_t size;
+ struct snapshot_work *sw;
+
+ if (uatomic_is_true(&work_error))
+ return;
+
+ sw = container_of(work, struct snapshot_work, work);
+
+ size = get_objsize(sw->entry.oid);
+ buf = xmalloc(size);
+
+ if (sd_read_object(sw->entry.oid, buf, size, 0, true) < 0)
+ goto error;
+
+ if (slice_write(buf, size, sw->entry.sha1) < 0)
+ goto error;
+
+ free(buf);
+ return;
+error:
+ free(buf);
+ sd_err("Fail to save object, oid %"PRIx64, sw->entry.oid);
+ uatomic_set_true(&work_error);
+}
+
+static void farm_show_progress(uint64_t done, uint64_t total)
+{
+ return show_progress(done, total, true);
+}
+
+static void save_object_done(struct work *work)
+{
+ struct snapshot_work *sw = container_of(work, struct snapshot_work,
+ work);
+ static unsigned long saved;
+
+ if (uatomic_is_true(&work_error))
+ goto out;
+
+ strbuf_add(sw->trunk_buf, &sw->entry, sizeof(struct trunk_entry));
+ farm_show_progress(uatomic_add_return(&saved, 1), object_tree_size());
+out:
+ free(sw);
+}
+
+static int queue_save_snapshot_work(uint64_t oid, int nr_copies, void *data)
+{
+ struct snapshot_work *sw = xzalloc(sizeof(struct snapshot_work));
+ struct strbuf *trunk_buf = data;
+
+ sw->entry.oid = oid;
+ sw->entry.nr_copies = nr_copies;
+ sw->trunk_buf = trunk_buf;
+ sw->work.fn = do_save_object;
+ sw->work.done = save_object_done;
+ queue_work(wq, &sw->work);
+
+ return 0;
+}
+
+int farm_save_snapshot(const char *tag)
+{
+ unsigned char snap_sha1[SHA1_DIGEST_SIZE];
+ unsigned char trunk_sha1[SHA1_DIGEST_SIZE];
+ struct strbuf trunk_buf;
+ void *snap_log = NULL;
+ int log_nr, idx, ret = -1;
+ uint64_t nr_objects = object_tree_size();
+
+ snap_log = snap_log_read(&log_nr);
+ if (!snap_log)
+ goto out;
+
+ idx = log_nr + 1;
+
+ strbuf_init(&trunk_buf, sizeof(struct trunk_entry) * nr_objects);
+
+ wq = create_work_queue("save snapshot", WQ_ORDERED);
+ if (for_each_object_in_tree(queue_save_snapshot_work,
+ &trunk_buf) < 0)
+ goto out;
+
+ work_queue_wait(wq);
+ if (uatomic_is_true(&work_error))
+ goto out;
+
+ if (trunk_file_write(nr_objects, (struct trunk_entry *)trunk_buf.buf,
+ trunk_sha1) < 0)
+ goto out;
+
+ if (snap_file_write(idx, trunk_sha1, snap_sha1) < 0)
+ goto out;
+
+ if (snap_log_write(idx, tag, snap_sha1) < 0)
+ goto out;
+
+ ret = 0;
+out:
+ strbuf_release(&trunk_buf);
+ free(snap_log);
+ return ret;
+}
+
+static void do_load_object(struct work *work)
+{
+ void *buffer = NULL;
+ size_t size;
+ struct snapshot_work *sw;
+ static unsigned long loaded;
+
+ if (uatomic_is_true(&work_error))
+ return;
+
+ sw = container_of(work, struct snapshot_work, work);
+
+ buffer = slice_read(sw->entry.sha1, &size);
+
+ if (!buffer)
+ goto error;
+
+ if (sd_write_object(sw->entry.oid, 0, buffer, size, 0, 0,
+ sw->entry.nr_copies, true, true) != 0)
+ goto error;
+
+ if (is_vdi_obj(sw->entry.oid)) {
+ if (notify_vdi_add(oid_to_vid(sw->entry.oid),
+ sw->entry.nr_copies) < 0)
+ goto error;
+
+ sd_write_lock(&vdi_list_lock);
+ insert_vdi(buffer);
+ sd_unlock(&vdi_list_lock);
+ }
+
+ farm_show_progress(uatomic_add_return(&loaded, 1), trunk_get_count());
+ free(buffer);
+ return;
+error:
+ free(buffer);
+ sd_err("Fail to load object, oid %"PRIx64, sw->entry.oid);
+ uatomic_set_true(&work_error);
+}
+
+static void load_object_done(struct work *work)
+{
+ struct snapshot_work *sw = container_of(work, struct snapshot_work,
+ work);
+
+ free(sw);
+}
+
+static int queue_load_snapshot_work(struct trunk_entry *entry, void *data)
+{
+ struct snapshot_work *sw = xzalloc(sizeof(struct snapshot_work));
+
+ memcpy(&sw->entry, entry, sizeof(struct trunk_entry));
+ sw->work.fn = do_load_object;
+ sw->work.done = load_object_done;
+ queue_work(wq, &sw->work);
+
+ return 0;
+}
+
+int farm_load_snapshot(uint32_t idx, const char *tag)
+{
+ int ret = -1;
+ unsigned char trunk_sha1[SHA1_DIGEST_SIZE];
+
+ if (get_trunk_sha1(idx, tag, trunk_sha1) < 0)
+ goto out;
+
+ wq = create_work_queue("load snapshot", WQ_DYNAMIC);
+ if (for_each_entry_in_trunk(trunk_sha1, queue_load_snapshot_work,
+ NULL) < 0)
+ goto out;
+
+ work_queue_wait(wq);
+ if (uatomic_is_true(&work_error))
+ goto out;
+
+ if (create_active_vdis() < 0)
+ goto out;
+
+ ret = 0;
+out:
+ free_vdi_list();
+ return ret;
+}
diff --git a/dog/farm/farm.h b/dog/farm/farm.h
new file mode 100644
index 0000000..0f457e4
--- /dev/null
+++ b/dog/farm/farm.h
@@ -0,0 +1,83 @@
+#ifndef FARM_H
+#define FARM_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <memory.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <linux/limits.h>
+
+#include "dog.h"
+#include "sheep.h"
+#include "strbuf.h"
+#include "sha1.h"
+
+struct trunk_entry {
+ uint64_t oid;
+ int nr_copies;
+ unsigned char sha1[SHA1_DIGEST_SIZE];
+};
+
+struct trunk_file {
+ uint64_t nr_entries;
+ struct trunk_entry *entries;
+};
+
+struct snap_file {
+ int idx;
+ unsigned char trunk_sha1[SHA1_DIGEST_SIZE];
+};
+
+struct snap_log {
+ uint32_t idx;
+ char tag[SD_MAX_SNAPSHOT_TAG_LEN];
+ uint64_t time;
+ unsigned char sha1[SHA1_DIGEST_SIZE];
+};
+
+/* farm.c */
+int farm_init(const char *path);
+bool farm_contain_snapshot(uint32_t idx, const char *tag);
+int farm_save_snapshot(const char *tag);
+int farm_load_snapshot(uint32_t idx, const char *tag);
+char *get_object_directory(void);
+
+/* trunk.c */
+int trunk_init(void);
+int trunk_file_write(uint64_t nr_entries, struct trunk_entry *entries,
+ unsigned char *trunk_sha1);
+int for_each_entry_in_trunk(unsigned char *trunk_sha1,
+ int (*func)(struct trunk_entry *entry, void *data),
+ void *data);
+uint64_t trunk_get_count(void);
+
+/* snap.c */
+int snap_init(const char *path);
+struct snap_file *snap_file_read(unsigned char *sha1);
+int snap_file_write(uint32_t idx, unsigned char *trunk_sha1,
+ unsigned char *outsha1);
+void *snap_log_read(int *out_nr);
+int snap_log_write(uint32_t idx, const char *tag, unsigned char *sha1);
+
+/* sha1_file.c */
+int sha1_file_write(void *buf, size_t len, unsigned char *sha1);
+void *sha1_file_read(const unsigned char *sha1, size_t *size);
+
+/* object_tree.c */
+int object_tree_size(void);
+void object_tree_insert(uint64_t oid, int nr_copies);
+void object_tree_free(void);
+void object_tree_print(void);
+int for_each_object_in_tree(int (*func)(uint64_t oid, int nr_copies,
+ void *data), void *data);
+/* slice.c */
+int slice_write(void *buf, size_t len, unsigned char *outsha1);
+void *slice_read(const unsigned char *sha1, size_t *outsize);
+
+#endif
diff --git a/dog/farm/object_tree.c b/dog/farm/object_tree.c
new file mode 100644
index 0000000..00cad2d
--- /dev/null
+++ b/dog/farm/object_tree.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2013 Zelin.io
+ *
+ * Kai Zhang <kyle at zelin.io>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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 "farm.h"
+#include "rbtree.h"
+
+struct object_tree_entry {
+ uint64_t oid;
+ int nr_copies;
+ struct rb_node node;
+ struct list_head list;
+};
+
+struct object_tree {
+ int nr_objs;
+ struct rb_root root;
+ struct list_head list;
+};
+
+static struct object_tree tree = {
+ .nr_objs = 0,
+ .root = RB_ROOT,
+ .list = LIST_HEAD_INIT(tree.list)
+};
+static struct object_tree_entry *cached_entry;
+
+static struct object_tree_entry *do_insert(struct rb_root *root,
+ struct object_tree_entry *new)
+{
+ struct rb_node **p = &root->rb_node;
+ struct rb_node *parent = NULL;
+ struct object_tree_entry *entry;
+
+ while (*p) {
+ parent = *p;
+ entry = rb_entry(parent, struct object_tree_entry, node);
+
+ if (new->oid < entry->oid)
+ p = &(*p)->rb_left;
+ else if (new->oid > entry->oid)
+ p = &(*p)->rb_right;
+ else
+ return entry; /* already has this entry */
+ }
+ rb_link_node(&new->node, parent, p);
+ rb_insert_color(&new->node, root);
+
+ return NULL; /* insert sucessfully */
+}
+
+void object_tree_insert(uint64_t oid, int nr_copies)
+{
+ struct rb_root *root = &tree.root;
+ struct object_tree_entry *p = NULL;
+
+ if (!cached_entry)
+ cached_entry = xzalloc(sizeof(*cached_entry));
+ cached_entry->oid = oid;
+ cached_entry->nr_copies = nr_copies;
+ rb_init_node(&cached_entry->node);
+ p = do_insert(root, cached_entry);
+ if (!p) {
+ list_add(&cached_entry->list, &tree.list);
+ tree.nr_objs++;
+ cached_entry = NULL;
+ }
+}
+
+void object_tree_print(void)
+{
+ struct rb_node *p = rb_first(&tree.root);
+ struct object_tree_entry *entry;
+ printf("nr_objs: %d\n", tree.nr_objs);
+
+ while (p) {
+ entry = rb_entry(p, struct object_tree_entry, node);
+ printf("Obj id: %"PRIx64"\n", entry->oid);
+ p = rb_next(p);
+ }
+}
+
+void object_tree_free(void)
+{
+ struct object_tree_entry *entry, *next;
+ list_for_each_entry_safe(entry, next, &tree.list, list)
+ free(entry);
+
+ free(cached_entry);
+}
+
+int object_tree_size(void)
+{
+ return tree.nr_objs;
+}
+
+int for_each_object_in_tree(int (*func)(uint64_t oid, int nr_copies,
+ void *data), void *data)
+{
+ struct rb_node *p = rb_first(&tree.root);
+ struct object_tree_entry *entry;
+ int ret = -1;
+
+ while (p) {
+ entry = rb_entry(p, struct object_tree_entry, node);
+
+ if (func(entry->oid, entry->nr_copies, data) < 0)
+ goto out;
+
+ p = rb_next(p);
+ }
+ ret = 0;
+out:
+ return ret;
+}
diff --git a/dog/farm/sha1_file.c b/dog/farm/sha1_file.c
new file mode 100644
index 0000000..3ba2519
--- /dev/null
+++ b/dog/farm/sha1_file.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2011 Taobao Inc.
+ *
+ * Liu Yuan <namei.unix at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * sha1_file provide us some useful features:
+ *
+ * - Regardless of object type, all objects are all in deflated with zlib,
+ * and have a header that not only specifies their tag, but also size
+ * information about the data in the object.
+ *
+ * - the general consistency of an object can always be tested independently
+ * of the contents or the type of the object: all objects can be validated
+ * by verifying that their hashes match the content of the file.
+ */
+#include <sys/types.h>
+
+#include "farm.h"
+#include "util.h"
+
+static void fill_sha1_path(char *pathbuf, const unsigned char *sha1)
+{
+ int i;
+ for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
+ static const char hex[] = "0123456789abcdef";
+ unsigned int val = sha1[i];
+ char *pos = pathbuf + i*2 + (i > 0);
+ *pos++ = hex[val >> 4];
+ *pos = hex[val & 0xf];
+ }
+}
+
+static char *sha1_to_path(const unsigned char *sha1)
+{
+ static __thread char buf[PATH_MAX];
+ const char *objdir;
+ int len;
+
+ objdir = get_object_directory();
+ len = strlen(objdir);
+
+ /* '/' + sha1(2) + '/' + sha1(38) + '\0' */
+ memcpy(buf, objdir, len);
+ buf[len] = '/';
+ buf[len+3] = '/';
+ buf[len+42] = '\0';
+ fill_sha1_path(buf + len + 1, sha1);
+ return buf;
+}
+
+static int sha1_buffer_write(const unsigned char *sha1,
+ void *buf, unsigned int size)
+{
+ char *filename = sha1_to_path(sha1);
+ int fd, ret = 0, len;
+
+ fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
+ if (fd < 0) {
+ if (errno != EEXIST) {
+ sd_err("failed to open file %s with error: %m",
+ filename);
+ ret = -1;
+ }
+ goto err_open;
+ }
+ len = xwrite(fd, buf, size);
+ if (len != size) {
+ sd_err("%m");
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+err_open:
+ return ret;
+}
+
+int sha1_file_write(void *buf, size_t len, unsigned char *outsha1)
+{
+ unsigned char sha1[SHA1_DIGEST_SIZE];
+
+ sha1_from_buffer(buf, len, sha1);
+ if (sha1_buffer_write(sha1, buf, len) < 0)
+ return -1;
+ if (outsha1)
+ memcpy(outsha1, sha1, SHA1_DIGEST_SIZE);
+ return 0;
+}
+
+static int verify_sha1_file(const unsigned char *sha1,
+ void *buf, unsigned long len)
+{
+ unsigned char tmp[SHA1_DIGEST_SIZE];
+
+ sha1_from_buffer(buf, len, tmp);
+ if (memcmp((char *)tmp, (char *)sha1, SHA1_DIGEST_SIZE) != 0) {
+ sd_err("failed, %s != %s", sha1_to_hex(sha1), sha1_to_hex(tmp));
+ return -1;
+ }
+ return 0;
+}
+
+void *sha1_file_read(const unsigned char *sha1, size_t *size)
+{
+ char *filename = sha1_to_path(sha1);
+ int fd = open(filename, O_RDONLY);
+ struct stat st;
+ void *buf = NULL;
+
+ if (fd < 0) {
+ perror(filename);
+ return NULL;
+ }
+ if (fstat(fd, &st) < 0) {
+ sd_err("%m");
+ goto out;
+ }
+
+ buf = xmalloc(st.st_size);
+ if (!buf)
+ goto out;
+
+ if (xread(fd, buf, st.st_size) != st.st_size) {
+ free(buf);
+ buf = NULL;
+ goto out;
+ }
+
+ if (verify_sha1_file(sha1, buf, st.st_size) < 0) {
+ free(buf);
+ buf = NULL;
+ goto out;
+ }
+
+ *size = st.st_size;
+out:
+ close(fd);
+ return buf;
+}
diff --git a/dog/farm/slice.c b/dog/farm/slice.c
new file mode 100644
index 0000000..53941c1
--- /dev/null
+++ b/dog/farm/slice.c
@@ -0,0 +1,109 @@
+/*
+ * copyright (c) 2013 taobao inc.
+ *
+ * liu yuan <namei.unix at gmail.com>
+ *
+ * this program is free software; you can redistribute it and/or
+ * modify it under the terms of the gnu general public license version
+ * 2 as published by the free software foundation.
+ *
+ * you should have received a copy of the gnu general public license
+ * along with this program. if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Slice is a fixed chunk of one object to be stored in farm. We slice
+ * the object into smaller chunks to get better deduplication.
+ */
+
+#include <pthread.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "farm.h"
+#include "strbuf.h"
+#include "util.h"
+#include "sheepdog_proto.h"
+
+struct slice {
+ unsigned char sha1[SHA1_DIGEST_SIZE];
+};
+
+struct slice_file {
+ uint32_t nr_slices;
+ struct slice *slices;
+};
+
+/* 128k, best empirical value from some tests, but no rationale */
+#define SLICE_SIZE (1024*128)
+
+int slice_write(void *buf, size_t len, unsigned char *outsha1)
+{
+ int count = DIV_ROUND_UP(len, SLICE_SIZE);
+ size_t slen = count * SHA1_DIGEST_SIZE;
+ char *sbuf = xmalloc(slen);
+ char *p = buf;
+
+ for (int i = 0; i < count; i++, p += SLICE_SIZE) {
+ unsigned char sha1[SHA1_DIGEST_SIZE];
+ size_t wlen = (ssize_t)len - SLICE_SIZE > 0 ? SLICE_SIZE : len;
+ len -= SLICE_SIZE;
+
+ if (sha1_file_write(p, wlen, sha1) < 0)
+ goto err;
+ memcpy(sbuf + i * SHA1_DIGEST_SIZE, sha1, SHA1_DIGEST_SIZE);
+ }
+
+ if (sha1_file_write(sbuf, slen, outsha1) < 0)
+ goto err;
+ free(sbuf);
+ return 0;
+err:
+ free(sbuf);
+ return -1;
+}
+
+static struct slice_file *slice_file_read(const unsigned char *sha1)
+{
+ size_t size;
+ struct slice_file *slice_file = NULL;
+ void *buf = sha1_file_read(sha1, &size);
+
+ if (!buf)
+ return NULL;
+ slice_file = xmalloc(sizeof(struct slice_file));
+ slice_file->nr_slices = size / SHA1_DIGEST_SIZE;
+ slice_file->slices = buf;
+
+ return slice_file;
+}
+
+void *slice_read(const unsigned char *sha1, size_t *outsize)
+{
+ struct slice_file *file = slice_file_read(sha1);
+ struct strbuf buf = STRBUF_INIT;
+ void *object;
+
+ if (!file)
+ goto err;
+
+ *outsize = 0;
+ for (uint32_t i = 0; i < file->nr_slices; i++) {
+ size_t size;
+ void *sbuf;
+
+ sbuf = sha1_file_read(file->slices[i].sha1, &size);
+ if (!sbuf)
+ goto err;
+ strbuf_add(&buf, sbuf, size);
+ *outsize += size;
+ }
+
+ object = xmalloc(*outsize);
+ strbuf_copyout(&buf, object, *outsize);
+ strbuf_release(&buf);
+ return object;
+err:
+ strbuf_release(&buf);
+ return NULL;
+}
diff --git a/dog/farm/snap.c b/dog/farm/snap.c
new file mode 100644
index 0000000..8c46484
--- /dev/null
+++ b/dog/farm/snap.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2011 Taobao Inc.
+ * Copyright (C) 2013 Zelin.io
+ *
+ * Liu Yuan <namei.unix at gmail.com>
+ * Kai Zhang <kyle at zelin.io>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Snap object is the meta data that describes the cluster snapshot. */
+
+#include <time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "farm.h"
+
+static char snap_log_path[PATH_MAX];
+
+int snap_init(const char *farm_dir)
+{
+ int fd, ret = -1;
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_addstr(&buf, farm_dir);
+ strbuf_addf(&buf, "/%s", "user_snap");
+
+ if (!strlen(snap_log_path))
+ strbuf_copyout(&buf, snap_log_path, sizeof(snap_log_path));
+
+ fd = open(snap_log_path, O_CREAT | O_EXCL, 0666);
+ if (fd < 0) {
+ if (errno != EEXIST) {
+ sd_err("%m");
+ goto out;
+ }
+ }
+
+ ret = 0;
+ close(fd);
+out:
+ strbuf_release(&buf);
+ return ret;
+}
+
+int snap_log_write(uint32_t idx, const char *tag, unsigned char *sha1)
+{
+ int fd, ret = -1;
+ struct strbuf buf = STRBUF_INIT;
+ struct snap_log log = { .idx = idx,
+ .time = time(NULL) };
+ pstrcpy(log.tag, SD_MAX_SNAPSHOT_TAG_LEN, tag);
+ memcpy(log.sha1, sha1, SHA1_DIGEST_SIZE);
+
+ fd = open(snap_log_path, O_WRONLY | O_APPEND);
+ if (fd < 0) {
+ sd_err("%m");
+ goto out;
+ }
+
+ strbuf_reset(&buf);
+ strbuf_add(&buf, &log, sizeof(log));
+ ret = xwrite(fd, buf.buf, buf.len);
+ if (ret != buf.len)
+ goto out_close;
+
+ ret = 0;
+out_close:
+ close(fd);
+out:
+ strbuf_release(&buf);
+ return ret;
+}
+
+void *snap_log_read(int *out_nr)
+{
+ struct stat st;
+ void *buffer = NULL;
+ int len, fd;
+
+ fd = open(snap_log_path, O_RDONLY);
+ if (fd < 0) {
+ sd_err("%m");
+ goto out;
+ }
+ if (fstat(fd, &st) < 0) {
+ sd_err("%m");
+ goto out_close;
+ }
+
+ len = st.st_size;
+ buffer = xmalloc(len);
+ len = xread(fd, buffer, len);
+ if (len != st.st_size) {
+ free(buffer);
+ buffer = NULL;
+ goto out_close;
+ }
+ *out_nr = len / sizeof(struct snap_log);
+out_close:
+ close(fd);
+out:
+ return buffer;
+}
+
+struct snap_file *snap_file_read(unsigned char *sha1)
+{
+ size_t size;
+ return sha1_file_read(sha1, &size);
+}
+
+int snap_file_write(uint32_t idx, unsigned char *trunk_sha1,
+ unsigned char *outsha1)
+{
+ struct snap_file snap;
+ snap.idx = idx;
+ memcpy(snap.trunk_sha1, trunk_sha1, SHA1_DIGEST_SIZE);
+
+ return sha1_file_write(&snap, sizeof(struct snap_file),
+ outsha1);
+}
diff --git a/dog/farm/trunk.c b/dog/farm/trunk.c
new file mode 100644
index 0000000..91f293e
--- /dev/null
+++ b/dog/farm/trunk.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2011 Taobao Inc.
+ * Copyright (C) 2013 Zelin.io
+ *
+ * Liu Yuan <namei.unix at gmail.com>
+ * Kai Zhang <kyle at zelin.io>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Trunk object is meta data that describes the structure of the data objects
+ * at the time of snapshot being taken. It ties data objects together into a
+ * flat directory structure.
+ */
+#include <pthread.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "farm.h"
+#include "strbuf.h"
+#include "list.h"
+#include "util.h"
+#include "sheepdog_proto.h"
+
+static uint64_t total_count;
+
+int trunk_file_write(uint64_t nr_entries, struct trunk_entry *entries,
+ unsigned char *trunk_sha1)
+{
+ size_t size = sizeof(struct trunk_entry) * nr_entries;
+ return sha1_file_write(entries, size, trunk_sha1);
+}
+
+static struct trunk_file *trunk_file_read(unsigned char *sha1)
+{
+ size_t size;
+ struct trunk_file *trunk = NULL;
+ void *buf = sha1_file_read(sha1, &size);
+
+ if (!buf)
+ return NULL;
+ trunk = xmalloc(sizeof(struct trunk_file));
+ trunk->nr_entries = size / sizeof(struct trunk_entry);
+ trunk->entries = buf;
+
+ return trunk;
+}
+
+int for_each_entry_in_trunk(unsigned char *trunk_sha1,
+ int (*func)(struct trunk_entry *entry, void *data),
+ void *data)
+{
+ struct trunk_file *trunk;
+ struct trunk_entry *entry;
+ int ret = -1;
+
+ trunk = trunk_file_read(trunk_sha1);
+ if (!trunk)
+ goto out;
+
+ total_count = trunk->nr_entries;
+ entry = trunk->entries;
+ for (uint64_t i = 0; i < trunk->nr_entries; i++, entry++) {
+ if (func(entry, data) < 0)
+ goto out;
+ }
+
+ ret = 0;
+out:
+ free(trunk->entries);
+ free(trunk);
+ return ret;
+}
+
+uint64_t trunk_get_count(void)
+{
+ return total_count;
+}
diff --git a/dog/node.c b/dog/node.c
new file mode 100644
index 0000000..e00058e
--- /dev/null
+++ b/dog/node.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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 "dog.h"
+
+static struct node_cmd_data {
+ bool all_nodes;
+ bool recovery_progress;
+} node_cmd_data;
+
+static void cal_total_vdi_size(uint32_t vid, const char *name, const char *tag,
+ uint32_t snapid, uint32_t flags,
+ const struct sd_inode *i, void *data)
+{
+ uint64_t *size = data;
+
+ if (!vdi_is_snapshot(i))
+ *size += i->vdi_size;
+}
+
+static int node_list(int argc, char **argv)
+{
+ int i;
+
+ if (!raw_output)
+ printf(" Id Host:Port V-Nodes Zone\n");
+ for (i = 0; i < sd_nodes_nr; i++) {
+ const char *host = addr_to_str(sd_nodes[i].nid.addr,
+ sd_nodes[i].nid.port);
+
+ printf(raw_output ? "%d %s %d %u\n" : "%4d %-20s\t%2d%11u\n",
+ i, host, sd_nodes[i].nr_vnodes, sd_nodes[i].zone);
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int node_info(int argc, char **argv)
+{
+ int i, ret, success = 0;
+ uint64_t total_size = 0, total_avail = 0, total_vdi_size = 0;
+ char total_str[UINT64_DECIMAL_SIZE], use_str[UINT64_DECIMAL_SIZE],
+ avail_str[UINT64_DECIMAL_SIZE], vdi_size_str[UINT64_DECIMAL_SIZE];
+
+ if (!raw_output)
+ printf("Id\tSize\tUsed\tAvail\tUse%%\n");
+
+ for (i = 0; i < sd_nodes_nr; i++) {
+ struct sd_req req;
+ struct sd_rsp *rsp = (struct sd_rsp *)&req;
+ char store_str[UINT64_DECIMAL_SIZE],
+ used_str[UINT64_DECIMAL_SIZE],
+ free_str[UINT64_DECIMAL_SIZE];
+
+ sd_init_req(&req, SD_OP_STAT_SHEEP);
+
+ ret = send_light_req(&req, sd_nodes[i].nid.addr,
+ sd_nodes[i].nid.port);
+
+ size_to_str(rsp->node.store_size, store_str, sizeof(store_str));
+ size_to_str(rsp->node.store_free, free_str, sizeof(free_str));
+ size_to_str(rsp->node.store_size - rsp->node.store_free,
+ used_str, sizeof(used_str));
+ if (!ret) {
+ int ratio = (int)(((double)(rsp->node.store_size -
+ rsp->node.store_free) /
+ rsp->node.store_size) * 100);
+ printf(raw_output ? "%d %s %s %s %d%%\n" :
+ "%2d\t%s\t%s\t%s\t%3d%%\n",
+ i, store_str, used_str, free_str,
+ rsp->node.store_size == 0 ? 0 : ratio);
+ success++;
+ }
+
+ total_size += rsp->node.store_size;
+ total_avail += rsp->node.store_free;
+ }
+
+ if (success == 0) {
+ sd_err("Cannot get information from any nodes");
+ return EXIT_SYSFAIL;
+ }
+
+ if (parse_vdi(cal_total_vdi_size, SD_INODE_HEADER_SIZE,
+ &total_vdi_size) < 0)
+ return EXIT_SYSFAIL;
+
+ size_to_str(total_size, total_str, sizeof(total_str));
+ size_to_str(total_avail, avail_str, sizeof(avail_str));
+ size_to_str(total_size - total_avail, use_str, sizeof(use_str));
+ size_to_str(total_vdi_size, vdi_size_str, sizeof(vdi_size_str));
+ printf(raw_output ? "Total %s %s %s %d%% %s\n"
+ : "Total\t%s\t%s\t%s\t%3d%%\n\n"
+ "Total virtual image size\t%s\n",
+ total_str, use_str, avail_str,
+ (int)(((double)(total_size - total_avail) / total_size) * 100),
+ vdi_size_str);
+
+ return EXIT_SUCCESS;
+}
+
+static int get_recovery_state(struct recovery_state *state)
+{
+ int ret;
+ struct sd_req req;
+
+ sd_init_req(&req, SD_OP_STAT_RECOVERY);
+ req.data_length = sizeof(*state);
+
+ ret = dog_exec_req(sdhost, sdport, &req, state);
+ if (ret < 0) {
+ sd_err("Failed to execute request");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int node_recovery_progress(void)
+{
+ int result;
+ unsigned int prev_nr_total;
+ struct recovery_state rstate;
+
+ /*
+ * ToDos
+ *
+ * 1. Calculate size of actually copied objects.
+ * For doing this, not so trivial changes for recovery process are
+ * required.
+ *
+ * 2. Print remaining physical time.
+ * Even if it is not so acculate, the information is helpful for
+ * administrators.
+ */
+
+ result = get_recovery_state(&rstate);
+ if (result < 0)
+ return EXIT_SYSFAIL;
+
+ if (!rstate.in_recovery)
+ return EXIT_SUCCESS;
+
+ do {
+ prev_nr_total = rstate.nr_total;
+
+ result = get_recovery_state(&rstate);
+ if (result < 0)
+ break;
+
+ if (!rstate.in_recovery) {
+ show_progress(prev_nr_total, prev_nr_total, true);
+ break;
+ }
+
+ switch (rstate.state) {
+ case RW_PREPARE_LIST:
+ printf("\rpreparing a checked object list...");
+ break;
+ case RW_NOTIFY_COMPLETION:
+ printf("\rnotifying a completion of recovery...");
+ break;
+ case RW_RECOVER_OBJ:
+ show_progress(rstate.nr_finished, rstate.nr_total,
+ true);
+ break;
+ default:
+ panic("unknown state of recovery: %d", rstate.state);
+ break;
+ }
+
+ sleep(1);
+ } while (true);
+
+ return result < 0 ? EXIT_SYSFAIL : EXIT_SUCCESS;
+}
+
+static int node_recovery(int argc, char **argv)
+{
+ int i, ret;
+
+ if (node_cmd_data.recovery_progress)
+ return node_recovery_progress();
+
+ if (!raw_output) {
+ printf("Nodes In Recovery:\n");
+ printf(" Id Host:Port V-Nodes Zone"
+ " Progress\n");
+ }
+
+ for (i = 0; i < sd_nodes_nr; i++) {
+ struct sd_req req;
+ struct recovery_state state;
+
+ memset(&state, 0, sizeof(state));
+
+ sd_init_req(&req, SD_OP_STAT_RECOVERY);
+ req.data_length = sizeof(state);
+
+ ret = dog_exec_req(sd_nodes[i].nid.addr,
+ sd_nodes[i].nid.port, &req, &state);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ if (state.in_recovery) {
+ const char *host = addr_to_str(sd_nodes[i].nid.addr,
+ sd_nodes[i].nid.port);
+ if (raw_output)
+ printf("%d %s %d %d %"PRIu64" %"PRIu64"\n", i,
+ host, sd_nodes[i].nr_vnodes,
+ sd_nodes[i].zone, state.nr_finished,
+ state.nr_total);
+ else
+ printf("%4d %-20s%5d%11d%11.1f%%\n", i, host,
+ sd_nodes[i].nr_vnodes, sd_nodes[i].zone,
+ 100 * (float)state.nr_finished
+ / state.nr_total);
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int node_kill(int argc, char **argv)
+{
+ int node_id, ret;
+ struct sd_req req;
+ const char *p = argv[optind++];
+
+ if (!is_numeric(p)) {
+ sd_err("Invalid node id '%s', please specify a numeric value",
+ p);
+ exit(EXIT_USAGE);
+ }
+
+ node_id = strtol(p, NULL, 10);
+ if (node_id < 0 || node_id >= sd_nodes_nr) {
+ sd_err("Invalid node id '%d'", node_id);
+ exit(EXIT_USAGE);
+ }
+
+ sd_init_req(&req, SD_OP_KILL_NODE);
+
+ ret = send_light_req(&req, sd_nodes[node_id].nid.addr,
+ sd_nodes[node_id].nid.port);
+ if (ret) {
+ sd_err("Failed to execute request");
+ exit(EXIT_FAILURE);
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int node_md_info(struct node_id *nid)
+{
+ struct sd_md_info info = {};
+ char size_str[UINT64_DECIMAL_SIZE], used_str[UINT64_DECIMAL_SIZE],
+ avail_str[UINT64_DECIMAL_SIZE];
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ int ret, i;
+
+ sd_init_req(&hdr, SD_OP_MD_INFO);
+ hdr.data_length = sizeof(info);
+
+ ret = dog_exec_req(nid->addr, nid->port, &hdr, &info);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("failed to get multi-disk infomation: %s",
+ sd_strerror(rsp->result));
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < info.nr; i++) {
+ uint64_t size = info.disk[i].free + info.disk[i].used;
+ int ratio = (int)(((double)info.disk[i].used / size) * 100);
+
+ size_to_str(size, size_str, sizeof(size_str));
+ size_to_str(info.disk[i].used, used_str, sizeof(used_str));
+ size_to_str(info.disk[i].free, avail_str, sizeof(avail_str));
+ fprintf(stdout, "%2d\t%s\t%s\t%s\t%3d%%\t%s\n",
+ info.disk[i].idx, size_str, used_str, avail_str, ratio,
+ info.disk[i].path);
+ }
+ return EXIT_SUCCESS;
+}
+
+static int md_info(int argc, char **argv)
+{
+ int i, ret;
+
+ fprintf(stdout, "Id\tSize\tUsed\tAvail\tUse%%\tPath\n");
+
+ if (!node_cmd_data.all_nodes) {
+ struct node_id nid = {.port = sdport};
+
+ memcpy(nid.addr, sdhost, sizeof(nid.addr));
+
+ return node_md_info(&nid);
+ }
+
+ for (i = 0; i < sd_nodes_nr; i++) {
+ fprintf(stdout, "Node %d:\n", i);
+ ret = node_md_info(&sd_nodes[i].nid);
+ if (ret != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+}
+
+static int do_plug_unplug(char *disks, bool plug)
+{
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ int ret;
+
+ if (!strlen(disks)) {
+ sd_err("Empty path isn't allowed");
+ return EXIT_FAILURE;
+ }
+
+ if (plug)
+ sd_init_req(&hdr, SD_OP_MD_PLUG);
+ else
+ sd_init_req(&hdr, SD_OP_MD_UNPLUG);
+ hdr.flags = SD_FLAG_CMD_WRITE;
+ hdr.data_length = strlen(disks) + 1;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, disks);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("Failed to execute request, look for sheep.log"
+ " for more information");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int md_plug(int argc, char **argv)
+{
+ return do_plug_unplug(argv[optind], true);
+}
+
+static int md_unplug(int argc, char **argv)
+{
+ return do_plug_unplug(argv[optind], false);
+}
+
+static struct subcommand node_md_cmd[] = {
+ {"info", NULL, NULL, "show multi-disk information",
+ NULL, CMD_NEED_NODELIST, md_info},
+ {"plug", NULL, NULL, "plug more disk(s) into node",
+ NULL, CMD_NEED_ARG, md_plug},
+ {"unplug", NULL, NULL, "unplug disk(s) from node",
+ NULL, CMD_NEED_ARG, md_unplug},
+ {NULL},
+};
+
+static int node_md(int argc, char **argv)
+{
+ return do_generic_subcommand(node_md_cmd, argc, argv);
+}
+
+
+static int node_parser(int ch, char *opt)
+{
+ switch (ch) {
+ case 'A':
+ node_cmd_data.all_nodes = true;
+ break;
+ case 'P':
+ node_cmd_data.recovery_progress = true;
+ break;
+ }
+
+ return 0;
+}
+
+static struct sd_option node_options[] = {
+ {'A', "all", false, "show md information of all the nodes"},
+ {'P', "progress", false, "show progress of recovery in the node"},
+
+ { 0, NULL, false, NULL },
+};
+
+static struct subcommand node_cmd[] = {
+ {"kill", "<node id>", "aprh", "kill node", NULL,
+ CMD_NEED_ARG | CMD_NEED_NODELIST, node_kill},
+ {"list", NULL, "aprh", "list nodes", NULL,
+ CMD_NEED_NODELIST, node_list},
+ {"info", NULL, "aprh", "show information about each node", NULL,
+ CMD_NEED_NODELIST, node_info},
+ {"recovery", NULL, "aphPr", "show recovery information of nodes", NULL,
+ CMD_NEED_NODELIST, node_recovery, node_options},
+ {"md", "[disks]", "apAh", "See 'dog node md' for more information",
+ node_md_cmd, CMD_NEED_ARG, node_md, node_options},
+ {NULL,},
+};
+
+struct command node_command = {
+ "node",
+ node_cmd,
+ node_parser
+};
diff --git a/dog/trace.c b/dog/trace.c
new file mode 100644
index 0000000..162a935
--- /dev/null
+++ b/dog/trace.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2011 Taobao Inc.
+ *
+ * Liu Yuan <namei.unix at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "dog.h"
+#include "rbtree.h"
+#include "list.h"
+
+static inline void print_thread_name(struct trace_graph_item *item)
+{
+ printf("%-*s|", TRACE_THREAD_LEN, item->tname);
+}
+
+static inline void print_time(struct trace_graph_item *item)
+{
+ if (item->type == TRACE_GRAPH_RETURN) {
+ unsigned duration = item->return_time - item->entry_time;
+ unsigned quot = duration / 1000, rem = duration % 1000;
+
+ printf("%8u.%-3u|", quot, rem);
+ } else if (item->type == TRACE_GRAPH_ENTRY) {
+ printf(" |");
+ }
+}
+
+static inline void print_finale(struct trace_graph_item *item)
+{
+ int i;
+
+ for (i = 0; i < item->depth; i++)
+ printf(" ");
+ if (item->type == TRACE_GRAPH_ENTRY)
+ printf("%s() {\n", item->fname);
+ else
+ printf("}\n");
+}
+
+static void print_trace_item(struct trace_graph_item *item)
+{
+ print_thread_name(item);
+ print_time(item);
+ print_finale(item);
+}
+
+static void cat_trace_file(void *buf, size_t size)
+{
+ struct trace_graph_item *item = (struct trace_graph_item *)buf;
+ size_t sz = size / sizeof(struct trace_graph_item), i;
+
+ printf(" Thread Name | Time(us) | Function Graph\n");
+ printf("--------------------------------------------------\n");
+ for (i = 0; i < sz; i++)
+ print_trace_item(item++);
+ return;
+}
+
+static const char *tracefile = "/tmp/tracefile";
+
+static int trace_read_buffer(void)
+{
+ int ret, tfd;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+#define TRACE_BUF_LEN (1024 * 1024 * 20)
+ char *buf = xzalloc(TRACE_BUF_LEN);
+
+ tfd = open(tracefile, O_CREAT | O_RDWR | O_APPEND | O_TRUNC, 0644);
+ if (tfd < 0) {
+ sd_err("can't create tracefile");
+ return EXIT_SYSFAIL;
+ }
+
+read_buffer:
+ sd_init_req(&hdr, SD_OP_TRACE_READ_BUF);
+ hdr.data_length = TRACE_BUF_LEN;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, buf);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ if (rsp->result == SD_RES_AGAIN)
+ goto read_buffer;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("Trace failed: %s", sd_strerror(rsp->result));
+ return EXIT_FAILURE;
+ }
+
+ xwrite(tfd, buf, rsp->data_length);
+ if (rsp->data_length == TRACE_BUF_LEN) {
+ memset(buf, 0, TRACE_BUF_LEN);
+ goto read_buffer;
+ }
+
+ free(buf);
+ return EXIT_SUCCESS;
+}
+
+static int trace_enable(int argc, char **argv)
+{
+ const char *tracer = argv[optind];
+ int ret;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+
+ sd_init_req(&hdr, SD_OP_TRACE_ENABLE);
+ hdr.flags = SD_FLAG_CMD_WRITE;
+ hdr.data_length = strlen(tracer) + 1;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, (void *)tracer);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ switch (rsp->result) {
+ case SD_RES_SUCCESS:
+ break;
+ case SD_RES_NO_SUPPORT:
+ sd_err("no such tracer %s", tracer);
+ return EXIT_FAILURE;
+ case SD_RES_INVALID_PARMS:
+ sd_err("tracer %s is already enabled", tracer);
+ return EXIT_FAILURE;
+ default:
+ sd_err("unknown error (%s)", sd_strerror(rsp->result));
+ return EXIT_SYSFAIL;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int trace_disable(int argc, char **argv)
+{
+ const char *tracer = argv[optind];
+ int ret;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+
+ sd_init_req(&hdr, SD_OP_TRACE_DISABLE);
+ hdr.flags = SD_FLAG_CMD_WRITE;
+ hdr.data_length = strlen(tracer) + 1;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, (void *)tracer);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ switch (rsp->result) {
+ case SD_RES_SUCCESS:
+ break;
+ case SD_RES_NO_SUPPORT:
+ sd_err("no such tracer %s", tracer);
+ return EXIT_FAILURE;
+ case SD_RES_INVALID_PARMS:
+ sd_err("tracer %s is not enabled", tracer);
+ return EXIT_FAILURE;
+ default:
+ sd_err("unknown error (%s)", sd_strerror(rsp->result));
+ return EXIT_SYSFAIL;
+ }
+
+ return trace_read_buffer();
+}
+
+static int trace_status(int argc, char **argv)
+{
+ char buf[4096]; /* must have enough space to store tracer list */
+ int ret;
+ struct sd_req hdr;
+
+ sd_init_req(&hdr, SD_OP_TRACE_STATUS);
+ hdr.data_length = sizeof(buf);
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, buf);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ printf("%s", buf);
+
+ return EXIT_SUCCESS;
+}
+
+static void *map_trace_file(struct stat *st)
+{
+ int fd = open(tracefile, O_RDONLY);
+ void *map;
+
+ if (fd < 0) {
+ sd_err("%m");
+ return NULL;
+ }
+
+ if (fstat(fd, st) < 0) {
+ sd_err("%m");
+ close(fd);
+ return NULL;
+ }
+
+ if (st->st_size == 0) {
+ sd_err("trace file is empty");
+ return NULL;
+ }
+
+ map = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ close(fd);
+ if (map == MAP_FAILED) {
+ sd_err("%m");
+ return NULL;
+ }
+
+ return map;
+}
+
+static int graph_cat(int argc, char **argv)
+{
+ struct stat st;
+ void *map = map_trace_file(&st);
+
+ if (!map)
+ return EXIT_FAILURE;
+
+ cat_trace_file(map, st.st_size);
+ munmap(map, st.st_size);
+
+ return EXIT_SUCCESS;
+}
+
+struct graph_stat_entry {
+ struct rb_node rb;
+ struct list_head list;
+ char fname[TRACE_FNAME_LEN];
+ uint64_t duration;
+ uint16_t nr_calls;
+};
+
+static struct rb_root stat_tree_root;
+
+static LIST_HEAD(stat_list);
+
+static struct graph_stat_entry *
+stat_tree_insert(struct graph_stat_entry *new)
+{
+ struct rb_node **p = &stat_tree_root.rb_node;
+ struct rb_node *parent = NULL;
+ struct graph_stat_entry *entry;
+
+ while (*p) {
+ int cmp;
+
+ parent = *p;
+ entry = rb_entry(parent, struct graph_stat_entry, rb);
+ cmp = strcmp(new->fname, entry->fname);
+
+ if (cmp < 0)
+ p = &(*p)->rb_left;
+ else if (cmp > 0)
+ p = &(*p)->rb_right;
+ else {
+ entry->duration += new->duration;
+ entry->nr_calls++;
+ return entry;
+ }
+ }
+ rb_link_node(&new->rb, parent, p);
+ rb_insert_color(&new->rb, &stat_tree_root);
+
+ return NULL; /* insert successfully */
+}
+
+static void prepare_stat_tree(struct trace_graph_item *item)
+{
+ struct graph_stat_entry *new;
+
+ if (item->type != TRACE_GRAPH_RETURN)
+ return;
+ new = xmalloc(sizeof(*new));
+ pstrcpy(new->fname, sizeof(new->fname), item->fname);
+ new->duration = item->return_time - item->entry_time;
+ new->nr_calls = 1;
+ INIT_LIST_HEAD(&new->list);
+ if (stat_tree_insert(new)) {
+ free(new);
+ return;
+ }
+ list_add(&new->list, &stat_list);
+}
+
+static void stat_list_print(void)
+{
+ struct graph_stat_entry *entry;
+
+ list_for_each_entry(entry, &stat_list, list) {
+ float total = (float)entry->duration / 1000000000;
+ float per = (float)entry->duration / entry->nr_calls / 1000000;
+
+ printf("%10.3f %10.3f %5"PRIu16" %-*s\n", total, per,
+ entry->nr_calls, TRACE_FNAME_LEN, entry->fname);
+ }
+}
+
+static int stat_list_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+ struct graph_stat_entry *ga = container_of(a, struct graph_stat_entry,
+ list);
+ struct graph_stat_entry *gb = container_of(b, struct graph_stat_entry,
+ list);
+ /* '-' is for reverse sort, largest first */
+ return -intcmp(ga->duration, gb->duration);
+}
+
+static void stat_trace_file(void *buf, size_t size)
+{
+ struct trace_graph_item *item = (struct trace_graph_item *)buf;
+ size_t sz = size / sizeof(struct trace_graph_item), i;
+
+ printf(" Total (s) Per Call (ms) Calls Name\n");
+ for (i = 0; i < sz; i++)
+ prepare_stat_tree(item++);
+ list_sort(NULL, &stat_list, stat_list_cmp);
+ stat_list_print();
+}
+
+static int graph_stat(int argc, char **argv)
+{
+ struct stat st;
+ void *map = map_trace_file(&st);
+
+ if (!map)
+ return EXIT_FAILURE;
+
+ stat_trace_file(map, st.st_size);
+ munmap(map, st.st_size);
+ return EXIT_SUCCESS;
+}
+
+static int trace_parser(int ch, char *opt)
+{
+ return 0;
+}
+
+static struct subcommand graph_cmd[] = {
+ {"cat", NULL, NULL, "cat the output of graph tracer",
+ NULL, 0, graph_cat},
+ {"stat", NULL, NULL, "get the stat of the graph calls",
+ NULL, 0, graph_stat},
+ {NULL,},
+};
+
+static int trace_graph(int argc, char **argv)
+{
+ return do_generic_subcommand(graph_cmd, argc, argv);
+}
+
+/* Subcommand list of trace */
+static struct subcommand trace_cmd[] = {
+ {"enable", "<tracer>", "aph", "enable tracer", NULL,
+ CMD_NEED_ARG, trace_enable},
+ {"disable", "<tracer>", "aph", "disable tracer", NULL,
+ CMD_NEED_ARG, trace_disable},
+ {"status", NULL, "aph", "show tracer statuses", NULL,
+ 0, trace_status},
+ {"graph", NULL, "aph", "run dog trace graph for more information",
+ graph_cmd, CMD_NEED_ARG, trace_graph},
+ {NULL},
+};
+
+struct command trace_command = {
+ "trace",
+ trace_cmd,
+ trace_parser
+};
diff --git a/dog/treeview.c b/dog/treeview.c
new file mode 100644
index 0000000..baf0f00
--- /dev/null
+++ b/dog/treeview.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2009-2011 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "util.h"
+#include "treeview.h"
+
+#ifndef MAX_DEPTH
+#define MAX_DEPTH 100
+#endif
+
+struct vdi_tree {
+ char name[1024];
+ char label[256];
+ uint32_t vid;
+ uint32_t pvid;
+ bool highlight;
+ struct list_head children;
+ struct list_head siblings;
+};
+
+static int *width, *more;
+static struct vdi_tree *root;
+
+static struct vdi_tree *find_vdi(struct vdi_tree *parent, uint32_t vid,
+ const char *name)
+{
+ struct vdi_tree *vdi, *ret;
+
+ list_for_each_entry(vdi, &parent->children, siblings) {
+ if (vdi->vid == vid && !strcmp(vdi->name, name))
+ return vdi;
+
+ ret = find_vdi(vdi, vid, name);
+ if (ret)
+ return ret;
+ }
+ return NULL;
+}
+
+static struct vdi_tree *new_vdi(const char *name, const char *label,
+ uint64_t vid, uint64_t pvid, bool highlight)
+{
+ struct vdi_tree *vdi;
+
+ vdi = xmalloc(sizeof(struct vdi_tree));
+ pstrcpy(vdi->name, sizeof(vdi->name), name);
+ pstrcpy(vdi->label, sizeof(vdi->label), label);
+ vdi->vid = vid;
+ vdi->pvid = pvid;
+ vdi->highlight = highlight;
+ INIT_LIST_HEAD(&vdi->children);
+ return vdi;
+}
+
+void init_tree(void)
+{
+ root = new_vdi("", "", 0, 0, 0);
+}
+
+void add_vdi_tree(const char *name, const char *label, uint32_t vid,
+ uint32_t pvid, bool highlight)
+{
+ struct vdi_tree *vdi, *parent;
+
+ vdi = new_vdi(name, label, vid, pvid, highlight);
+ if (!vdi)
+ return;
+
+ parent = find_vdi(root, pvid, name);
+ if (!parent)
+ parent = root;
+
+ list_add_tail(&vdi->siblings, &parent->children);
+}
+
+static void compaction(struct vdi_tree *parent)
+{
+ struct vdi_tree *vdi, *e, *new_parent;
+
+ list_for_each_entry_safe(vdi, e, &parent->children, siblings) {
+ new_parent = find_vdi(root, vdi->pvid, vdi->name);
+ if (new_parent && parent != new_parent)
+ list_move_tail(&vdi->siblings, &new_parent->children);
+
+ compaction(vdi);
+ }
+}
+
+static int get_depth(struct vdi_tree *parent)
+{
+ struct vdi_tree *vdi;
+ int max_depth = 0, depth;
+
+ list_for_each_entry(vdi, &parent->children, siblings) {
+ depth = get_depth(vdi);
+ if (max_depth < depth)
+ max_depth = depth;
+ }
+ return max_depth + 1;
+}
+
+static void spaces(int n)
+{
+ while (n--)
+ putchar(' ');
+}
+
+static void indent(int level, bool first, bool last)
+{
+ int lvl;
+
+ if (first)
+ printf(last ? "---" : "-+-");
+ else {
+ for (lvl = 0; lvl < level - 1; lvl++) {
+ spaces(width[lvl] + 1);
+ printf(more[lvl + 1] ? "| " : " ");
+ }
+
+ spaces(width[level - 1] + 1);
+ printf(last ? "`-" : "|-");
+ }
+}
+
+static void _dump_tree(struct vdi_tree *current, int level, bool first, bool last)
+{
+ struct vdi_tree *vdi;
+
+ indent(level, first, last);
+
+ if (current->highlight)
+ printf(TEXT_BOLD);
+
+ printf("%s", current->label);
+
+ if (current->highlight)
+ printf(TEXT_NORMAL);
+
+ if (list_empty(¤t->children)) {
+ putchar('\n');
+ return;
+ }
+
+ more[level] = !last;
+ width[level] = strlen(current->label);
+
+ list_for_each_entry(vdi, ¤t->children, siblings) {
+ _dump_tree(vdi, level + 1,
+ &vdi->siblings == current->children.next,
+ vdi->siblings.next == ¤t->children);
+ }
+}
+
+void dump_tree(void)
+{
+ struct vdi_tree *vdi;
+ int depth;
+
+ compaction(root);
+
+ depth = get_depth(root);
+
+ width = malloc(sizeof(int) * depth);
+ more = malloc(sizeof(int) * depth);
+ if (!width || !more) {
+ sd_err("Failed to allocate memory");
+ return;
+ }
+
+ list_for_each_entry(vdi, &root->children, siblings) {
+ printf("%s", vdi->name);
+ more[0] = 0;
+ width[0] = strlen(vdi->name);
+ _dump_tree(vdi, 1, true, true);
+ }
+}
diff --git a/dog/treeview.h b/dog/treeview.h
new file mode 100644
index 0000000..9787fbb
--- /dev/null
+++ b/dog/treeview.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2009-2011 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __TREEVIEW__
+#define __TREEVIEW__
+
+#include <stdbool.h>
+
+void init_tree(void);
+void add_vdi_tree(const char *label, const char *tag, uint32_t vid,
+ uint32_t pvid, bool highlight);
+void dump_tree(void);
+
+#endif
diff --git a/dog/vdi.c b/dog/vdi.c
new file mode 100644
index 0000000..370ad7b
--- /dev/null
+++ b/dog/vdi.c
@@ -0,0 +1,2160 @@
+/*
+ * Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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 <ctype.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "dog.h"
+#include "treeview.h"
+#include "sha1.h"
+
+static struct sd_option vdi_options[] = {
+ {'P', "prealloc", false, "preallocate all the data objects"},
+ {'i', "index", true, "specify the index of data objects"},
+ {'s', "snapshot", true, "specify a snapshot id or tag name"},
+ {'x', "exclusive", false, "write in an exclusive mode"},
+ {'d', "delete", false, "delete a key"},
+ {'w', "writeback", false, "use writeback mode"},
+ {'c', "copies", true, "specify the data redundancy (number of copies)"},
+ {'F', "from", true, "create a differential backup from the snapshot"},
+ {'f', "force", false, "do operation forcibly"},
+ { 0, NULL, false, NULL },
+};
+
+static struct vdi_cmd_data {
+ unsigned int index;
+ int snapshot_id;
+ char snapshot_tag[SD_MAX_VDI_TAG_LEN];
+ bool exclusive;
+ bool delete;
+ bool prealloc;
+ int nr_copies;
+ bool writeback;
+ int from_snapshot_id;
+ char from_snapshot_tag[SD_MAX_VDI_TAG_LEN];
+ bool force;
+} vdi_cmd_data = { ~0, };
+
+struct get_vdi_info {
+ const char *name;
+ const char *tag;
+ uint32_t vid;
+ uint32_t snapid;
+ uint8_t nr_copies;
+};
+
+static int parse_option_size(const char *value, uint64_t *ret)
+{
+ char *postfix;
+ double sizef;
+
+ sizef = strtod(value, &postfix);
+ switch (*postfix) {
+ case 'T':
+ sizef *= 1024;
+ case 'G':
+ sizef *= 1024;
+ case 'M':
+ sizef *= 1024;
+ case 'K':
+ case 'k':
+ sizef *= 1024;
+ case 'b':
+ case '\0':
+ *ret = (uint64_t) sizef;
+ break;
+ default:
+ sd_err("Invalid size '%s'", value);
+ sd_err("You may use k, M, G or T suffixes for "
+ "kilobytes, megabytes, gigabytes and terabytes.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void vdi_show_progress(uint64_t done, uint64_t total)
+{
+ return show_progress(done, total, false);
+}
+
+static void print_vdi_list(uint32_t vid, const char *name, const char *tag,
+ uint32_t snapid, uint32_t flags,
+ const struct sd_inode *i, void *data)
+{
+ int idx;
+ bool is_clone = false;
+ uint64_t my_objs, cow_objs;
+ char vdi_size_str[16], my_objs_str[16], cow_objs_str[16];
+ time_t ti;
+ struct tm tm;
+ char dbuf[128];
+ struct get_vdi_info *info = data;
+
+ if (info && strcmp(name, info->name) != 0)
+ return;
+
+ ti = i->create_time >> 32;
+ if (raw_output) {
+ snprintf(dbuf, sizeof(dbuf), "%" PRIu64, (uint64_t) ti);
+ } else {
+ localtime_r(&ti, &tm);
+ strftime(dbuf, sizeof(dbuf),
+ "%Y-%m-%d %H:%M", &tm);
+ }
+
+ my_objs = 0;
+ cow_objs = 0;
+ for (idx = 0; idx < MAX_DATA_OBJS; idx++) {
+ if (!i->data_vdi_id[idx])
+ continue;
+ if (is_data_obj_writeable(i, idx))
+ my_objs++;
+ else
+ cow_objs++;
+ }
+
+ size_to_str(i->vdi_size, vdi_size_str, sizeof(vdi_size_str));
+ size_to_str(my_objs * SD_DATA_OBJ_SIZE, my_objs_str, sizeof(my_objs_str));
+ size_to_str(cow_objs * SD_DATA_OBJ_SIZE, cow_objs_str, sizeof(cow_objs_str));
+
+ if (i->snap_id == 1 && i->parent_vdi_id != 0)
+ is_clone = true;
+
+ if (raw_output) {
+ printf("%c ", vdi_is_snapshot(i) ? 's' : (is_clone ? 'c' : '='));
+ while (*name) {
+ if (isspace(*name) || *name == '\\')
+ putchar('\\');
+ putchar(*name++);
+ }
+ printf(" %d %s %s %s %s %" PRIx32 " %d %s\n", snapid,
+ vdi_size_str, my_objs_str, cow_objs_str, dbuf, vid,
+ i->nr_copies, i->tag);
+ } else {
+ printf("%c %-8s %5d %7s %7s %7s %s %7" PRIx32 " %5d %13s\n",
+ vdi_is_snapshot(i) ? 's' : (is_clone ? 'c' : ' '),
+ name, snapid, vdi_size_str, my_objs_str, cow_objs_str,
+ dbuf, vid, i->nr_copies, i->tag);
+ }
+}
+
+static void print_vdi_tree(uint32_t vid, const char *name, const char *tag,
+ uint32_t snapid, uint32_t flags,
+ const struct sd_inode *i, void *data)
+{
+ time_t ti;
+ struct tm tm;
+ char buf[128];
+
+ if (vdi_is_snapshot(i)) {
+ ti = i->create_time >> 32;
+ localtime_r(&ti, &tm);
+
+ strftime(buf, sizeof(buf),
+ "[%Y-%m-%d %H:%M]", &tm);
+ } else
+ pstrcpy(buf, sizeof(buf), "(you are here)");
+
+ add_vdi_tree(name, buf, vid, i->parent_vdi_id,
+ highlight && !vdi_is_snapshot(i));
+}
+
+static void print_vdi_graph(uint32_t vid, const char *name, const char *tag,
+ uint32_t snapid, uint32_t flags,
+ const struct sd_inode *i, void *data)
+{
+ time_t ti;
+ struct tm tm;
+ char dbuf[128], tbuf[128], size_str[128];
+
+ ti = i->create_time >> 32;
+ localtime_r(&ti, &tm);
+
+ strftime(dbuf, sizeof(dbuf), "%Y-%m-%d", &tm);
+ strftime(tbuf, sizeof(tbuf), "%H:%M:%S", &tm);
+ size_to_str(i->vdi_size, size_str, sizeof(size_str));
+
+ printf(" \"%x\" -> \"%x\";\n", i->parent_vdi_id, vid);
+ printf(" \"%x\" [\n"
+ " group = \"%s\",\n"
+ " label = \"",
+ vid, name);
+ printf("Name: %10s\\n"
+ "Tag: %10x\\n"
+ "Size: %10s\\n"
+ "Date: %10s\\n"
+ "Time: %10s",
+ name, snapid, size_str, dbuf, tbuf);
+
+ if (vdi_is_snapshot(i))
+ printf("\"\n ];\n\n");
+ else
+ printf("\",\n color=\"red\"\n ];\n\n");
+
+}
+
+static void get_oid(uint32_t vid, const char *name, const char *tag,
+ uint32_t snapid, uint32_t flags,
+ const struct sd_inode *i, void *data)
+{
+ struct get_vdi_info *info = data;
+
+ if (info->name) {
+ if (info->tag && info->tag[0]) {
+ if (!strcmp(name, info->name) &&
+ !strcmp(tag, info->tag)) {
+ info->vid = vid;
+ info->nr_copies = i->nr_copies;
+ }
+ } else if (info->snapid) {
+ if (!strcmp(name, info->name) &&
+ snapid == info->snapid) {
+ info->vid = vid;
+ info->nr_copies = i->nr_copies;
+ }
+ } else {
+ if (!strcmp(name, info->name)) {
+ info->vid = vid;
+ info->nr_copies = i->nr_copies;
+ }
+ }
+ }
+}
+
+typedef int (*obj_parser_func_t)(const char *sheep, uint64_t oid,
+ struct sd_rsp *rsp, char *buf, void *data);
+
+static int do_print_obj(const char *sheep, uint64_t oid, struct sd_rsp *rsp,
+ char *buf, void *data)
+{
+ switch (rsp->result) {
+ case SD_RES_SUCCESS:
+ printf("%s has the object (should be %d copies)\n",
+ sheep, rsp->obj.copies);
+ break;
+ case SD_RES_NO_OBJ:
+ printf("%s doesn't have the object\n", sheep);
+ break;
+ case SD_RES_OLD_NODE_VER:
+ case SD_RES_NEW_NODE_VER:
+ sd_err("The node list has changed: please try again");
+ break;
+ default:
+ sd_err("%s: hit an unexpected error (%s)", sheep,
+ sd_strerror(rsp->result));
+ break;
+ }
+
+ return 0;
+}
+
+struct get_data_oid_info {
+ bool success;
+ uint64_t data_oid;
+ unsigned idx;
+};
+
+static int get_data_oid(const char *sheep, uint64_t oid, struct sd_rsp *rsp,
+ char *buf, void *data)
+{
+ struct get_data_oid_info *info = data;
+ struct sd_inode *inode = (struct sd_inode *)buf;
+
+ switch (rsp->result) {
+ case SD_RES_SUCCESS:
+ if (info->success)
+ break;
+ info->success = true;
+ if (inode->data_vdi_id[info->idx]) {
+ info->data_oid = vid_to_data_oid(inode->data_vdi_id[info->idx], info->idx);
+ return 1;
+ }
+ break;
+ case SD_RES_NO_OBJ:
+ break;
+ case SD_RES_OLD_NODE_VER:
+ case SD_RES_NEW_NODE_VER:
+ sd_err("The node list has changed: please try again");
+ break;
+ default:
+ sd_err("%s: hit an unexpected error (%s)", sheep,
+ sd_strerror(rsp->result));
+ break;
+ }
+
+ return 0;
+}
+
+static void parse_objs(uint64_t oid, obj_parser_func_t func, void *data, unsigned size)
+{
+ int i, ret, cb_ret;
+ char *buf;
+
+ buf = xzalloc(size);
+ for (i = 0; i < sd_nodes_nr; i++) {
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+
+ sd_init_req(&hdr, SD_OP_READ_PEER);
+ hdr.data_length = size;
+ hdr.flags = 0;
+ hdr.epoch = sd_epoch;
+
+ hdr.obj.oid = oid;
+
+ ret = dog_exec_req(sd_nodes[i].nid.addr,
+ sd_nodes[i].nid.port, &hdr, buf);
+ if (ret < 0)
+ continue;
+
+ untrim_zero_blocks(buf, rsp->obj.offset, rsp->data_length,
+ size);
+
+ cb_ret = func(addr_to_str(sd_nodes[i].nid.addr,
+ sd_nodes[i].nid.port),
+ oid, rsp, buf, data);
+ if (cb_ret)
+ break;
+ }
+
+ free(buf);
+}
+
+
+static int vdi_list(int argc, char **argv)
+{
+ const char *vdiname = argv[optind];
+
+ if (!raw_output)
+ printf(" Name Id Size Used Shared Creation time VDI id Copies Tag\n");
+
+ if (vdiname) {
+ struct get_vdi_info info;
+ memset(&info, 0, sizeof(info));
+ info.name = vdiname;
+ if (parse_vdi(print_vdi_list, SD_INODE_SIZE, &info) < 0)
+ return EXIT_SYSFAIL;
+ return EXIT_SUCCESS;
+ } else {
+ if (parse_vdi(print_vdi_list, SD_INODE_SIZE, NULL) < 0)
+ return EXIT_SYSFAIL;
+ return EXIT_SUCCESS;
+ }
+}
+
+static int vdi_tree(int argc, char **argv)
+{
+ init_tree();
+ if (parse_vdi(print_vdi_tree, SD_INODE_HEADER_SIZE, NULL) < 0)
+ return EXIT_SYSFAIL;
+ dump_tree();
+
+ return EXIT_SUCCESS;
+}
+
+static int vdi_graph(int argc, char **argv)
+{
+ /* print a header */
+ printf("digraph G {\n");
+ printf(" node [shape = \"box\", fontname = \"Courier\"];\n\n");
+ printf(" \"0\" [shape = \"ellipse\", label = \"root\"];\n\n");
+
+ if (parse_vdi(print_vdi_graph, SD_INODE_HEADER_SIZE, NULL) < 0)
+ return EXIT_SYSFAIL;
+
+ /* print a footer */
+ printf("}\n");
+
+ return EXIT_SUCCESS;
+}
+
+static int find_vdi_name(const char *vdiname, uint32_t snapid, const char *tag,
+ uint32_t *vid, int for_snapshot)
+{
+ int ret;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
+
+ memset(buf, 0, sizeof(buf));
+ pstrcpy(buf, SD_MAX_VDI_LEN, vdiname);
+ if (tag)
+ pstrcpy(buf + SD_MAX_VDI_LEN, SD_MAX_VDI_TAG_LEN, tag);
+
+ if (for_snapshot)
+ sd_init_req(&hdr, SD_OP_GET_VDI_INFO);
+ else
+ sd_init_req(&hdr, SD_OP_LOCK_VDI);
+ hdr.data_length = SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN;
+ hdr.flags = SD_FLAG_CMD_WRITE;
+ hdr.vdi.snapid = snapid;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, buf);
+ if (ret < 0)
+ return -1;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("Cannot get VDI info for %s %d %s: %s", vdiname, snapid,
+ tag, sd_strerror(rsp->result));
+ return -1;
+ }
+ *vid = rsp->vdi.vdi_id;
+
+ return 0;
+}
+
+static int read_vdi_obj(const char *vdiname, int snapid, const char *tag,
+ uint32_t *pvid, struct sd_inode *inode,
+ size_t size)
+{
+ int ret;
+ uint32_t vid;
+
+ ret = find_vdi_name(vdiname, snapid, tag, &vid, 0);
+ if (ret < 0) {
+ sd_err("Failed to open VDI %s", vdiname);
+ return EXIT_FAILURE;
+ }
+
+ ret = sd_read_object(vid_to_vdi_oid(vid), inode, size, 0, true);
+ if (ret != SD_RES_SUCCESS) {
+ if (snapid) {
+ sd_err("Failed to read a snapshot %s:%d", vdiname,
+ snapid);
+ } else if (tag && tag[0]) {
+ sd_err("Failed to read a snapshot %s:%s", vdiname, tag);
+ } else {
+ sd_err("Failed to read a vdi %s", vdiname);
+ }
+ return EXIT_FAILURE;
+ }
+
+ if (pvid)
+ *pvid = vid;
+
+ return EXIT_SUCCESS;
+}
+
+int do_vdi_create(const char *vdiname, int64_t vdi_size,
+ uint32_t base_vid, uint32_t *vdi_id, bool snapshot,
+ int nr_copies)
+{
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ int ret;
+ char buf[SD_MAX_VDI_LEN];
+
+ memset(buf, 0, sizeof(buf));
+ pstrcpy(buf, SD_MAX_VDI_LEN, vdiname);
+
+ sd_init_req(&hdr, SD_OP_NEW_VDI);
+ hdr.flags = SD_FLAG_CMD_WRITE;
+ hdr.data_length = SD_MAX_VDI_LEN;
+
+ hdr.vdi.base_vdi_id = base_vid;
+ hdr.vdi.snapid = snapshot ? 1 : 0;
+ hdr.vdi.vdi_size = vdi_size;
+ hdr.vdi.copies = nr_copies;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, buf);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("Failed to create VDI %s: %s", vdiname,
+ sd_strerror(rsp->result));
+ return EXIT_FAILURE;
+ }
+
+ if (vdi_id)
+ *vdi_id = rsp->vdi.vdi_id;
+
+ return EXIT_SUCCESS;
+}
+
+static int vdi_create(int argc, char **argv)
+{
+ const char *vdiname = argv[optind++];
+ uint64_t size;
+ uint32_t vid;
+ uint64_t oid;
+ int idx, max_idx, ret, nr_copies = vdi_cmd_data.nr_copies;
+ struct sd_inode *inode = NULL;
+
+ if (!argv[optind]) {
+ sd_err("Please specify the VDI size");
+ return EXIT_USAGE;
+ }
+ ret = parse_option_size(argv[optind], &size);
+ if (ret < 0)
+ return EXIT_USAGE;
+ if (size > SD_MAX_VDI_SIZE) {
+ sd_err("VDI size is too large");
+ return EXIT_USAGE;
+ }
+
+ if (nr_copies > sd_nodes_nr) {
+ sd_err("There are not enough nodes(%d) to hold the copies(%d)",
+ sd_nodes_nr, nr_copies);
+ return EXIT_USAGE;
+ }
+
+ ret = do_vdi_create(vdiname, size, 0, &vid, false,
+ vdi_cmd_data.nr_copies);
+ if (ret != EXIT_SUCCESS || !vdi_cmd_data.prealloc)
+ goto out;
+
+ inode = xmalloc(sizeof(*inode));
+
+ ret = sd_read_object(vid_to_vdi_oid(vid), inode, sizeof(*inode), 0, true);
+ if (ret != SD_RES_SUCCESS) {
+ sd_err("Failed to read a newly created VDI object");
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ max_idx = DIV_ROUND_UP(size, SD_DATA_OBJ_SIZE);
+
+ for (idx = 0; idx < max_idx; idx++) {
+ vdi_show_progress(idx * SD_DATA_OBJ_SIZE, inode->vdi_size);
+ oid = vid_to_data_oid(vid, idx);
+
+ ret = sd_write_object(oid, 0, NULL, 0, 0, 0, inode->nr_copies,
+ true, true);
+ if (ret != SD_RES_SUCCESS) {
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ inode->data_vdi_id[idx] = vid;
+ ret = sd_write_object(vid_to_vdi_oid(vid), 0, &vid, sizeof(vid),
+ SD_INODE_HEADER_SIZE + sizeof(vid) * idx, 0,
+ inode->nr_copies, false, true);
+ if (ret) {
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ }
+ vdi_show_progress(idx * SD_DATA_OBJ_SIZE, inode->vdi_size);
+ ret = EXIT_SUCCESS;
+
+ if (verbose) {
+ if (raw_output)
+ printf("%x\n", vid);
+ else
+ printf("VDI ID of newly created VDI: %x\n", vid);
+ }
+
+out:
+ free(inode);
+ return ret;
+}
+
+static int vdi_snapshot(int argc, char **argv)
+{
+ const char *vdiname = argv[optind++];
+ uint32_t vid;
+ int ret;
+ char buf[SD_INODE_HEADER_SIZE];
+ struct sd_inode *inode = (struct sd_inode *)buf;
+
+ if (vdi_cmd_data.snapshot_id != 0) {
+ sd_err("Please specify a non-integer value for "
+ "a snapshot tag name");
+ return EXIT_USAGE;
+ }
+
+ ret = read_vdi_obj(vdiname, 0, "", &vid, inode, SD_INODE_HEADER_SIZE);
+ if (ret != EXIT_SUCCESS)
+ return ret;
+
+ ret = sd_write_object(vid_to_vdi_oid(vid), 0, vdi_cmd_data.snapshot_tag,
+ SD_MAX_VDI_TAG_LEN,
+ offsetof(struct sd_inode, tag),
+ 0, inode->nr_copies, false, false);
+ if (ret != SD_RES_SUCCESS)
+ return EXIT_FAILURE;
+
+ ret = do_vdi_create(vdiname, inode->vdi_size, vid, NULL, true,
+ inode->nr_copies);
+
+ if (ret == EXIT_SUCCESS && verbose) {
+ if (raw_output)
+ printf("%x\n", vid);
+ else
+ printf("VDI ID of newly created snapshot: %x\n", vid);
+ }
+
+ return ret;
+}
+
+static int vdi_clone(int argc, char **argv)
+{
+ const char *src_vdi = argv[optind++], *dst_vdi;
+ uint32_t base_vid, new_vid;
+ uint64_t oid;
+ int idx, max_idx, ret;
+ struct sd_inode *inode = NULL;
+ char *buf = NULL;
+
+ dst_vdi = argv[optind];
+ if (!dst_vdi) {
+ sd_err("Destination VDI name must be specified");
+ ret = EXIT_USAGE;
+ goto out;
+ }
+
+ if (!vdi_cmd_data.snapshot_id && !vdi_cmd_data.snapshot_tag[0]) {
+ sd_err("Only snapshot VDIs can be cloned");
+ sd_err("Please specify the '-s' option");
+ ret = EXIT_USAGE;
+ goto out;
+ }
+
+ inode = xmalloc(sizeof(*inode));
+
+ ret = read_vdi_obj(src_vdi, vdi_cmd_data.snapshot_id,
+ vdi_cmd_data.snapshot_tag, &base_vid, inode,
+ SD_INODE_SIZE);
+ if (ret != EXIT_SUCCESS)
+ goto out;
+
+ ret = do_vdi_create(dst_vdi, inode->vdi_size, base_vid, &new_vid, false,
+ vdi_cmd_data.nr_copies);
+ if (ret != EXIT_SUCCESS || !vdi_cmd_data.prealloc)
+ goto out;
+
+ buf = xzalloc(SD_DATA_OBJ_SIZE);
+ max_idx = DIV_ROUND_UP(inode->vdi_size, SD_DATA_OBJ_SIZE);
+
+ for (idx = 0; idx < max_idx; idx++) {
+ vdi_show_progress(idx * SD_DATA_OBJ_SIZE, inode->vdi_size);
+ if (inode->data_vdi_id[idx]) {
+ oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
+ ret = sd_read_object(oid, buf, SD_DATA_OBJ_SIZE, 0, true);
+ if (ret) {
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ } else
+ memset(buf, 0, SD_DATA_OBJ_SIZE);
+
+ oid = vid_to_data_oid(new_vid, idx);
+ ret = sd_write_object(oid, 0, buf, SD_DATA_OBJ_SIZE, 0, 0,
+ inode->nr_copies, true, true);
+ if (ret != SD_RES_SUCCESS) {
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ ret = sd_write_object(vid_to_vdi_oid(new_vid), 0, &new_vid, sizeof(new_vid),
+ SD_INODE_HEADER_SIZE + sizeof(new_vid) * idx, 0,
+ inode->nr_copies, false, true);
+ if (ret) {
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ }
+ vdi_show_progress(idx * SD_DATA_OBJ_SIZE, inode->vdi_size);
+ ret = EXIT_SUCCESS;
+
+ if (verbose) {
+ if (raw_output)
+ printf("%x\n", new_vid);
+ else
+ printf("VDI ID of newly created clone: %x\n", new_vid);
+ }
+out:
+ free(inode);
+ free(buf);
+ return ret;
+}
+
+static int vdi_resize(int argc, char **argv)
+{
+ const char *vdiname = argv[optind++];
+ uint64_t new_size;
+ uint32_t vid;
+ int ret;
+ char buf[SD_INODE_HEADER_SIZE];
+ struct sd_inode *inode = (struct sd_inode *)buf;
+
+ if (!argv[optind]) {
+ sd_err("Please specify the new size for the VDI");
+ return EXIT_USAGE;
+ }
+ ret = parse_option_size(argv[optind], &new_size);
+ if (ret < 0)
+ return EXIT_USAGE;
+ if (new_size > SD_MAX_VDI_SIZE) {
+ sd_err("New VDI size is too large");
+ return EXIT_USAGE;
+ }
+
+ ret = read_vdi_obj(vdiname, 0, "", &vid, inode, SD_INODE_HEADER_SIZE);
+ if (ret != EXIT_SUCCESS)
+ return ret;
+
+ if (new_size < inode->vdi_size) {
+ sd_err("Shrinking VDIs is not implemented");
+ return EXIT_USAGE;
+ }
+ inode->vdi_size = new_size;
+
+ ret = sd_write_object(vid_to_vdi_oid(vid), 0, inode, SD_INODE_HEADER_SIZE, 0,
+ 0, inode->nr_copies, false, true);
+ if (ret != SD_RES_SUCCESS) {
+ sd_err("Failed to update an inode header");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int do_vdi_delete(const char *vdiname, int snap_id, const char *snap_tag)
+{
+ int ret;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ char data[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN];
+ uint32_t vid;
+
+ ret = find_vdi_name(vdiname, snap_id, snap_tag, &vid, 0);
+ if (ret < 0) {
+ sd_err("Failed to open VDI %s", vdiname);
+ return EXIT_FAILURE;
+ }
+
+ sd_init_req(&hdr, SD_OP_DELETE_CACHE);
+ hdr.obj.oid = vid_to_vdi_oid(vid);
+
+ ret = send_light_req(&hdr, sdhost, sdport);
+ if (ret) {
+ sd_err("failed to execute request");
+ return EXIT_FAILURE;
+ }
+
+ sd_init_req(&hdr, SD_OP_DEL_VDI);
+ hdr.flags = SD_FLAG_CMD_WRITE;
+ hdr.data_length = sizeof(data);
+ hdr.vdi.snapid = snap_id;
+ memset(data, 0, sizeof(data));
+ pstrcpy(data, SD_MAX_VDI_LEN, vdiname);
+ if (snap_tag)
+ pstrcpy(data + SD_MAX_VDI_LEN, SD_MAX_VDI_TAG_LEN, snap_tag);
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, data);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("Failed to delete %s: %s", vdiname,
+ sd_strerror(rsp->result));
+ if (rsp->result == SD_RES_NO_VDI)
+ return EXIT_MISSING;
+ else
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int vdi_delete(int argc, char **argv)
+{
+ char *vdiname = argv[optind];
+
+ return do_vdi_delete(vdiname, vdi_cmd_data.snapshot_id,
+ vdi_cmd_data.snapshot_tag);
+}
+
+static int vdi_rollback(int argc, char **argv)
+{
+ const char *vdiname = argv[optind++];
+ uint32_t base_vid, new_vid;
+ int ret;
+ char buf[SD_INODE_HEADER_SIZE];
+ struct sd_inode *inode = (struct sd_inode *)buf;
+
+ if (!vdi_cmd_data.snapshot_id && !vdi_cmd_data.snapshot_tag[0]) {
+ sd_err("Please specify the '-s' option");
+ return EXIT_USAGE;
+ }
+
+ ret = read_vdi_obj(vdiname, vdi_cmd_data.snapshot_id,
+ vdi_cmd_data.snapshot_tag, &base_vid, inode,
+ SD_INODE_HEADER_SIZE);
+ if (ret != EXIT_SUCCESS)
+ return ret;
+
+ if (!vdi_cmd_data.force)
+ confirm("This operation dicards any changes made since the"
+ " previous\nsnapshot was taken. Continue? [yes/no]: ");
+
+ ret = do_vdi_delete(vdiname, 0, NULL);
+ if (ret != SD_RES_SUCCESS) {
+ sd_err("Failed to delete the current state");
+ return EXIT_FAILURE;
+ }
+
+ ret = do_vdi_create(vdiname, inode->vdi_size, base_vid, &new_vid,
+ false, vdi_cmd_data.nr_copies);
+
+ if (ret == EXIT_SUCCESS && verbose) {
+ if (raw_output)
+ printf("%x\n", new_vid);
+ else
+ printf("New VDI ID of rollbacked VDI: %x\n", new_vid);
+ }
+
+ return ret;
+}
+
+static int vdi_object(int argc, char **argv)
+{
+ const char *vdiname = argv[optind];
+ unsigned idx = vdi_cmd_data.index;
+ struct get_vdi_info info;
+ uint32_t vid;
+
+ memset(&info, 0, sizeof(info));
+ info.name = vdiname;
+ info.tag = vdi_cmd_data.snapshot_tag;
+ info.vid = 0;
+ info.snapid = vdi_cmd_data.snapshot_id;
+
+ if (parse_vdi(get_oid, SD_INODE_HEADER_SIZE, &info) < 0)
+ return EXIT_SYSFAIL;
+
+ vid = info.vid;
+ if (vid == 0) {
+ sd_err("VDI not found");
+ return EXIT_MISSING;
+ }
+
+ if (idx == ~0) {
+ printf("Looking for the inode object 0x%" PRIx32 " with %d nodes\n\n",
+ vid, sd_nodes_nr);
+ parse_objs(vid_to_vdi_oid(vid), do_print_obj, NULL, SD_INODE_SIZE);
+ } else {
+ struct get_data_oid_info oid_info = {0};
+
+ oid_info.success = false;
+ oid_info.idx = idx;
+
+ if (idx >= MAX_DATA_OBJS) {
+ printf("The offset is too large!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ parse_objs(vid_to_vdi_oid(vid), get_data_oid, &oid_info, SD_DATA_OBJ_SIZE);
+
+ if (oid_info.success) {
+ if (oid_info.data_oid) {
+ printf("Looking for the object 0x%" PRIx64
+ " (the inode vid 0x%" PRIx32 " idx %u) with %d nodes\n\n",
+ oid_info.data_oid, vid, idx, sd_nodes_nr);
+
+ parse_objs(oid_info.data_oid, do_print_obj, NULL, SD_DATA_OBJ_SIZE);
+ } else
+ printf("The inode object 0x%" PRIx32 " idx %u is not allocated\n",
+ vid, idx);
+ } else
+ sd_err("Failed to read the inode object 0x%" PRIx32,
+ vid);
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int do_track_object(uint64_t oid, uint8_t nr_copies)
+{
+ int i, j, ret;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ struct sd_vnode *vnodes;
+ const struct sd_vnode *vnode_buf[SD_MAX_COPIES];
+ struct epoch_log *logs;
+ int vnodes_nr, nr_logs, log_length;
+
+ log_length = sd_epoch * sizeof(struct epoch_log);
+ logs = xmalloc(log_length);
+ vnodes = xmalloc(sizeof(*vnodes) * SD_MAX_VNODES);
+
+ sd_init_req(&hdr, SD_OP_STAT_CLUSTER);
+ hdr.data_length = log_length;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, logs);
+ if (ret < 0)
+ goto error;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ printf("%s\n", sd_strerror(rsp->result));
+ goto error;
+ }
+
+ nr_logs = rsp->data_length / sizeof(struct epoch_log);
+ for (i = nr_logs - 1; i >= 0; i--) {
+ printf("\nobj %"PRIx64" locations at epoch %d, copies = %d\n",
+ oid, logs[i].epoch, nr_copies);
+ printf("---------------------------------------------------\n");
+
+ /*
+ * When # of nodes is less than nr_copies, we only print
+ * remaining nodes that holds all the remaining copies.
+ */
+ if (logs[i].nr_nodes < nr_copies) {
+ for (j = 0; j < logs[i].nr_nodes; j++) {
+ const struct node_id *n = &logs[i].nodes[j].nid;
+
+ printf("%s\n", addr_to_str(n->addr, n->port));
+ }
+ continue;
+ }
+ vnodes_nr = nodes_to_vnodes(logs[i].nodes,
+ logs[i].nr_nodes, vnodes);
+ oid_to_vnodes(vnodes, vnodes_nr, oid, nr_copies, vnode_buf);
+ for (j = 0; j < nr_copies; j++) {
+ const struct node_id *n = &vnode_buf[j]->nid;
+
+ printf("%s\n", addr_to_str(n->addr, n->port));
+ }
+ }
+
+ free(logs);
+ free(vnodes);
+ return EXIT_SUCCESS;
+error:
+ free(logs);
+ free(vnodes);
+ return EXIT_SYSFAIL;
+}
+
+static int vdi_track(int argc, char **argv)
+{
+ const char *vdiname = argv[optind];
+ unsigned idx = vdi_cmd_data.index;
+ struct get_vdi_info info;
+ struct get_data_oid_info oid_info = {0};
+ uint32_t vid;
+ uint8_t nr_copies;
+
+ memset(&info, 0, sizeof(info));
+ info.name = vdiname;
+ info.tag = vdi_cmd_data.snapshot_tag;
+ info.vid = 0;
+ info.snapid = vdi_cmd_data.snapshot_id;
+
+ if (parse_vdi(get_oid, SD_INODE_HEADER_SIZE, &info) < 0)
+ return EXIT_SYSFAIL;
+
+ vid = info.vid;
+ nr_copies = info.nr_copies;
+ if (vid == 0) {
+ sd_err("VDI not found");
+ return EXIT_MISSING;
+ }
+
+ if (idx == ~0) {
+ printf("Tracking the inode object 0x%" PRIx32 " with %d nodes\n",
+ vid, sd_nodes_nr);
+ return do_track_object(vid_to_vdi_oid(vid), nr_copies);
+ }
+
+ oid_info.success = false;
+ oid_info.idx = idx;
+
+ if (idx >= MAX_DATA_OBJS) {
+ printf("The offset is too large!\n");
+ goto err;
+ }
+
+ parse_objs(vid_to_vdi_oid(vid), get_data_oid,
+ &oid_info, SD_DATA_OBJ_SIZE);
+
+ if (!oid_info.success) {
+ sd_err("Failed to read the inode object 0x%" PRIx32, vid);
+ goto err;
+ }
+ if (!oid_info.data_oid) {
+ printf("The inode object 0x%"PRIx32" idx %u is not allocated\n",
+ vid, idx);
+ goto err;
+ }
+ printf("Tracking the object 0x%" PRIx64
+ " (the inode vid 0x%" PRIx32 " idx %u)"
+ " with %d nodes\n",
+ oid_info.data_oid, vid, idx, sd_nodes_nr);
+ return do_track_object(oid_info.data_oid, nr_copies);
+err:
+ return EXIT_FAILURE;
+}
+
+static int find_vdi_attr_oid(const char *vdiname, const char *tag, uint32_t snapid,
+ const char *key, void *value, unsigned int value_len,
+ uint32_t *vid, uint64_t *oid, unsigned int *nr_copies,
+ bool create, bool excl, bool delete)
+{
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ int ret;
+ struct sheepdog_vdi_attr vattr;
+
+ memset(&vattr, 0, sizeof(vattr));
+ pstrcpy(vattr.name, SD_MAX_VDI_LEN, vdiname);
+ pstrcpy(vattr.tag, SD_MAX_VDI_TAG_LEN, vdi_cmd_data.snapshot_tag);
+ vattr.snap_id = vdi_cmd_data.snapshot_id;
+ pstrcpy(vattr.key, SD_MAX_VDI_ATTR_KEY_LEN, key);
+ if (value && value_len) {
+ vattr.value_len = value_len;
+ memcpy(vattr.value, value, value_len);
+ }
+
+ sd_init_req(&hdr, SD_OP_GET_VDI_ATTR);
+ hdr.flags = SD_FLAG_CMD_WRITE;
+ hdr.data_length = SD_ATTR_OBJ_SIZE;
+ hdr.vdi.snapid = vdi_cmd_data.snapshot_id;
+
+ if (create)
+ hdr.flags |= SD_FLAG_CMD_CREAT;
+ if (excl)
+ hdr.flags |= SD_FLAG_CMD_EXCL;
+ if (delete)
+ hdr.flags |= SD_FLAG_CMD_DEL;
+
+ ret = dog_exec_req(sdhost, sdport, &hdr, &vattr);
+ if (ret < 0)
+ return SD_RES_EIO;
+
+ if (rsp->result != SD_RES_SUCCESS)
+ return rsp->result;
+
+ *vid = rsp->vdi.vdi_id;
+ *oid = vid_to_attr_oid(rsp->vdi.vdi_id, rsp->vdi.attr_id);
+ *nr_copies = rsp->vdi.copies;
+
+ return SD_RES_SUCCESS;
+}
+
+static int vdi_setattr(int argc, char **argv)
+{
+ int ret, value_len = 0;
+ uint64_t attr_oid = 0;
+ uint32_t vid = 0, nr_copies = 0;
+ const char *vdiname = argv[optind++], *key;
+ char *value;
+ uint64_t offset;
+
+ key = argv[optind++];
+ if (!key) {
+ sd_err("Please specify the attribute key");
+ return EXIT_USAGE;
+ }
+
+ value = argv[optind++];
+ if (!value && !vdi_cmd_data.delete) {
+ value = xmalloc(SD_MAX_VDI_ATTR_VALUE_LEN);
+
+ offset = 0;
+reread:
+ ret = read(STDIN_FILENO, value + offset,
+ SD_MAX_VDI_ATTR_VALUE_LEN - offset);
+ if (ret < 0) {
+ sd_err("Failed to read attribute value from stdin: %m");
+ return EXIT_SYSFAIL;
+ }
+ if (ret > 0) {
+ offset += ret;
+ goto reread;
+ }
+ }
+
+ if (value)
+ value_len = strlen(value);
+
+ ret = find_vdi_attr_oid(vdiname, vdi_cmd_data.snapshot_tag,
+ vdi_cmd_data.snapshot_id, key, value,
+ value_len, &vid, &attr_oid,
+ &nr_copies, !vdi_cmd_data.delete,
+ vdi_cmd_data.exclusive, vdi_cmd_data.delete);
+ if (ret) {
+ if (ret == SD_RES_VDI_EXIST) {
+ sd_err("The attribute '%s' already exists", key);
+ return EXIT_EXISTS;
+ } else if (ret == SD_RES_NO_OBJ) {
+ sd_err("Attribute '%s' not found", key);
+ return EXIT_MISSING;
+ } else if (ret == SD_RES_NO_VDI) {
+ sd_err("VDI not found");
+ return EXIT_MISSING;
+ } else
+ sd_err("Failed to set attribute: %s", sd_strerror(ret));
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int vdi_getattr(int argc, char **argv)
+{
+ int ret;
+ uint64_t oid, attr_oid = 0;
+ uint32_t vid = 0, nr_copies = 0;
+ const char *vdiname = argv[optind++], *key;
+ struct sheepdog_vdi_attr vattr;
+
+ key = argv[optind++];
+ if (!key) {
+ sd_err("Please specify the attribute key");
+ return EXIT_USAGE;
+ }
+
+ ret = find_vdi_attr_oid(vdiname, vdi_cmd_data.snapshot_tag,
+ vdi_cmd_data.snapshot_id, key, NULL, 0, &vid,
+ &attr_oid, &nr_copies, false, false, false);
+ if (ret == SD_RES_NO_OBJ) {
+ sd_err("Attribute '%s' not found", key);
+ return EXIT_MISSING;
+ } else if (ret == SD_RES_NO_VDI) {
+ sd_err("VDI not found");
+ return EXIT_MISSING;
+ } else if (ret) {
+ sd_err("Failed to find attribute oid: %s", sd_strerror(ret));
+ return EXIT_MISSING;
+ }
+
+ oid = attr_oid;
+
+ ret = sd_read_object(oid, &vattr, SD_ATTR_OBJ_SIZE, 0, true);
+ if (ret != SD_RES_SUCCESS) {
+ sd_err("Failed to read attribute oid: %s", sd_strerror(ret));
+ return EXIT_SYSFAIL;
+ }
+
+ xwrite(STDOUT_FILENO, vattr.value, vattr.value_len);
+ return EXIT_SUCCESS;
+}
+
+static int vdi_read(int argc, char **argv)
+{
+ const char *vdiname = argv[optind++];
+ int ret, idx;
+ struct sd_inode *inode = NULL;
+ uint64_t offset = 0, oid, done = 0, total = (uint64_t) -1;
+ unsigned int len;
+ char *buf = NULL;
+
+ if (argv[optind]) {
+ ret = parse_option_size(argv[optind++], &offset);
+ if (ret < 0)
+ return EXIT_USAGE;
+ if (argv[optind]) {
+ ret = parse_option_size(argv[optind++], &total);
+ if (ret < 0)
+ return EXIT_USAGE;
+ }
+ }
+
+ inode = malloc(sizeof(*inode));
+ buf = xmalloc(SD_DATA_OBJ_SIZE);
+
+ ret = read_vdi_obj(vdiname, vdi_cmd_data.snapshot_id,
+ vdi_cmd_data.snapshot_tag, NULL, inode,
+ SD_INODE_SIZE);
+ if (ret != EXIT_SUCCESS)
+ goto out;
+
+ if (inode->vdi_size < offset) {
+ sd_err("Read offset is beyond the end of the VDI");
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ total = min(total, inode->vdi_size - offset);
+ idx = offset / SD_DATA_OBJ_SIZE;
+ offset %= SD_DATA_OBJ_SIZE;
+ while (done < total) {
+ len = min(total - done, SD_DATA_OBJ_SIZE - offset);
+
+ if (inode->data_vdi_id[idx]) {
+ oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
+ ret = sd_read_object(oid, buf, len, offset, false);
+ if (ret != SD_RES_SUCCESS) {
+ sd_err("Failed to read VDI");
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ } else
+ memset(buf, 0, len);
+
+ ret = xwrite(STDOUT_FILENO, buf, len);
+ if (ret < 0) {
+ sd_err("Failed to write to stdout: %m");
+ ret = EXIT_SYSFAIL;
+ goto out;
+ }
+
+ offset = 0;
+ idx++;
+ done += len;
+ }
+ fsync(STDOUT_FILENO);
+ ret = EXIT_SUCCESS;
+out:
+ free(inode);
+ free(buf);
+
+ return ret;
+}
+
+static int vdi_write(int argc, char **argv)
+{
+ const char *vdiname = argv[optind++];
+ uint32_t vid, flags;
+ int ret, idx;
+ struct sd_inode *inode = NULL;
+ uint64_t offset = 0, oid, old_oid, done = 0, total = (uint64_t) -1;
+ unsigned int len;
+ char *buf = NULL;
+ bool create;
+
+ if (argv[optind]) {
+ ret = parse_option_size(argv[optind++], &offset);
+ if (ret < 0)
+ return EXIT_USAGE;
+ if (argv[optind]) {
+ ret = parse_option_size(argv[optind++], &total);
+ if (ret < 0)
+ return EXIT_USAGE;
+ }
+ }
+
+ inode = xmalloc(sizeof(*inode));
+ buf = xmalloc(SD_DATA_OBJ_SIZE);
+
+ ret = read_vdi_obj(vdiname, 0, "", &vid, inode, SD_INODE_SIZE);
+ if (ret != EXIT_SUCCESS)
+ goto out;
+
+ if (inode->vdi_size < offset) {
+ sd_err("Write offset is beyond the end of the VDI");
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ total = min(total, inode->vdi_size - offset);
+ idx = offset / SD_DATA_OBJ_SIZE;
+ offset %= SD_DATA_OBJ_SIZE;
+ while (done < total) {
+ create = false;
+ old_oid = 0;
+ flags = 0;
+ len = min(total - done, SD_DATA_OBJ_SIZE - offset);
+
+ if (!inode->data_vdi_id[idx])
+ create = true;
+ else if (!is_data_obj_writeable(inode, idx)) {
+ create = true;
+ old_oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
+ }
+
+ if (vdi_cmd_data.writeback)
+ flags |= SD_FLAG_CMD_CACHE;
+
+ ret = xread(STDIN_FILENO, buf, len);
+ if (ret < 0) {
+ sd_err("Failed to read from stdin: %m");
+ ret = EXIT_SYSFAIL;
+ goto out;
+ } else if (ret < len) {
+ /* exit after this buffer is sent */
+ memset(buf + ret, 0, len - ret);
+ total = done + len;
+ }
+
+ inode->data_vdi_id[idx] = inode->vdi_id;
+ oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
+ ret = sd_write_object(oid, old_oid, buf, len, offset, flags,
+ inode->nr_copies, create, false);
+ if (ret != SD_RES_SUCCESS) {
+ sd_err("Failed to write VDI");
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ if (create) {
+ ret = sd_write_object(vid_to_vdi_oid(vid), 0, &vid, sizeof(vid),
+ SD_INODE_HEADER_SIZE + sizeof(vid) * idx,
+ flags, inode->nr_copies, false, false);
+ if (ret) {
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ }
+
+ offset += len;
+ if (offset == SD_DATA_OBJ_SIZE) {
+ offset = 0;
+ idx++;
+ }
+ done += len;
+ }
+ ret = EXIT_SUCCESS;
+out:
+ free(inode);
+ free(buf);
+
+ return ret;
+}
+
+static void *read_object_from(const struct sd_vnode *vnode, uint64_t oid)
+{
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ int ret;
+ void *buf;
+ size_t size = get_objsize(oid);
+
+ buf = xmalloc(size);
+
+ sd_init_req(&hdr, SD_OP_READ_PEER);
+ hdr.epoch = sd_epoch;
+ hdr.flags = 0;
+ hdr.data_length = size;
+
+ hdr.obj.oid = oid;
+
+ ret = dog_exec_req(vnode->nid.addr, vnode->nid.port, &hdr, buf);
+
+ if (ret < 0)
+ exit(EXIT_SYSFAIL);
+
+ switch (rsp->result) {
+ case SD_RES_SUCCESS:
+ untrim_zero_blocks(buf, rsp->obj.offset, rsp->data_length,
+ size);
+ break;
+ case SD_RES_NO_OBJ:
+ free(buf);
+ return NULL;
+ default:
+ sd_err("FATAL: failed to read %"PRIx64", %s", oid,
+ sd_strerror(rsp->result));
+ exit(EXIT_FAILURE);
+ }
+ return buf;
+}
+
+static void write_object_to(const struct sd_vnode *vnode, uint64_t oid,
+ void *buf, bool create)
+{
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ int ret;
+
+ if (create)
+ sd_init_req(&hdr, SD_OP_CREATE_AND_WRITE_PEER);
+ else
+ sd_init_req(&hdr, SD_OP_WRITE_PEER);
+ hdr.epoch = sd_epoch;
+ hdr.flags = SD_FLAG_CMD_WRITE;
+ hdr.data_length = get_objsize(oid);
+ hdr.obj.oid = oid;
+
+ ret = dog_exec_req(vnode->nid.addr, vnode->nid.port, &hdr, buf);
+
+ if (ret < 0)
+ exit(EXIT_SYSFAIL);
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("FATAL: failed to write %"PRIx64", %s", oid,
+ sd_strerror(rsp->result));
+ exit(EXIT_FAILURE);
+ }
+}
+
+struct vdi_check_work {
+ struct vdi_check_info *info;
+ const struct sd_vnode *vnode;
+ uint8_t hash[SHA1_DIGEST_SIZE];
+ bool object_found;
+ struct work work;
+};
+
+struct vdi_check_info {
+ uint64_t oid;
+ int nr_copies;
+ uint64_t total;
+ uint64_t *done;
+ int refcnt;
+ struct work_queue *wq;
+ struct vdi_check_work *base;
+ struct vdi_check_work vcw[0];
+};
+
+static void free_vdi_check_info(struct vdi_check_info *info)
+{
+ if (info->done) {
+ *info->done += SD_DATA_OBJ_SIZE;
+ vdi_show_progress(*info->done, info->total);
+ }
+ free(info);
+}
+
+static void vdi_repair_work(struct work *work)
+{
+ struct vdi_check_work *vcw = container_of(work, struct vdi_check_work,
+ work);
+ struct vdi_check_info *info = vcw->info;
+ void *buf;
+
+ buf = read_object_from(info->base->vnode, info->oid);
+ write_object_to(vcw->vnode, info->oid, buf, !vcw->object_found);
+ free(buf);
+}
+
+static void vdi_repair_main(struct work *work)
+{
+ struct vdi_check_work *vcw = container_of(work, struct vdi_check_work,
+ work);
+ struct vdi_check_info *info = vcw->info;
+
+ if (vcw->object_found)
+ fprintf(stdout, "fixed replica %"PRIx64"\n", info->oid);
+ else
+ fprintf(stdout, "fixed missing %"PRIx64"\n", info->oid);
+
+ info->refcnt--;
+ if (info->refcnt == 0)
+ free_vdi_check_info(info);
+}
+
+static void vdi_hash_check_work(struct work *work)
+{
+ struct vdi_check_work *vcw = container_of(work, struct vdi_check_work,
+ work);
+ struct vdi_check_info *info = vcw->info;
+ int ret;
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+
+ sd_init_req(&hdr, SD_OP_GET_HASH);
+ hdr.obj.oid = info->oid;
+ hdr.obj.tgt_epoch = sd_epoch;
+
+ ret = dog_exec_req(vcw->vnode->nid.addr, vcw->vnode->nid.port, &hdr,
+ NULL);
+ if (ret < 0)
+ exit(EXIT_SYSFAIL);
+
+ switch (ret) {
+ case SD_RES_SUCCESS:
+ vcw->object_found = true;
+ memcpy(vcw->hash, rsp->hash.digest, sizeof(vcw->hash));
+ uatomic_set(&info->base, vcw);
+ break;
+ case SD_RES_NO_OBJ:
+ vcw->object_found = false;
+ break;
+ default:
+ sd_err("failed to read %" PRIx64 " from %s, %s", info->oid,
+ addr_to_str(vcw->vnode->nid.addr, vcw->vnode->nid.port),
+ sd_strerror(ret));
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void vdi_hash_check_main(struct work *work)
+{
+ struct vdi_check_work *vcw = container_of(work, struct vdi_check_work,
+ work);
+ struct vdi_check_info *info = vcw->info;
+
+ info->refcnt--;
+ if (info->refcnt > 0)
+ return;
+
+ if (info->base == NULL) {
+ sd_err("no node has %" PRIx64, info->oid);
+ exit(EXIT_FAILURE);
+ }
+
+ for (int i = 0; i < info->nr_copies; i++) {
+ if (&info->vcw[i] == info->base)
+ continue;
+ /* need repair when object not found or consistency broken */
+ if (!info->vcw[i].object_found ||
+ memcmp(info->base->hash, info->vcw[i].hash,
+ sizeof(info->base->hash)) != 0) {
+ info->vcw[i].work.fn = vdi_repair_work;
+ info->vcw[i].work.done = vdi_repair_main;
+ info->refcnt++;
+ queue_work(info->wq, &info->vcw[i].work);
+ }
+ }
+
+ if (info->refcnt == 0)
+ free_vdi_check_info(info);
+}
+
+static void queue_vdi_check_work(struct sd_inode *inode, uint64_t oid,
+ uint64_t *done, struct work_queue *wq)
+{
+ struct vdi_check_info *info;
+ const struct sd_vnode *tgt_vnodes[SD_MAX_COPIES];
+ int nr_copies = inode->nr_copies;
+
+ info = xzalloc(sizeof(*info) + sizeof(info->vcw[0]) * nr_copies);
+ info->oid = oid;
+ info->nr_copies = nr_copies;
+ info->total = inode->vdi_size;
+ info->done = done;
+ info->wq = wq;
+
+ oid_to_vnodes(sd_vnodes, sd_vnodes_nr, oid, nr_copies, tgt_vnodes);
+ for (int i = 0; i < nr_copies; i++) {
+ info->vcw[i].info = info;
+ info->vcw[i].vnode = tgt_vnodes[i];
+ info->vcw[i].work.fn = vdi_hash_check_work;
+ info->vcw[i].work.done = vdi_hash_check_main;
+ info->refcnt++;
+ queue_work(info->wq, &info->vcw[i].work);
+ }
+}
+
+static int vdi_check(int argc, char **argv)
+{
+ const char *vdiname = argv[optind++];
+ int ret, max_idx;
+ uint64_t done = 0, oid;
+ uint32_t vid;
+ struct sd_inode *inode = xmalloc(sizeof(*inode));
+ struct work_queue *wq;
+
+ ret = read_vdi_obj(vdiname, vdi_cmd_data.snapshot_id,
+ vdi_cmd_data.snapshot_tag, &vid, inode,
+ SD_INODE_SIZE);
+ if (ret != EXIT_SUCCESS) {
+ sd_err("FATAL: no inode objects");
+ goto out;
+ }
+ if (sd_nodes_nr < inode->nr_copies) {
+ sd_err("ABORT: Not enough active nodes for consistency-check");
+ return EXIT_FAILURE;
+ }
+
+ wq = create_work_queue("vdi check", WQ_DYNAMIC);
+
+ queue_vdi_check_work(inode, vid_to_vdi_oid(vid), NULL, wq);
+
+ max_idx = DIV_ROUND_UP(inode->vdi_size, SD_DATA_OBJ_SIZE);
+ vdi_show_progress(done, inode->vdi_size);
+ for (int idx = 0; idx < max_idx; idx++) {
+ vid = inode->data_vdi_id[idx];
+ if (vid) {
+ oid = vid_to_data_oid(vid, idx);
+ queue_vdi_check_work(inode, oid, &done, wq);
+ } else {
+ done += SD_DATA_OBJ_SIZE;
+ vdi_show_progress(done, inode->vdi_size);
+ }
+ }
+
+ work_queue_wait(wq);
+
+ fprintf(stdout, "finish check&repair %s\n", vdiname);
+ return EXIT_SUCCESS;
+out:
+ return ret;
+}
+
+/* vdi backup format */
+
+#define VDI_BACKUP_FORMAT_VERSION 1
+#define VDI_BACKUP_MAGIC 0x11921192
+
+struct backup_hdr {
+ uint32_t version;
+ uint32_t magic;
+};
+
+struct obj_backup {
+ uint32_t idx;
+ uint32_t offset;
+ uint32_t length;
+ uint32_t reserved;
+ uint8_t data[SD_DATA_OBJ_SIZE];
+};
+
+/* discards redundant area from backup data */
+static void compact_obj_backup(struct obj_backup *backup, uint8_t *from_data)
+{
+ uint8_t *p1, *p2;
+
+ p1 = backup->data;
+ p2 = from_data;
+ while (backup->length > 0 && memcmp(p1, p2, SECTOR_SIZE) == 0) {
+ p1 += SECTOR_SIZE;
+ p2 += SECTOR_SIZE;
+ backup->offset += SECTOR_SIZE;
+ backup->length -= SECTOR_SIZE;
+ }
+
+ p1 = backup->data + SD_DATA_OBJ_SIZE - SECTOR_SIZE;
+ p2 = from_data + SD_DATA_OBJ_SIZE - SECTOR_SIZE;
+ while (backup->length > 0 && memcmp(p1, p2, SECTOR_SIZE) == 0) {
+ p1 -= SECTOR_SIZE;
+ p2 -= SECTOR_SIZE;
+ backup->length -= SECTOR_SIZE;
+ }
+}
+
+static int get_obj_backup(int idx, uint32_t from_vid, uint32_t to_vid,
+ struct obj_backup *backup)
+{
+ int ret;
+ uint8_t *from_data = xzalloc(SD_DATA_OBJ_SIZE);
+
+ backup->idx = idx;
+ backup->offset = 0;
+ backup->length = SD_DATA_OBJ_SIZE;
+
+ if (to_vid) {
+ ret = sd_read_object(vid_to_data_oid(to_vid, idx), backup->data,
+ SD_DATA_OBJ_SIZE, 0, true);
+ if (ret != SD_RES_SUCCESS) {
+ sd_err("Failed to read object %" PRIx32 ", %d", to_vid,
+ idx);
+ return EXIT_FAILURE;
+ }
+ } else
+ memset(backup->data, 0, SD_DATA_OBJ_SIZE);
+
+ if (from_vid) {
+ ret = sd_read_object(vid_to_data_oid(from_vid, idx), from_data,
+ SD_DATA_OBJ_SIZE, 0, true);
+ if (ret != SD_RES_SUCCESS) {
+ sd_err("Failed to read object %" PRIx32 ", %d",
+ from_vid, idx);
+ return EXIT_FAILURE;
+ }
+ }
+
+ compact_obj_backup(backup, from_data);
+
+ free(from_data);
+
+ return EXIT_SUCCESS;
+}
+
+static int vdi_backup(int argc, char **argv)
+{
+ const char *vdiname = argv[optind++];
+ int ret = EXIT_SUCCESS, idx, nr_objs;
+ struct sd_inode *from_inode = xzalloc(sizeof(*from_inode));
+ struct sd_inode *to_inode = xzalloc(sizeof(*to_inode));
+ struct backup_hdr hdr = {
+ .version = VDI_BACKUP_FORMAT_VERSION,
+ .magic = VDI_BACKUP_MAGIC,
+ };
+ struct obj_backup *backup = xzalloc(sizeof(*backup));
+
+ if ((!vdi_cmd_data.snapshot_id && !vdi_cmd_data.snapshot_tag[0]) ||
+ (!vdi_cmd_data.from_snapshot_id &&
+ !vdi_cmd_data.from_snapshot_tag[0])) {
+ sd_err("Please specify snapshots with '-F' and '-s' options");
+ ret = EXIT_USAGE;
+ goto out;
+ }
+
+ ret = read_vdi_obj(vdiname, vdi_cmd_data.from_snapshot_id,
+ vdi_cmd_data.from_snapshot_tag, NULL,
+ from_inode, SD_INODE_SIZE);
+ if (ret != EXIT_SUCCESS)
+ goto out;
+
+ ret = read_vdi_obj(vdiname, vdi_cmd_data.snapshot_id,
+ vdi_cmd_data.snapshot_tag, NULL, to_inode,
+ SD_INODE_SIZE);
+ if (ret != EXIT_SUCCESS)
+ goto out;
+
+ nr_objs = DIV_ROUND_UP(to_inode->vdi_size, SD_DATA_OBJ_SIZE);
+
+ ret = xwrite(STDOUT_FILENO, &hdr, sizeof(hdr));
+ if (ret < 0) {
+ sd_err("failed to write backup header, %m");
+ ret = EXIT_SYSFAIL;
+ goto out;
+ }
+
+ for (idx = 0; idx < nr_objs; idx++) {
+ uint32_t from_vid = from_inode->data_vdi_id[idx];
+ uint32_t to_vid = to_inode->data_vdi_id[idx];
+
+ if (to_vid == 0 && from_vid == 0)
+ continue;
+
+ ret = get_obj_backup(idx, from_vid, to_vid, backup);
+ if (ret != EXIT_SUCCESS)
+ goto out;
+
+ if (backup->length == 0)
+ continue;
+
+ ret = xwrite(STDOUT_FILENO, backup,
+ sizeof(*backup) - sizeof(backup->data));
+ if (ret < 0) {
+ sd_err("failed to write backup data, %m");
+ ret = EXIT_SYSFAIL;
+ goto out;
+ }
+ ret = xwrite(STDOUT_FILENO, backup->data + backup->offset,
+ backup->length);
+ if (ret < 0) {
+ sd_err("failed to write backup data, %m");
+ ret = EXIT_SYSFAIL;
+ goto out;
+ }
+ }
+
+ /* write end marker */
+ memset(backup, 0, sizeof(*backup) - sizeof(backup->data));
+ backup->idx = UINT32_MAX;
+ ret = xwrite(STDOUT_FILENO, backup,
+ sizeof(*backup) - sizeof(backup->data));
+ if (ret < 0) {
+ sd_err("failed to write end marker, %m");
+ ret = EXIT_SYSFAIL;
+ goto out;
+ }
+
+ fsync(STDOUT_FILENO);
+out:
+ free(from_inode);
+ free(to_inode);
+ free(backup);
+ return ret;
+}
+
+/* restore backup data to vdi */
+static int restore_obj(struct obj_backup *backup, uint32_t vid,
+ struct sd_inode *parent_inode)
+{
+ int ret;
+ uint32_t parent_vid = parent_inode->data_vdi_id[backup->idx];
+ uint64_t parent_oid = 0;
+
+ if (parent_vid)
+ parent_oid = vid_to_data_oid(parent_vid, backup->idx);
+
+ /* send a copy-on-write request */
+ ret = sd_write_object(vid_to_data_oid(vid, backup->idx), parent_oid,
+ backup->data, backup->length, backup->offset,
+ 0, parent_inode->nr_copies, true, true);
+ if (ret != SD_RES_SUCCESS)
+ return ret;
+
+ return sd_write_object(vid_to_vdi_oid(vid), 0, &vid, sizeof(vid),
+ SD_INODE_HEADER_SIZE + sizeof(vid) * backup->idx,
+ 0, parent_inode->nr_copies, false, true);
+}
+
+static uint32_t do_restore(const char *vdiname, int snapid, const char *tag)
+{
+ int ret;
+ uint32_t vid;
+ struct backup_hdr hdr;
+ struct obj_backup *backup = xzalloc(sizeof(*backup));
+ struct sd_inode *inode = xzalloc(sizeof(*inode));
+
+ ret = xread(STDIN_FILENO, &hdr, sizeof(hdr));
+ if (ret != sizeof(hdr))
+ sd_err("failed to read backup header, %m");
+
+ if (hdr.version != VDI_BACKUP_FORMAT_VERSION ||
+ hdr.magic != VDI_BACKUP_MAGIC) {
+ sd_err("The backup file is corrupted");
+ ret = EXIT_SYSFAIL;
+ goto out;
+ }
+
+ ret = read_vdi_obj(vdiname, snapid, tag, NULL, inode, SD_INODE_SIZE);
+ if (ret != EXIT_SUCCESS)
+ goto out;
+
+ ret = do_vdi_create(vdiname, inode->vdi_size, inode->vdi_id, &vid,
+ false, inode->nr_copies);
+ if (ret != EXIT_SUCCESS) {
+ sd_err("Failed to read VDI");
+ goto out;
+ }
+
+ while (true) {
+ ret = xread(STDIN_FILENO, backup,
+ sizeof(*backup) - sizeof(backup->data));
+ if (ret != sizeof(*backup) - sizeof(backup->data)) {
+ sd_err("failed to read backup data");
+ ret = EXIT_SYSFAIL;
+ break;
+ }
+
+ if (backup->idx == UINT32_MAX) {
+ ret = EXIT_SUCCESS;
+ break;
+ }
+
+ ret = xread(STDIN_FILENO, backup->data, backup->length);
+ if (ret != backup->length) {
+ sd_err("failed to read backup data");
+ ret = EXIT_SYSFAIL;
+ break;
+ }
+
+ ret = restore_obj(backup, vid, inode);
+ if (ret != SD_RES_SUCCESS) {
+ sd_err("failed to restore backup");
+ do_vdi_delete(vdiname, 0, NULL);
+ ret = EXIT_FAILURE;
+ break;
+ }
+ }
+out:
+ free(backup);
+ free(inode);
+
+ return ret;
+}
+
+static int vdi_restore(int argc, char **argv)
+{
+ const char *vdiname = argv[optind++];
+ int ret;
+ char buf[SD_INODE_HEADER_SIZE] = {0};
+ struct sd_inode *current_inode = xzalloc(sizeof(*current_inode));
+ struct sd_inode *parent_inode = (struct sd_inode *)buf;
+ bool need_current_recovery = false;
+
+ if (!vdi_cmd_data.snapshot_id && !vdi_cmd_data.snapshot_tag[0]) {
+ sd_err("We can restore a backup file only to snapshots");
+ sd_err("Please specify the '-s' option");
+ ret = EXIT_USAGE;
+ goto out;
+ }
+
+ /*
+ * delete the current vdi temporarily first to avoid making
+ * the current state become snapshot
+ */
+ ret = read_vdi_obj(vdiname, 0, "", NULL, current_inode,
+ SD_INODE_HEADER_SIZE);
+ if (ret != EXIT_SUCCESS)
+ goto out;
+
+ ret = sd_read_object(vid_to_vdi_oid(current_inode->parent_vdi_id),
+ parent_inode, SD_INODE_HEADER_SIZE, 0, true);
+ if (ret != SD_RES_SUCCESS) {
+ printf("error\n");
+ goto out;
+ }
+
+ if (is_stdin_console()) {
+ sd_err("stdin must be pipe");
+ ret = EXIT_USAGE;
+ goto out;
+ }
+
+ ret = do_vdi_delete(vdiname, 0, NULL);
+ if (ret != EXIT_SUCCESS) {
+ sd_err("Failed to delete the current state");
+ goto out;
+ }
+ need_current_recovery = true;
+
+ /* restore backup data */
+ ret = do_restore(vdiname, vdi_cmd_data.snapshot_id,
+ vdi_cmd_data.snapshot_tag);
+out:
+ if (need_current_recovery) {
+ int recovery_ret;
+ /* recreate the current vdi object */
+ recovery_ret = do_vdi_create(vdiname, current_inode->vdi_size,
+ current_inode->parent_vdi_id, NULL,
+ true, current_inode->nr_copies);
+ if (recovery_ret != EXIT_SUCCESS) {
+ sd_err("failed to resume the current vdi");
+ ret = recovery_ret;
+ }
+ }
+ free(current_inode);
+ return ret;
+}
+
+static int vdi_cache_flush(int argc, char **argv)
+{
+ const char *vdiname = argv[optind++];
+ struct sd_req hdr;
+ uint32_t vid;
+ int ret = EXIT_SUCCESS;
+
+ ret = find_vdi_name(vdiname, vdi_cmd_data.snapshot_id,
+ vdi_cmd_data.snapshot_tag, &vid, 0);
+ if (ret < 0) {
+ sd_err("Failed to open VDI %s", vdiname);
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ sd_init_req(&hdr, SD_OP_FLUSH_VDI);
+ hdr.obj.oid = vid_to_vdi_oid(vid);
+
+ ret = send_light_req(&hdr, sdhost, sdport);
+ if (ret) {
+ sd_err("failed to execute request");
+ return EXIT_FAILURE;
+ }
+out:
+ return ret;
+}
+
+static int vdi_cache_delete(int argc, char **argv)
+{
+ const char *vdiname = argv[optind++];
+ struct sd_req hdr;
+ uint32_t vid;
+ int ret = EXIT_SUCCESS;
+
+ ret = find_vdi_name(vdiname, vdi_cmd_data.snapshot_id,
+ vdi_cmd_data.snapshot_tag, &vid, 0);
+ if (ret < 0) {
+ sd_err("Failed to open VDI %s", vdiname);
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+
+ sd_init_req(&hdr, SD_OP_DELETE_CACHE);
+ hdr.obj.oid = vid_to_vdi_oid(vid);
+
+ ret = send_light_req(&hdr, sdhost, sdport);
+ if (ret) {
+ sd_err("failed to execute request");
+ return EXIT_FAILURE;
+ }
+out:
+ return ret;
+}
+
+static int vid_to_name_tag(uint32_t vid, char *name, char *tag)
+{
+ struct sd_inode inode;
+ int ret;
+
+ ret = sd_read_object(vid_to_vdi_oid(vid), &inode, SD_INODE_HEADER_SIZE,
+ 0, true);
+ if (ret != SD_RES_SUCCESS)
+ return ret;
+
+ pstrcpy(name, SD_MAX_VDI_LEN, inode.name);
+ pstrcpy(tag, SD_MAX_VDI_TAG_LEN, inode.tag);
+
+ return SD_RES_SUCCESS;
+}
+
+static int vdi_cache_info(int argc, char **argv)
+{
+ struct object_cache_info info = {};
+ struct sd_req hdr;
+ struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+ char size_str[UINT64_DECIMAL_SIZE], used_str[UINT64_DECIMAL_SIZE];
+ int ret, i;
+
+ sd_init_req(&hdr, SD_OP_GET_CACHE_INFO);
+ hdr.data_length = sizeof(info);
+ ret = dog_exec_req(sdhost, sdport, &hdr, &info);
+ if (ret < 0)
+ return EXIT_SYSFAIL;
+
+ if (rsp->result != SD_RES_SUCCESS) {
+ sd_err("failed to get cache infomation: %s",
+ sd_strerror(rsp->result));
+ return EXIT_FAILURE;
+ }
+
+ fprintf(stdout, "Name\tTag\tTotal\tDirty\tClean\n");
+ for (i = 0; i < info.count; i++) {
+ char total_str[UINT64_DECIMAL_SIZE],
+ dirty_str[UINT64_DECIMAL_SIZE],
+ clean_str[UINT64_DECIMAL_SIZE];
+ uint64_t total = info.caches[i].total * SD_DATA_OBJ_SIZE,
+ dirty = info.caches[i].dirty * SD_DATA_OBJ_SIZE,
+ clean = total - dirty;
+ char name[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
+
+ size_to_str(total, total_str, sizeof(total_str));
+ size_to_str(dirty, dirty_str, sizeof(dirty_str));
+ size_to_str(clean, clean_str, sizeof(clean_str));
+ ret = vid_to_name_tag(info.caches[i].vid, name, tag);
+ if (ret != SD_RES_SUCCESS)
+ return EXIT_FAILURE;
+ fprintf(stdout, "%s\t%s\t%s\t%s\t%s\n",
+ name, tag, total_str, dirty_str, clean_str);
+ }
+
+ size_to_str(info.size, size_str, sizeof(size_str));
+ size_to_str(info.used, used_str, sizeof(used_str));
+ fprintf(stdout, "\nCache size %s, used %s\n", size_str, used_str);
+
+ return EXIT_SUCCESS;
+}
+
+static struct subcommand vdi_cache_cmd[] = {
+ {"flush", NULL, NULL, "flush the cache of the vdi specified.",
+ NULL, CMD_NEED_ARG, vdi_cache_flush},
+ {"delete", NULL, NULL, "delete the cache of the vdi specified in all nodes.",
+ NULL, CMD_NEED_ARG, vdi_cache_delete},
+ {"info", NULL, NULL, "show usage of the cache",
+ NULL, 0, vdi_cache_info},
+ {NULL,},
+};
+
+static int vdi_cache(int argc, char **argv)
+{
+ return do_generic_subcommand(vdi_cache_cmd, argc, argv);
+}
+
+static struct subcommand vdi_cmd[] = {
+ {"check", "<vdiname>", "saph", "check and repair image's consistency",
+ NULL, CMD_NEED_NODELIST|CMD_NEED_ARG,
+ vdi_check, vdi_options},
+ {"create", "<vdiname> <size>", "Pcaphrv", "create an image",
+ NULL, CMD_NEED_NODELIST|CMD_NEED_ARG,
+ vdi_create, vdi_options},
+ {"snapshot", "<vdiname>", "saphrv", "create a snapshot",
+ NULL, CMD_NEED_ARG,
+ vdi_snapshot, vdi_options},
+ {"clone", "<src vdi> <dst vdi>", "sPcaphrv", "clone an image",
+ NULL, CMD_NEED_ARG,
+ vdi_clone, vdi_options},
+ {"delete", "<vdiname>", "saph", "delete an image",
+ NULL, CMD_NEED_ARG,
+ vdi_delete, vdi_options},
+ {"rollback", "<vdiname>", "saphfrv", "rollback to a snapshot",
+ NULL, CMD_NEED_ARG,
+ vdi_rollback, vdi_options},
+ {"list", "[vdiname]", "aprh", "list images",
+ NULL, 0, vdi_list, vdi_options},
+ {"tree", NULL, "aph", "show images in tree view format",
+ NULL, 0, vdi_tree, vdi_options},
+ {"graph", NULL, "aph", "show images in Graphviz dot format",
+ NULL, 0, vdi_graph, vdi_options},
+ {"object", "<vdiname>", "isaph", "show object information in the image",
+ NULL, CMD_NEED_NODELIST|CMD_NEED_ARG,
+ vdi_object, vdi_options},
+ {"track", "<vdiname>", "isaph", "show the object epoch trace in the image",
+ NULL, CMD_NEED_NODELIST|CMD_NEED_ARG,
+ vdi_track, vdi_options},
+ {"setattr", "<vdiname> <key> [value]", "dxaph", "set a VDI attribute",
+ NULL, CMD_NEED_ARG,
+ vdi_setattr, vdi_options},
+ {"getattr", "<vdiname> <key>", "aph", "get a VDI attribute",
+ NULL, CMD_NEED_ARG,
+ vdi_getattr, vdi_options},
+ {"resize", "<vdiname> <new size>", "aph", "resize an image",
+ NULL, CMD_NEED_ARG,
+ vdi_resize, vdi_options},
+ {"read", "<vdiname> [<offset> [<len>]]", "saph", "read data from an image",
+ NULL, CMD_NEED_ARG,
+ vdi_read, vdi_options},
+ {"write", "<vdiname> [<offset> [<len>]]", "apwh", "write data to an image",
+ NULL, CMD_NEED_ARG,
+ vdi_write, vdi_options},
+ {"backup", "<vdiname> <backup>", "sFaph", "create an incremental backup between two snapshots",
+ NULL, CMD_NEED_NODELIST|CMD_NEED_ARG,
+ vdi_backup, vdi_options},
+ {"restore", "<vdiname> <backup>", "saph", "restore snapshot images from a backup",
+ NULL, CMD_NEED_NODELIST|CMD_NEED_ARG,
+ vdi_restore, vdi_options},
+ {"cache", "<vdiname>", "saph", "Run 'dog vdi cache' for more information",
+ vdi_cache_cmd, CMD_NEED_ARG,
+ vdi_cache, vdi_options},
+ {NULL,},
+};
+
+static int vdi_parser(int ch, char *opt)
+{
+ char *p;
+ int nr_copies;
+
+ switch (ch) {
+ case 'P':
+ vdi_cmd_data.prealloc = true;
+ break;
+ case 'i':
+ vdi_cmd_data.index = strtol(opt, &p, 10);
+ if (opt == p) {
+ sd_err("The index must be an integer");
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 's':
+ vdi_cmd_data.snapshot_id = strtol(opt, &p, 10);
+ if (opt == p) {
+ vdi_cmd_data.snapshot_id = 0;
+ pstrcpy(vdi_cmd_data.snapshot_tag,
+ sizeof(vdi_cmd_data.snapshot_tag), opt);
+ } else if (vdi_cmd_data.snapshot_id == 0) {
+ fprintf(stderr,
+ "The snapshot id must be larger than zero\n");
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'x':
+ vdi_cmd_data.exclusive = true;
+ break;
+ case 'd':
+ vdi_cmd_data.delete = true;
+ break;
+ case 'w':
+ vdi_cmd_data.writeback = true;
+ break;
+ case 'c':
+ nr_copies = strtol(opt, &p, 10);
+ if (opt == p || nr_copies < 0 || nr_copies > SD_MAX_COPIES) {
+ sd_err("Invalid copies number, must be "
+ "an integer between 0 and %d", SD_MAX_COPIES);
+ exit(EXIT_FAILURE);
+ }
+ vdi_cmd_data.nr_copies = nr_copies;
+ break;
+ case 'F':
+ vdi_cmd_data.from_snapshot_id = strtol(opt, &p, 10);
+ if (opt == p) {
+ vdi_cmd_data.from_snapshot_id = 0;
+ pstrcpy(vdi_cmd_data.from_snapshot_tag,
+ sizeof(vdi_cmd_data.from_snapshot_tag), opt);
+ }
+ break;
+ case 'f':
+ vdi_cmd_data.force = true;
+ break;
+ }
+
+ return 0;
+}
+
+struct command vdi_command = {
+ "vdi",
+ vdi_cmd,
+ vdi_parser
+};
diff --git a/include/internal_proto.h b/include/internal_proto.h
index 7a15336..8802300 100644
--- a/include/internal_proto.h
+++ b/include/internal_proto.h
@@ -13,7 +13,7 @@
/*
* This file specified the sheepdog-internal protocol, which is spoken between
- * sheepdog daemons, as well as between collie and sheepdog daemon for internal
+ * sheepdog daemons, as well as between dog and sheepdog daemon for internal
* operations.
*/
@@ -33,7 +33,7 @@
/*
* Operations with opcodes above 0x80 are considered part of the inter-sheep
- * include sheep-collie protocol and are versioned using SD_SHEEP_PROTO_VER
+ * include sheep-dog protocol and are versioned using SD_SHEEP_PROTO_VER
* instead of SD_PROTO_VER.
*
* These same applies for the above 0x80 flags and error values below.
diff --git a/lib/logger.c b/lib/logger.c
index b7dbd2f..012cfa2 100644
--- a/lib/logger.c
+++ b/lib/logger.c
@@ -117,7 +117,7 @@ static int64_t max_logsize = 500 * 1024 * 1024; /*500MB*/
static pthread_mutex_t logsize_lock = PTHREAD_MUTEX_INITIALIZER;
/*
- * We need to set default log formatter because collie doesn't want to call
+ * We need to set default log formatter because dog doesn't want to call
* select_log_formatter().
*/
static void __attribute__((constructor(65535)))
diff --git a/man/Makefile.am b/man/Makefile.am
index 6962bb8..6d34cdd 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -1,12 +1,12 @@
MAINTAINERCLEANFILES = Makefile.in
-dist_man_MANS = sheep.8 collie.8
+dist_man_MANS = sheep.8 dog.8
if BUILD_SHEEPFS
dist_man_MANS += sheepfs.8
endif
-EXTRA_DIST = sheep.8.in collie.8.in sheepfs.8.in
+EXTRA_DIST = sheep.8.in dog.8.in sheepfs.8.in
sheep.8.options = $(shell ../sheep/sheep -h | \
perl -ne 'print ".TP\n.BI $$1 \"\\fR, \\fP\" $$2\n$$3\n" if /^ ([^,]+), (\S+)\s+(.+)/' | \
@@ -14,9 +14,9 @@ sheep.8.options = $(shell ../sheep/sheep -h | \
sed 's/"/\\"/g' | \
perl -pe 's/\n/\\n/g')
-collie.8.options = $(shell ../collie/collie -h | \
- perl -ne 'if (/^ (.+?) \s+(.+)/) {system "../collie/collie $$1 -h"; print "Description:\n $$2\n"}'| \
- sed 's/Usage: collie \(.*\)/.TP\n.BI "\1"/g' | \
+dog.8.options = $(shell ../dog/dog -h | \
+ perl -ne 'if (/^ (.+?) \s+(.+)/) {system "../dog/dog $$1 -h"; print "Description:\n $$2\n"}'| \
+ sed 's/Usage: dog \(.*\)/.TP\n.BI "\1"/g' | \
sed 's/\(^[a-zA-Z]*:\)/\n\1/g' | \
sed 's/\\/\\\\\\/g' | \
sed 's/"/\\"/g' | \
diff --git a/man/collie.8.in b/man/collie.8.in
deleted file mode 100644
index 7fdee4a..0000000
--- a/man/collie.8.in
+++ /dev/null
@@ -1,37 +0,0 @@
-.TH SHEEPDOG 8 @DATE@
-.SH NAME
-collie \- Command line utility for the sheep daemon
-.SH SYNOPSIS
-.B "collie <command> <subcommand> [options]"
-.SH DESCRIPTION
-.B collie
-- Sheepdog is a distributed storage system for QEMU. It provides
-highly available block level storage volumes to virtual machines.
-Sheepdog supports advanced volume management features such as snapshot,
-cloning, and thin provisioning. The architecture of Sheepdog is fully
-symmetric; there is no central node such as a meta-data server.
-
-The server daemon is called sheep(8). A command line utility is available
-via collie(8). QEMU virtual machines use the sheep daemon via a block
-driver available in qemu(1).
-
-For more information, run 'collie <command> <subcommand> --help'.
-.SH COMMAND & SUBCOMMAND
- at OPTIONS@
-
-.SH DEPENDENCIES
-\fBSheepdog\fP requires QEMU 0.13.z or later and Corosync 1.y.z or 2.y.z.
-
-.SH FILES
-none
-
-.SH SEE ALSO
-.BR sheep(8),
-.BR qemu(1),
-.BR sheepfs(8),
-.BR corosync_overview(8)
-
-.SH AUTHORS
-This software is developed by the Sheepdog community which may be reached
-via mailing list at <sheepdog at lists.wpkg.org>.
-.PP
diff --git a/man/dog.8.in b/man/dog.8.in
new file mode 100644
index 0000000..9834a56
--- /dev/null
+++ b/man/dog.8.in
@@ -0,0 +1,37 @@
+.TH SHEEPDOG 8 @DATE@
+.SH NAME
+dog \- Command line utility for the sheep daemon
+.SH SYNOPSIS
+.B "dog <command> <subcommand> [options]"
+.SH DESCRIPTION
+.B dog
+- Sheepdog is a distributed storage system for QEMU. It provides
+highly available block level storage volumes to virtual machines.
+Sheepdog supports advanced volume management features such as snapshot,
+cloning, and thin provisioning. The architecture of Sheepdog is fully
+symmetric; there is no central node such as a meta-data server.
+
+The server daemon is called sheep(8). A command line utility is available
+via dog(8). QEMU virtual machines use the sheep daemon via a block
+driver available in qemu(1).
+
+For more information, run 'dog <command> <subcommand> --help'.
+.SH COMMAND & SUBCOMMAND
+ at OPTIONS@
+
+.SH DEPENDENCIES
+\fBSheepdog\fP requires QEMU 0.13.z or later and Corosync 1.y.z or 2.y.z.
+
+.SH FILES
+none
+
+.SH SEE ALSO
+.BR sheep(8),
+.BR qemu(1),
+.BR sheepfs(8),
+.BR corosync_overview(8)
+
+.SH AUTHORS
+This software is developed by the Sheepdog community which may be reached
+via mailing list at <sheepdog at lists.wpkg.org>.
+.PP
diff --git a/man/sheep.8.in b/man/sheep.8.in
index 93295a8..6f855c2 100644
--- a/man/sheep.8.in
+++ b/man/sheep.8.in
@@ -12,7 +12,7 @@ cloning, and thin provisioning. The architecture of Sheepdog is fully
symmetric; there is no central node such as a meta-data server.
The server daemon is called sheep(8). A command line utility is available
-via collie(8). QEMU virtual machines use the sheep daemon via a block
+via dog(8). QEMU virtual machines use the sheep daemon via a block
driver available in qemu(1).
.SH OPTIONS
@OPTIONS@
@@ -32,7 +32,7 @@ mount \-o remount,user_xattr /var/lib/sheepdog
.B /var/lib/sheepdog - Directory containing block storage information
.SH SEE ALSO
-.BR collie(8),
+.BR dog(8),
.BR qemu(1),
.BR sheepfs(8),
.BR corosync_overview(8)
diff --git a/man/sheepfs.8.in b/man/sheepfs.8.in
index 58d8624..0a3a3a1 100644
--- a/man/sheepfs.8.in
+++ b/man/sheepfs.8.in
@@ -12,7 +12,7 @@ cloning, and thin provisioning. The architecture of Sheepdog is fully
symmetric; there is no central node such as a meta-data server.
The server daemon is called sheep(8). A command line utility is available
-via collie(8). A pseudo file system is available via sheepfs(8). QEMU
+via dog(8). A pseudo file system is available via sheepfs(8). QEMU
virtual machines use the sheep daemon via a block driver available in qemu(1).
Sheepfs is a FUSE-based pseudo file system in userland to access both
@@ -47,7 +47,7 @@ none
.SH SEE ALSO
.BR sheep(8),
-.BR collie(8),
+.BR dog(8),
.BR qemu(1),
.BR corosync_overview(8)
diff --git a/script/Makefile.am b/script/Makefile.am
index 6ae958d..66ee428 100644
--- a/script/Makefile.am
+++ b/script/Makefile.am
@@ -2,7 +2,7 @@ MAINTAINERCLEANFILES = Makefile.in
EXTRA_DIST = generic.in
-noinst_HEADERS = bash_completion_collie checkarch.sh vditest
+noinst_HEADERS = bash_completion_dog checkarch.sh vditest
target_INIT = generic
diff --git a/script/bash_completion_collie b/script/bash_completion_collie
deleted file mode 100644
index a368184..0000000
--- a/script/bash_completion_collie
+++ /dev/null
@@ -1,303 +0,0 @@
-#!bash
-
-_collie_cluster_format()
-{
- local cur
- cur="${COMP_WORDS[COMP_CWORD]}"
-
- case "$cur" in
- -*)
- COMPREPLY=(${COMPREPLY[@]} \
- $( compgen \
- -W "-c --copies" \
- -- ${cur} ))
- ;;
- esac
-}
-
-_collie_cluster_recover()
-{
- local cur
- cur="${COMP_WORDS[COMP_CWORD]}"
-
- case "$cur" in
- -*)
- COMPREPLY=(${COMPREPLY[@]} \
- $( compgen \
- -W "-f --force" \
- -- ${cur} ))
- ;;
- esac
-}
-
-_collie_vdi_create()
-{
- local cur
- cur="${COMP_WORDS[COMP_CWORD]}"
-
- case "$cur" in
- -*)
- COMPREPLY=(${COMPREPLY[@]} \
- $( compgen \
- -W "-P --prealloc" \
- -- ${cur} ))
- ;;
- esac
-}
-
-_collie_vdi_snapshot()
-{
- local cur
- cur="${COMP_WORDS[COMP_CWORD]}"
-
- case "$cur" in
- -*)
- COMPREPLY=(${COMPREPLY[@]} \
- $( compgen \
- -W "-s --snapshot" \
- -- ${cur} ))
- ;;
- esac
-}
-
-_collie_vdi_clone()
-{
- local cur
- cur="${COMP_WORDS[COMP_CWORD]}"
-
- case "$cur" in
- -*)
- COMPREPLY=(${COMPREPLY[@]} \
- $( compgen \
- -W "-P --prealloc -s --snapshot" \
- -- ${cur} ))
- ;;
- esac
-}
-
-_collie_vdi_read()
-{
- local cur
- cur="${COMP_WORDS[COMP_CWORD]}"
-
- case "$cur" in
- -*)
- COMPREPLY=(${COMPREPLY[@]} \
- $( compgen \
- -W "-s --snapshot" \
- -- ${cur} ))
- ;;
- esac
-}
-
-_collie_vdi_delete()
-{
- local cur collie vdilist
- cur="${COMP_WORDS[COMP_CWORD]}"
- collie="${COMP_WORDS[0]}"
- vdilist="$(${collie} vdi list | tail -n+3 | grep '^ ' | awk '{print $1}')"
-
- case "$cur" in
- -*)
- COMPREPLY=(${COMPREPLY[@]} \
- $( compgen \
- -W "-s --snapshot" \
- -- ${cur} ))
- ;;
- *)
- COMPREPLY=($( compgen -W "${vdilist}" -- ${cur} ))
- ;;
- esac
-}
-
-_collie_vdi_object()
-{
- local cur collie vdilist
- cur="${COMP_WORDS[COMP_CWORD]}"
- collie="${COMP_WORDS[0]}"
- vdilist="$(${collie} vdi list | tail -n+3 | grep '^ ' | awk '{print $1}')"
-
- case "$cur" in
- -*)
- COMPREPLY=(${COMPREPLY[@]} \
- $( compgen \
- -W "-i --index -s --snapshot" \
- -- ${cur} ))
- ;;
- *)
- COMPREPLY=($( compgen -W "${vdilist}" -- ${cur} ))
- ;;
- esac
-}
-
-_collie_vdi_setattr()
-{
- local cur
- cur="${COMP_WORDS[COMP_CWORD]}"
-
- case "$cur" in
- -*)
- COMPREPLY=(${COMPREPLY[@]} \
- $( compgen \
- -W "-d --delete -x --exclusive" \
- -- ${cur} ))
- ;;
- esac
-}
-
-_collie_cluster()
-{
- local opts
- opts="info format shutdown recover snapshot"
-
- case "$1" in
- info)
- ;;
- format)
- _collie_cluster_format
- ;;
- shutdown)
- ;;
- recover)
- _collie_cluster_recover
- ;;
- snapshot)
- ;;
- "")
- COMPREPLY=($( compgen \
- -W "${opts}" \
- -- "${COMP_WORDS[COMP_CWORD]}" ))
- ;;
- *)
- COMPREPLY=()
- ;;
- esac
-}
-
-_collie_node()
-{
- local opts
- opts="info list recovery kill cache"
-
- case "$1" in
- info)
- ;;
- list)
- ;;
- recovery)
- ;;
- kill)
- ;;
- cache)
- ;;
- "")
- COMPREPLY=($( compgen \
- -W "${opts}" \
- -- "${COMP_WORDS[COMP_CWORD]}" ))
- ;;
- *)
- COMPREPLY=()
- ;;
- esac
-}
-
-_collie_vdi()
-{
- local opts
- opts="create snapshot clone resize read write \
-list tree graph delete object setattr getattr track check \
-rollback flush backup restore"
-
- case "$1" in
- create)
- _collie_vdi_create
- ;;
- snapshot)
- _collie_vdi_snapshot
- ;;
- clone)
- _collie_vdi_clone
- ;;
- resize)
- ;;
- read)
- _collie_vdi_read
- ;;
- write)
- ;;
- list)
- ;;
- tree)
- ;;
- graph)
- ;;
- delete)
- _collie_vdi_delete
- ;;
- object)
- _collie_vdi_object
- ;;
- setattr)
- _collie_vdi_setattr
- ;;
- getattr)
- ;;
- track)
- ;;
- check)
- ;;
- rollback)
- ;;
- flush)
- ;;
- backup)
- ;;
- restore)
- ;;
- "")
- COMPREPLY=($( compgen \
- -W "${opts}" \
- -- "${COMP_WORDS[COMP_CWORD]}" ))
- ;;
- *)
- COMPREPLY=()
- ;;
- esac
-}
-
-_collie()
-{
- local opts cur cmd subcmd i
- opts="cluster node vdi"
- cur="${COMP_WORDS[COMP_CWORD]}"
-
- if [ $COMP_CWORD -gt 1 ]; then
- cmd=${COMP_WORDS[1]}
- fi
-
- if [ $COMP_CWORD -gt 2 ]; then
- subcmd=${COMP_WORDS[2]}
- fi
-
- COMPREPLY=($( compgen -W "-a --address -p --port -h --help" -- ${cur} ))
-
- case "${cmd}" in
- cluster)
- _collie_cluster ${subcmd}
- ;;
- node)
- _collie_node ${subcmd}
- ;;
- vdi)
- _collie_vdi ${subcmd}
- ;;
- "")
- COMPREPLY=($( compgen -W "${opts}" -- ${cur} ))
- ;;
- *)
- COMPREPLY=()
- ;;
- esac
-}
-
-complete -F _collie collie
diff --git a/script/bash_completion_dog b/script/bash_completion_dog
new file mode 100644
index 0000000..89c9544
--- /dev/null
+++ b/script/bash_completion_dog
@@ -0,0 +1,303 @@
+#!bash
+
+_dog_cluster_format()
+{
+ local cur
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ case "$cur" in
+ -*)
+ COMPREPLY=(${COMPREPLY[@]} \
+ $( compgen \
+ -W "-c --copies" \
+ -- ${cur} ))
+ ;;
+ esac
+}
+
+_dog_cluster_recover()
+{
+ local cur
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ case "$cur" in
+ -*)
+ COMPREPLY=(${COMPREPLY[@]} \
+ $( compgen \
+ -W "-f --force" \
+ -- ${cur} ))
+ ;;
+ esac
+}
+
+_dog_vdi_create()
+{
+ local cur
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ case "$cur" in
+ -*)
+ COMPREPLY=(${COMPREPLY[@]} \
+ $( compgen \
+ -W "-P --prealloc" \
+ -- ${cur} ))
+ ;;
+ esac
+}
+
+_dog_vdi_snapshot()
+{
+ local cur
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ case "$cur" in
+ -*)
+ COMPREPLY=(${COMPREPLY[@]} \
+ $( compgen \
+ -W "-s --snapshot" \
+ -- ${cur} ))
+ ;;
+ esac
+}
+
+_dog_vdi_clone()
+{
+ local cur
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ case "$cur" in
+ -*)
+ COMPREPLY=(${COMPREPLY[@]} \
+ $( compgen \
+ -W "-P --prealloc -s --snapshot" \
+ -- ${cur} ))
+ ;;
+ esac
+}
+
+_dog_vdi_read()
+{
+ local cur
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ case "$cur" in
+ -*)
+ COMPREPLY=(${COMPREPLY[@]} \
+ $( compgen \
+ -W "-s --snapshot" \
+ -- ${cur} ))
+ ;;
+ esac
+}
+
+_dog_vdi_delete()
+{
+ local cur dog vdilist
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ dog="${COMP_WORDS[0]}"
+ vdilist="$(${dog} vdi list | tail -n+3 | grep '^ ' | awk '{print $1}')"
+
+ case "$cur" in
+ -*)
+ COMPREPLY=(${COMPREPLY[@]} \
+ $( compgen \
+ -W "-s --snapshot" \
+ -- ${cur} ))
+ ;;
+ *)
+ COMPREPLY=($( compgen -W "${vdilist}" -- ${cur} ))
+ ;;
+ esac
+}
+
+_dog_vdi_object()
+{
+ local cur dog vdilist
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ dog="${COMP_WORDS[0]}"
+ vdilist="$(${dog} vdi list | tail -n+3 | grep '^ ' | awk '{print $1}')"
+
+ case "$cur" in
+ -*)
+ COMPREPLY=(${COMPREPLY[@]} \
+ $( compgen \
+ -W "-i --index -s --snapshot" \
+ -- ${cur} ))
+ ;;
+ *)
+ COMPREPLY=($( compgen -W "${vdilist}" -- ${cur} ))
+ ;;
+ esac
+}
+
+_dog_vdi_setattr()
+{
+ local cur
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ case "$cur" in
+ -*)
+ COMPREPLY=(${COMPREPLY[@]} \
+ $( compgen \
+ -W "-d --delete -x --exclusive" \
+ -- ${cur} ))
+ ;;
+ esac
+}
+
+_dog_cluster()
+{
+ local opts
+ opts="info format shutdown recover snapshot"
+
+ case "$1" in
+ info)
+ ;;
+ format)
+ _dog_cluster_format
+ ;;
+ shutdown)
+ ;;
+ recover)
+ _dog_cluster_recover
+ ;;
+ snapshot)
+ ;;
+ "")
+ COMPREPLY=($( compgen \
+ -W "${opts}" \
+ -- "${COMP_WORDS[COMP_CWORD]}" ))
+ ;;
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+}
+
+_dog_node()
+{
+ local opts
+ opts="info list recovery kill cache"
+
+ case "$1" in
+ info)
+ ;;
+ list)
+ ;;
+ recovery)
+ ;;
+ kill)
+ ;;
+ cache)
+ ;;
+ "")
+ COMPREPLY=($( compgen \
+ -W "${opts}" \
+ -- "${COMP_WORDS[COMP_CWORD]}" ))
+ ;;
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+}
+
+_dog_vdi()
+{
+ local opts
+ opts="create snapshot clone resize read write \
+list tree graph delete object setattr getattr track check \
+rollback flush backup restore"
+
+ case "$1" in
+ create)
+ _dog_vdi_create
+ ;;
+ snapshot)
+ _dog_vdi_snapshot
+ ;;
+ clone)
+ _dog_vdi_clone
+ ;;
+ resize)
+ ;;
+ read)
+ _dog_vdi_read
+ ;;
+ write)
+ ;;
+ list)
+ ;;
+ tree)
+ ;;
+ graph)
+ ;;
+ delete)
+ _dog_vdi_delete
+ ;;
+ object)
+ _dog_vdi_object
+ ;;
+ setattr)
+ _dog_vdi_setattr
+ ;;
+ getattr)
+ ;;
+ track)
+ ;;
+ check)
+ ;;
+ rollback)
+ ;;
+ flush)
+ ;;
+ backup)
+ ;;
+ restore)
+ ;;
+ "")
+ COMPREPLY=($( compgen \
+ -W "${opts}" \
+ -- "${COMP_WORDS[COMP_CWORD]}" ))
+ ;;
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+}
+
+_dog()
+{
+ local opts cur cmd subcmd i
+ opts="cluster node vdi"
+ cur="${COMP_WORDS[COMP_CWORD]}"
+
+ if [ $COMP_CWORD -gt 1 ]; then
+ cmd=${COMP_WORDS[1]}
+ fi
+
+ if [ $COMP_CWORD -gt 2 ]; then
+ subcmd=${COMP_WORDS[2]}
+ fi
+
+ COMPREPLY=($( compgen -W "-a --address -p --port -h --help" -- ${cur} ))
+
+ case "${cmd}" in
+ cluster)
+ _dog_cluster ${subcmd}
+ ;;
+ node)
+ _dog_node ${subcmd}
+ ;;
+ vdi)
+ _dog_vdi ${subcmd}
+ ;;
+ "")
+ COMPREPLY=($( compgen -W "${opts}" -- ${cur} ))
+ ;;
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+}
+
+complete -F _dog dog
diff --git a/sheep/sheep.c b/sheep/sheep.c
index 461a729..61d7f76 100644
--- a/sheep/sheep.c
+++ b/sheep/sheep.c
@@ -29,7 +29,7 @@ static const char bind_help[] =
"This tries to teach sheep listen to NIC of 192.168.1.1.\n"
"\nExample:\n\t$ sheep -b 0.0.0.0 ...\n"
"This tries to teach sheep listen to all the NICs available. It can be useful\n"
-"when you want sheep to response collie without specified address and port.\n";
+"when you want sheep to response dog without specified address and port.\n";
static const char ioaddr_help[] =
"Example:\n\t$ sheep -i host=192.168.1.1,port=7002 ...\n"
diff --git a/sheep/store.c b/sheep/store.c
index f4343b3..3e898b8 100644
--- a/sheep/store.c
+++ b/sheep/store.c
@@ -25,7 +25,7 @@ int update_epoch_log(uint32_t epoch, struct sd_node *nodes, size_t nr_nodes)
sd_debug("update epoch: %d, %zu", epoch, nr_nodes);
- /* Piggyback the epoch creation time for 'collie cluster info' */
+ /* Piggyback the epoch creation time for 'dog cluster info' */
time(&t);
nodes_len = nr_nodes * sizeof(struct sd_node);
len = nodes_len + sizeof(time_t);
diff --git a/sheepdog.spec.in b/sheepdog.spec.in
index 5e19366..b6ec4e6 100644
--- a/sheepdog.spec.in
+++ b/sheepdog.spec.in
@@ -63,12 +63,12 @@ fi
%doc COPYING README INSTALL
%{_sbindir}/sheep
%{_sbindir}/sheepfs
-%{_sbindir}/collie
+%{_sbindir}/dog
%attr(755,-,-)%config %{_initddir}/sheepdog
%dir %{_localstatedir}/lib/sheepdog
%{_mandir}/man8/sheep.8*
%{_mandir}/man8/sheepfs.8*
-%{_mandir}/man8/collie.8*
+%{_mandir}/man8/dog.8*
%changelog
* @date@ Autotools generated version <nobody at nowhere.org> - @version at -1.@alphatag@
diff --git a/sheepfs/cluster.c b/sheepfs/cluster.c
index 6665bce..3eb1d0b 100644
--- a/sheepfs/cluster.c
+++ b/sheepfs/cluster.c
@@ -50,7 +50,7 @@ size_t cluster_info_get_size(const char *path)
size_t len;
char cmd[COMMAND_LEN];
- snprintf(cmd, sizeof(cmd), "collie cluster info -a %s -p %d",
+ snprintf(cmd, sizeof(cmd), "dog cluster info -a %s -p %d",
sdhost, sdport);
buf = sheepfs_run_cmd(cmd);
if (!buf)
diff --git a/sheepfs/node.c b/sheepfs/node.c
index a3558d5..2a7df5b 100644
--- a/sheepfs/node.c
+++ b/sheepfs/node.c
@@ -57,7 +57,7 @@ size_t node_info_get_size(const char *path)
size_t len;
char cmd[COMMAND_LEN];
- snprintf(cmd, sizeof(cmd), "collie node info -a %s -p %d",
+ snprintf(cmd, sizeof(cmd), "dog node info -a %s -p %d",
sdhost, sdport);
buf = sheepfs_run_cmd(cmd);
if (!buf)
@@ -80,7 +80,7 @@ size_t node_list_get_size(const char *path)
size_t len;
char cmd[COMMAND_LEN];
- snprintf(cmd, sizeof(cmd), "collie node list -a %s -p %d",
+ snprintf(cmd, sizeof(cmd), "dog node list -a %s -p %d",
sdhost, sdport);
buf = sheepfs_run_cmd(cmd);
if (!buf)
diff --git a/sheepfs/vdi.c b/sheepfs/vdi.c
index 814a40b..f6d0639 100644
--- a/sheepfs/vdi.c
+++ b/sheepfs/vdi.c
@@ -62,7 +62,7 @@ size_t vdi_list_get_size(const char *path)
size_t len;
char cmd[COMMAND_LEN];
- snprintf(cmd, sizeof(cmd), "collie vdi list -a %s -p %d",
+ snprintf(cmd, sizeof(cmd), "dog vdi list -a %s -p %d",
sdhost, sdport);
buf = sheepfs_run_cmd(cmd);
if (!buf)
diff --git a/sheepfs/volume.c b/sheepfs/volume.c
index 73e7419..0558639 100644
--- a/sheepfs/volume.c
+++ b/sheepfs/volume.c
@@ -390,7 +390,7 @@ static int init_vdi_info(const char *entry, uint32_t *vid, size_t *size)
struct vdi_inode *inode = NULL, *dummy;
char command[COMMAND_LEN];
- snprintf(command, sizeof(command), "collie vdi list -r %s -a %s -p %d",
+ snprintf(command, sizeof(command), "dog vdi list -r %s -a %s -p %d",
entry, sdhost, sdport);
buf = sheepfs_run_cmd(command);
if (!buf)
diff --git a/tests/dynamorio/journaling/01.sh b/tests/dynamorio/journaling/01.sh
index 820793e..4d23929 100755
--- a/tests/dynamorio/journaling/01.sh
+++ b/tests/dynamorio/journaling/01.sh
@@ -15,7 +15,7 @@ sudo ~/dynamorio/build/bin64/drrun -c libjournaling.so 1 -- \
sleep 3
-collie cluster format -c 1
-collie vdi create test 100M
+dog cluster format -c 1
+dog vdi create test 100M
sudo sheep -d -c shepherd:127.0.0.1 -p 7000 -j size=64 /tmp/sheepdog/dynamorio/0
diff --git a/tests/functional/001 b/tests/functional/001
index 0897bb4..2c812e3 100755
--- a/tests/functional/001
+++ b/tests/functional/001
@@ -37,5 +37,5 @@ done
_wait_for_sheep 3
echo check whether all nodes have the same cluster info
for i in 0 1 2; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
diff --git a/tests/functional/002 b/tests/functional/002
index 698f545..1812985 100755
--- a/tests/functional/002
+++ b/tests/functional/002
@@ -32,5 +32,5 @@ _wait_for_sheep 3
echo check whether all nodes have the same cluster info
for i in 0 1 2; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
diff --git a/tests/functional/003 b/tests/functional/003
index c799164..d949bc1 100755
--- a/tests/functional/003
+++ b/tests/functional/003
@@ -30,5 +30,5 @@ done
_wait_for_sheep 3
echo check whether all nodes have the same cluster info
for i in 0 1 2; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
diff --git a/tests/functional/004 b/tests/functional/004
index 83eb955..2a912db 100755
--- a/tests/functional/004
+++ b/tests/functional/004
@@ -38,5 +38,5 @@ done
_wait_for_sheep 5
echo check whether all nodes have the same cluster info
for i in 0 1 2 3 4; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
diff --git a/tests/functional/005 b/tests/functional/005
index 5523b9e..09613fe 100755
--- a/tests/functional/005
+++ b/tests/functional/005
@@ -22,7 +22,7 @@ done
_wait_for_sheep 2 4
-$COLLIE cluster shutdown -p 7004
+$DOG cluster shutdown -p 7004
_wait_for_sheep_stop
nr=0
@@ -35,5 +35,5 @@ done
_wait_for_sheep 5
echo check whether all nodes have the same cluster info
for i in 0 1 2 3 4; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
diff --git a/tests/functional/006 b/tests/functional/006
index 55ebbf8..308da48 100755
--- a/tests/functional/006
+++ b/tests/functional/006
@@ -19,7 +19,7 @@ _wait_for_sheep 10
echo check whether all nodes have the same cluster info
for i in `seq 0 9`; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info > $STORE/cinfo.$i
+ $DOG cluster info -p 700$i | _filter_cluster_info > $STORE/cinfo.$i
done
for i in `seq 1 9`; do
diff -u $STORE/cinfo.0 $STORE/cinfo.$i
diff --git a/tests/functional/007 b/tests/functional/007
index 0fda0eb..0221033 100755
--- a/tests/functional/007
+++ b/tests/functional/007
@@ -9,7 +9,7 @@
_start_sheep 1
_wait_for_sheep 1 1
_cluster_format -p 7001 -c 1
-$COLLIE cluster shutdown -p 7001
+$DOG cluster shutdown -p 7001
_wait_for_sheep_stop
# start Sheepdog with one node
@@ -23,5 +23,5 @@ _wait_for_sheep 1
_start_sheep 2 # should succeed
_wait_for_sheep 2
-$COLLIE cluster info -p 7000 | _filter_cluster_info
-$COLLIE cluster info -p 7002 | _filter_cluster_info
+$DOG cluster info -p 7000 | _filter_cluster_info
+$DOG cluster info -p 7002 | _filter_cluster_info
diff --git a/tests/functional/008 b/tests/functional/008
index 665cb6b..9afe56b 100755
--- a/tests/functional/008
+++ b/tests/functional/008
@@ -13,11 +13,11 @@ _wait_for_sheep "8"
_cluster_format -c 3
for i in `seq 0 4`; do
- $COLLIE vdi create test$i 100M
+ $DOG vdi create test$i 100M
done
for i in `seq 0 4`; do
- _random | $COLLIE vdi write test$i -p 7000 &
+ _random | $DOG vdi write test$i -p 7000 &
done
sleep 3
@@ -43,7 +43,7 @@ wait
for i in `seq 0 4`; do
for port in `seq 0 7`; do
- $COLLIE vdi read test$i -p 700$port | md5sum > $STORE/csum.$port &
+ $DOG vdi read test$i -p 700$port | md5sum > $STORE/csum.$port &
done
wait
for port in `seq 1 7`; do
diff --git a/tests/functional/009 b/tests/functional/009
index acf9693..86a4806 100755
--- a/tests/functional/009
+++ b/tests/functional/009
@@ -14,13 +14,13 @@ _wait_for_sheep 3
_cluster_format -c 2
# create a pre-allocated vdi
-$COLLIE vdi create test 80M -P
+$DOG vdi create test 80M -P
# stop the 3rd node
_kill_sheep 2
# write data to the vdi
-_random | $COLLIE vdi write test
+_random | $DOG vdi write test
# restart the 3rd node
_start_sheep 2
@@ -29,7 +29,7 @@ _wait_for_sheep_recovery 0
# show md5sum of the vdi on each node
for i in 0 1 2; do
- $COLLIE vdi read test -p 700$i | md5sum > $STORE/csum.$i
+ $DOG vdi read test -p 700$i | md5sum > $STORE/csum.$i
done
diff -u $STORE/csum.0 $STORE/csum.1
diff --git a/tests/functional/010 b/tests/functional/010
index de7ddbb..d050941 100755
--- a/tests/functional/010
+++ b/tests/functional/010
@@ -11,13 +11,13 @@ done
_wait_for_sheep 5
_cluster_format
-$COLLIE cluster recover disable
+$DOG cluster recover disable
-$COLLIE vdi create test 4G
+$DOG vdi create test 4G
# create 8 objects
for i in `seq 0 7`; do
- echo $i | $COLLIE vdi write test $((i * 4 * 1024 * 1024)) 512
+ echo $i | $DOG vdi write test $((i * 4 * 1024 * 1024)) 512
done
ls $STORE/*/obj/* | _filter_store | sort
@@ -26,43 +26,43 @@ _kill_sheep 3
_kill_sheep 4
_wait_for_sheep 3
-$COLLIE cluster info | head -6 | _filter_cluster_info
+$DOG cluster info | head -6 | _filter_cluster_info
ls $STORE/*/obj/* | _filter_store | sort
# overwrite the objects to invoke object recovery
for i in `seq 4 7`; do
- $COLLIE vdi read test $((i * 4 * 1024 * 1024)) 512 | md5sum
- echo $(($i + 100)) | $COLLIE vdi write test $((i * 4 * 1024 * 1024)) 512
+ $DOG vdi read test $((i * 4 * 1024 * 1024)) 512 | md5sum
+ echo $(($i + 100)) | $DOG vdi write test $((i * 4 * 1024 * 1024)) 512
done
-$COLLIE cluster info | head -6 | _filter_cluster_info
+$DOG cluster info | head -6 | _filter_cluster_info
ls $STORE/*/obj/* | _filter_store | sort
-$COLLIE cluster recover enable
+$DOG cluster recover enable
_wait_for_sheep_recovery 0
-$COLLIE cluster info | head -6 | _filter_cluster_info
+$DOG cluster info | head -6 | _filter_cluster_info
ls $STORE/*/obj/* | _filter_store | sort
-$COLLIE cluster recover disable
+$DOG cluster recover disable
for i in `seq 3 7`; do
_start_sheep $i
done
_wait_for_sheep 8
-$COLLIE cluster info | head -6 | _filter_cluster_info
+$DOG cluster info | head -6 | _filter_cluster_info
ls $STORE/*/obj/* | _filter_store | sort
# overwrite the objects to invoke object recovery
for i in `seq 0 3`; do
- $COLLIE vdi read test $((i * 4 * 1024 * 1024)) 512 -p 7007 | md5sum
- echo $(($i + 200)) | $COLLIE vdi write test $((i * 4 * 1024 * 1024)) 512
+ $DOG vdi read test $((i * 4 * 1024 * 1024)) 512 -p 7007 | md5sum
+ echo $(($i + 200)) | $DOG vdi write test $((i * 4 * 1024 * 1024)) 512
done
-$COLLIE cluster info | head -6 | _filter_cluster_info
+$DOG cluster info | head -6 | _filter_cluster_info
ls $STORE/*/obj/* | _filter_store | sort
-$COLLIE cluster recover enable
+$DOG cluster recover enable
_wait_for_sheep_recovery 0
-$COLLIE cluster info | head -6 | _filter_cluster_info
+$DOG cluster info | head -6 | _filter_cluster_info
ls $STORE/*/obj/* | _filter_store | sort
diff --git a/tests/functional/011 b/tests/functional/011
index c2dcffd..71548f6 100755
--- a/tests/functional/011
+++ b/tests/functional/011
@@ -18,7 +18,7 @@ _wait_for_sheep 3
echo check the number of vnodes
for i in 0 1 2; do
- $COLLIE node list -p 700$i
+ $DOG node list -p 700$i
done
status=0
diff --git a/tests/functional/012 b/tests/functional/012
index 9b1657e..91ac244 100755
--- a/tests/functional/012
+++ b/tests/functional/012
@@ -16,4 +16,4 @@ _start_sheep 4 "-g"
_wait_for_sheep 4
echo check the number of vnodes
-$COLLIE node list
+$DOG node list
diff --git a/tests/functional/014 b/tests/functional/014
index b561ba4..764f3ee 100755
--- a/tests/functional/014
+++ b/tests/functional/014
@@ -11,19 +11,19 @@ done
_wait_for_sheep 2
_cluster_format -c 2
-$COLLIE vdi create test 4G
+$DOG vdi create test 4G
echo -n value > $STORE/tmp.dat
echo "key shouldn't be found"
-$COLLIE vdi getattr test key
+$DOG vdi getattr test key
-$COLLIE vdi setattr test key value
-$COLLIE vdi getattr test key | diff - $STORE/tmp.dat
+$DOG vdi setattr test key value
+$DOG vdi getattr test key | diff - $STORE/tmp.dat
-$COLLIE vdi setattr test key value -d
+$DOG vdi setattr test key value -d
echo "key shouldn't be found"
-$COLLIE vdi getattr test key
+$DOG vdi getattr test key
status=0
diff --git a/tests/functional/015 b/tests/functional/015
index 2492d3b..b985506 100755
--- a/tests/functional/015
+++ b/tests/functional/015
@@ -12,38 +12,38 @@ _wait_for_sheep 2
_cluster_format -c 2
-$COLLIE vdi create test 539545600
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
+$DOG vdi create test 539545600
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
wait
echo "there should be 3 setattr errors"
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
wait
echo "there should be 8 setattr errors"
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
wait
echo "there should be 6 setattr errors"
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
-$COLLIE vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
+$DOG vdi setattr test lock 1 -x &
wait
echo "there should be 5 setattr errors"
diff --git a/tests/functional/016 b/tests/functional/016
index d52fd9c..92af8ef 100755
--- a/tests/functional/016
+++ b/tests/functional/016
@@ -11,23 +11,23 @@ done
_wait_for_sheep 3
_cluster_format -c 3
-$COLLIE vdi create base 100M -P
+$DOG vdi create base 100M -P
$QEMU_IMG snapshot -c tag sheepdog:base
sleep 1
-$COLLIE vdi clone -s 1 base test
+$DOG vdi clone -s 1 base test
sleep 1
-$COLLIE vdi delete test
+$DOG vdi delete test
sleep 1
-$COLLIE vdi delete base
+$DOG vdi delete base
sleep 1
-$COLLIE vdi delete -s 1 base
+$DOG vdi delete -s 1 base
sleep 3
echo there should be no vdi
diff --git a/tests/functional/017 b/tests/functional/017
index 30552f4..93e3d56 100755
--- a/tests/functional/017
+++ b/tests/functional/017
@@ -23,4 +23,4 @@ $QEMU_IMG snapshot -c tag2 sheepdog:test2
$QEMU_IO -c "write 0 512" sheepdog:test2:1 | _filter_qemu_io
$QEMU_IMG snapshot -c tag3 sheepdog:test2
-$COLLIE vdi tree | _filter_short_date
+$DOG vdi tree | _filter_short_date
diff --git a/tests/functional/018 b/tests/functional/018
index acec3c0..c0ab9ee 100755
--- a/tests/functional/018
+++ b/tests/functional/018
@@ -12,14 +12,14 @@ _wait_for_sheep "3"
_cluster_format -c 2
-$COLLIE vdi create test 4M
+$DOG vdi create test 4M
-_random | $COLLIE vdi write -w test
+_random | $DOG vdi write -w test
-$COLLIE vdi cache flush test
+$DOG vdi cache flush test
for port in `seq 0 2`; do
- $COLLIE vdi read test -p 700$port | md5sum > $STORE/csum.$port
+ $DOG vdi read test -p 700$port | md5sum > $STORE/csum.$port
done
for port in `seq 1 2`; do
diff --git a/tests/functional/019 b/tests/functional/019
index 7fc0921..efe8cb8 100755
--- a/tests/functional/019
+++ b/tests/functional/019
@@ -12,12 +12,12 @@ _wait_for_sheep "3"
_cluster_format -c 2
-$COLLIE vdi create test 4M
+$DOG vdi create test 4M
-_random | $COLLIE vdi write test
+_random | $DOG vdi write test
for port in `seq 0 2`; do
- $COLLIE vdi read test -p 700$port | md5sum > $STORE/csum.$port
+ $DOG vdi read test -p 700$port | md5sum > $STORE/csum.$port
done
for port in `seq 1 2`; do
diff --git a/tests/functional/020 b/tests/functional/020
index 53f1d20..77066bf 100755
--- a/tests/functional/020
+++ b/tests/functional/020
@@ -12,9 +12,9 @@ _wait_for_sheep "3"
_cluster_format -c 2
-$COLLIE vdi create test 40M
+$DOG vdi create test 40M
-_random | $COLLIE vdi write test
+_random | $DOG vdi write test
# check cache size, should be 20 * 80%
nr=`ls $STORE/0/cache/7c2b25 | wc -l`
diff --git a/tests/functional/022 b/tests/functional/022
index 6330dba..c2fe9f0 100755
--- a/tests/functional/022
+++ b/tests/functional/022
@@ -13,6 +13,6 @@ _wait_for_sheep "3"
_cluster_format -c 3
echo "creating a VDI should fail without data nodes available"
-$COLLIE vdi create test 100M
+$DOG vdi create test 100M
status=0
diff --git a/tests/functional/023 b/tests/functional/023
index 52e8281..dc3747f 100755
--- a/tests/functional/023
+++ b/tests/functional/023
@@ -10,7 +10,7 @@ done
_wait_for_sheep "1"
-$COLLIE cluster format -c 1
+$DOG cluster format -c 1
for i in `seq 1 9`; do
_start_sheep $i "-g"
@@ -21,7 +21,7 @@ _wait_for_sheep "10"
echo "comparing cluster info for all sheep. Should be the same"
for i in `seq 0 10`; do
- $COLLIE cluster info > $STORE/cinfo.$i
+ $DOG cluster info > $STORE/cinfo.$i
done
for i in `seq 1 10`; do
diff -u $STORE/cinfo.0 $STORE/cinfo.$i
diff --git a/tests/functional/024 b/tests/functional/024
index 9ef591d..87421a8 100755
--- a/tests/functional/024
+++ b/tests/functional/024
@@ -19,7 +19,7 @@ echo "formatting cluster"
_cluster_format -c 1
echo "creating vdi ${NAME}"
-$COLLIE vdi create ${VDI_NAME} ${VDI_SIZE}
+$DOG vdi create ${VDI_NAME} ${VDI_SIZE}
sleep 1
echo "filling ${VDI_NAME} with data"
diff --git a/tests/functional/025 b/tests/functional/025
index 2669888..2eb2f6d 100755
--- a/tests/functional/025
+++ b/tests/functional/025
@@ -23,7 +23,7 @@ echo "formatting cluster"
_cluster_format -c 2
echo "creating vdi ${NAME}"
-$COLLIE vdi create ${VDI_NAME} ${VDI_SIZE}
+$DOG vdi create ${VDI_NAME} ${VDI_SIZE}
echo "filling ${VDI_NAME} with data"
$QEMU_IO -c "write 0 ${VDI_SIZE}" sheepdog:${VDI_NAME} | _filter_qemu_io
@@ -40,5 +40,5 @@ _wait_for_sheep 4
echo "check that all sheep are alive"
for i in `seq 0 3`; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
diff --git a/tests/functional/026 b/tests/functional/026
index 94af215..bf62a6d 100755
--- a/tests/functional/026
+++ b/tests/functional/026
@@ -19,7 +19,7 @@ _cluster_format
# create new vdis
(
for i in `seq 0 40`;do
- $COLLIE vdi create test$i 4M
+ $DOG vdi create test$i 4M
done
) &
@@ -36,7 +36,7 @@ _wait_for_sheep_recovery 0
for i in `seq 1 5`; do _start_sheep $i;done
_wait_for_sheep 8
-# wait for collie to finish
+# wait for dog to finish
wait
-echo `$COLLIE vdi list | wc -l`
+echo `$DOG vdi list | wc -l`
diff --git a/tests/functional/027 b/tests/functional/027
index 455e300..e851e69 100755
--- a/tests/functional/027
+++ b/tests/functional/027
@@ -12,8 +12,8 @@ _wait_for_sheep "4"
_cluster_format -c 2
-$COLLIE vdi create test0 40M
-$COLLIE vdi create test1 40M
+$DOG vdi create test0 40M
+$DOG vdi create test1 40M
_kill_sheep 3
diff --git a/tests/functional/028 b/tests/functional/028
index 4b34db3..ff813c5 100755
--- a/tests/functional/028
+++ b/tests/functional/028
@@ -10,13 +10,13 @@ _wait_for_sheep 2
_cluster_format -c 2
-$COLLIE vdi create test 100M
+$DOG vdi create test 100M
for i in `seq 0 24`; do
- echo $i | $COLLIE vdi write test $((i * 4 * 1024 * 1024)) 512
+ echo $i | $DOG vdi write test $((i * 4 * 1024 * 1024)) 512
done
-$COLLIE vdi read test | md5sum
+$DOG vdi read test | md5sum
for i in 2 3; do
_start_sheep $i
@@ -27,10 +27,10 @@ done
# write different content
for i in `seq 0 24`; do
- echo $(($i+1)) | $COLLIE vdi write test $((i * 4 * 1024 * 1024)) 512 -p 7002
+ echo $(($i+1)) | $DOG vdi write test $((i * 4 * 1024 * 1024)) 512 -p 7002
done
-$COLLIE vdi read test -p 7002 | md5sum
+$DOG vdi read test -p 7002 | md5sum
for i in 2 3; do
_start_sheep $(($i-2))
@@ -39,11 +39,11 @@ for i in 2 3; do
_wait_for_sheep_recovery $(($i-2))
done
-$COLLIE vdi read test | md5sum
-$COLLIE vdi read test -p 7001 | md5sum
+$DOG vdi read test | md5sum
+$DOG vdi read test -p 7001 | md5sum
-$COLLIE vdi object test
+$DOG vdi object test
for i in `seq 0 24`; do
- $COLLIE vdi object -i $i test
+ $DOG vdi object -i $i test
done
diff --git a/tests/functional/029 b/tests/functional/029
index ab361f4..7101d5e 100755
--- a/tests/functional/029
+++ b/tests/functional/029
@@ -13,11 +13,11 @@ _wait_for_sheep 7
_cluster_format -c 3
for i in `seq 2 4`; do
- $COLLIE vdi create test$i 20M -c $i -P
+ $DOG vdi create test$i 20M -c $i -P
done
-$COLLIE vdi snapshot -s tag test2
-$COLLIE vdi clone -s 1 test2 clone -c 3
+$DOG vdi snapshot -s tag test2
+$DOG vdi clone -s 1 test2 clone -c 3
for i in `seq 2 3`; do
@@ -30,12 +30,12 @@ done
_wait_for_sheep_recovery 0
-$COLLIE vdi delete clone
-$COLLIE vdi delete -s 1 test2
+$DOG vdi delete clone
+$DOG vdi delete -s 1 test2
_vdi_list
for i in `seq 2 4`; do
- $COLLIE vdi object test$i -i 1;
+ $DOG vdi object test$i -i 1;
done
diff --git a/tests/functional/030 b/tests/functional/030
index 7e9daae..219f348 100755
--- a/tests/functional/030
+++ b/tests/functional/030
@@ -13,26 +13,26 @@ rm -rf $TMPDIR
_cluster_format -c 3
-$COLLIE vdi create test1 10M
-$COLLIE vdi create test2 10M
-
-_random | $COLLIE vdi write test1
-_random | $COLLIE vdi write test2
-$COLLIE vdi read test1 | md5sum > $STORE/csum.11.org
-$COLLIE vdi read test2 | md5sum > $STORE/csum.21.org
-$COLLIE vdi snapshot test1
-$COLLIE vdi snapshot test2
-$COLLIE cluster snapshot save s1 $TMPDIR
-$COLLIE cluster snapshot list $TMPDIR | _filter_date
-
-_random | $COLLIE vdi write test1
-_random | $COLLIE vdi write test2
-$COLLIE vdi read test1 | md5sum > $STORE/csum.12.org
-$COLLIE vdi read test2 | md5sum > $STORE/csum.22.org
-$COLLIE vdi snapshot test1
-$COLLIE vdi snapshot test2
-$COLLIE cluster snapshot save s2 $TMPDIR
-$COLLIE cluster snapshot list $TMPDIR | _filter_date
+$DOG vdi create test1 10M
+$DOG vdi create test2 10M
+
+_random | $DOG vdi write test1
+_random | $DOG vdi write test2
+$DOG vdi read test1 | md5sum > $STORE/csum.11.org
+$DOG vdi read test2 | md5sum > $STORE/csum.21.org
+$DOG vdi snapshot test1
+$DOG vdi snapshot test2
+$DOG cluster snapshot save s1 $TMPDIR
+$DOG cluster snapshot list $TMPDIR | _filter_date
+
+_random | $DOG vdi write test1
+_random | $DOG vdi write test2
+$DOG vdi read test1 | md5sum > $STORE/csum.12.org
+$DOG vdi read test2 | md5sum > $STORE/csum.22.org
+$DOG vdi snapshot test1
+$DOG vdi snapshot test2
+$DOG cluster snapshot save s2 $TMPDIR
+$DOG cluster snapshot list $TMPDIR | _filter_date
_vdi_list
@@ -43,11 +43,11 @@ done
_wait_for_sheep 4
_cluster_format -c 3
-$COLLIE cluster snapshot load s1 $TMPDIR
+$DOG cluster snapshot load s1 $TMPDIR
_vdi_list
-$COLLIE vdi read test1 | md5sum > $STORE/csum.11.new
-$COLLIE vdi read test2 | md5sum > $STORE/csum.21.new
+$DOG vdi read test1 | md5sum > $STORE/csum.11.new
+$DOG vdi read test2 | md5sum > $STORE/csum.21.new
diff -u $STORE/csum.11.org $STORE/csum.11.new
diff -u $STORE/csum.21.org $STORE/csum.21.new
@@ -57,7 +57,7 @@ for i in `seq 0 3`; do
done
_wait_for_sheep 4
-$COLLIE cluster snapshot load s2 $TMPDIR
+$DOG cluster snapshot load s2 $TMPDIR
_vdi_list
_cleanup
@@ -66,20 +66,20 @@ for i in `seq 0 3`; do
done
_wait_for_sheep 4
-$COLLIE cluster snapshot load 2 $TMPDIR
+$DOG cluster snapshot load 2 $TMPDIR
_vdi_list
-$COLLIE vdi read -s 2 test1 | md5sum > $STORE/csum.12.new
-$COLLIE vdi read -s 2 test2 | md5sum > $STORE/csum.22.new
+$DOG vdi read -s 2 test1 | md5sum > $STORE/csum.12.new
+$DOG vdi read -s 2 test2 | md5sum > $STORE/csum.22.new
diff -u $STORE/csum.12.org $STORE/csum.12.new
diff -u $STORE/csum.22.org $STORE/csum.22.new
-$COLLIE vdi read test1 | md5sum > $STORE/csum.12.new
-$COLLIE vdi read test2 | md5sum > $STORE/csum.22.new
+$DOG vdi read test1 | md5sum > $STORE/csum.12.new
+$DOG vdi read test2 | md5sum > $STORE/csum.22.new
diff -u $STORE/csum.12.org $STORE/csum.12.new
diff -u $STORE/csum.22.org $STORE/csum.22.new
-$COLLIE vdi read -s 1 test1 | md5sum > $STORE/csum.11.new
-$COLLIE vdi read -s 1 test2 | md5sum > $STORE/csum.21.new
+$DOG vdi read -s 1 test1 | md5sum > $STORE/csum.11.new
+$DOG vdi read -s 1 test2 | md5sum > $STORE/csum.21.new
diff -u $STORE/csum.11.org $STORE/csum.11.new
diff -u $STORE/csum.21.org $STORE/csum.21.new
diff --git a/tests/functional/031 b/tests/functional/031
index dcb6a42..93623ff 100755
--- a/tests/functional/031
+++ b/tests/functional/031
@@ -10,12 +10,12 @@ _wait_for_sheep 1
_cluster_format -c 1
for i in 1 2 3; do
- $COLLIE vdi create test$i ${i}00MB
+ $DOG vdi create test$i ${i}00MB
done
_vdi_list
-$COLLIE cluster shutdown
+$DOG cluster shutdown
_wait_for_sheep_stop
_start_sheep 0
diff --git a/tests/functional/032 b/tests/functional/032
index 691d360..467a402 100755
--- a/tests/functional/032
+++ b/tests/functional/032
@@ -12,13 +12,13 @@ _wait_for_sheep 8
_cluster_format
-$COLLIE vdi create test 100MB
+$DOG vdi create test 100MB
# create 25 objects
for i in `seq 0 24`; do
- echo $i | $COLLIE vdi write test $((i * 4 * 1024 * 1024)) 512
+ echo $i | $DOG vdi write test $((i * 4 * 1024 * 1024)) 512
done
-$COLLIE vdi read test | md5sum
+$DOG vdi read test | md5sum
for i in `seq 7 -1 0`; do
_wait_for_sheep_recovery 0
@@ -42,4 +42,4 @@ for i in `seq 0 24`; do
done
ls $STORE/*/obj/.stale | _filter_store | sort
-$COLLIE vdi read test | md5sum
+$DOG vdi read test | md5sum
diff --git a/tests/functional/033 b/tests/functional/033
index b5aa00e..d752c5d 100755
--- a/tests/functional/033
+++ b/tests/functional/033
@@ -12,13 +12,13 @@ _wait_for_sheep 8
_cluster_format
-$COLLIE vdi create test 100MB
+$DOG vdi create test 100MB
# create 25 objects
for i in `seq 0 24`; do
- echo $i | $COLLIE vdi write test $((i * 4 * 1024 * 1024)) 512
+ echo $i | $DOG vdi write test $((i * 4 * 1024 * 1024)) 512
done
-$COLLIE vdi read test | md5sum
+$DOG vdi read test | md5sum
# kill 7 nodes without waiting to finish recovery
for i in 7 6 5; do
@@ -53,4 +53,4 @@ for i in `seq 0 24`; do
done
ls $STORE/*/obj/.stale | _filter_store | sort
-$COLLIE vdi read test | md5sum
+$DOG vdi read test | md5sum
diff --git a/tests/functional/034 b/tests/functional/034
index c0ccab7..07caf5c 100755
--- a/tests/functional/034
+++ b/tests/functional/034
@@ -17,10 +17,10 @@ _wait_for_sheep 8
_cluster_format
-$COLLIE vdi create test 100MB
+$DOG vdi create test 100MB
# create 25 objects
for i in `seq 0 24`; do
- echo $i | $COLLIE vdi write test $((i * 4 * 1024 * 1024)) 512
+ echo $i | $DOG vdi write test $((i * 4 * 1024 * 1024)) 512
done
# kill 5 nodes
@@ -35,10 +35,10 @@ _wait_for_sheep 3
# update vdi
for i in `seq 0 24`; do
- echo $(($i + 100)) | $COLLIE vdi write test $((i * 4 * 1024 * 1024)) 512
+ echo $(($i + 100)) | $DOG vdi write test $((i * 4 * 1024 * 1024)) 512
done
-$COLLIE vdi read test | md5sum
+$DOG vdi read test | md5sum
# start 5 nodes who have old objects
for i in `seq 3 7`; do
@@ -48,5 +48,5 @@ done
_wait_for_sheep 8
for i in `seq 0 7`; do
- $COLLIE vdi read test -p 700$i | md5sum
+ $DOG vdi read test -p 700$i | md5sum
done
diff --git a/tests/functional/035 b/tests/functional/035
index dda4dd4..c1559e0 100755
--- a/tests/functional/035
+++ b/tests/functional/035
@@ -22,8 +22,8 @@ _wait_for_sheep 6
_cluster_format -c 3
-$COLLIE vdi create test 40M
-_random | $COLLIE vdi write test &
+$DOG vdi create test 40M
+_random | $DOG vdi write test &
sleep 3
# Test write timeout
@@ -31,14 +31,14 @@ for i in `seq 1 4`; do
_simulate_machine_down $i
done
-# wait for collie to finish
+# wait for dog to finish
wait
_wait_for_sheep_recovery 0
-$COLLIE vdi read test | md5sum > $STORE/csum.1
+$DOG vdi read test | md5sum > $STORE/csum.1
for i in `seq 0 9`; do
- $COLLIE vdi object -i $i test
+ $DOG vdi object -i $i test
done
for i in 6 7 8; do
@@ -48,7 +48,7 @@ done
_wait_for_sheep_recovery 0
# Test read timeout
-$COLLIE vdi read test | md5sum > $STORE/csum.2 &
+$DOG vdi read test | md5sum > $STORE/csum.2 &
for i in `seq 5 7`; do
_simulate_machine_down $i
done
diff --git a/tests/functional/036 b/tests/functional/036
index 36db7c9..dd440dd 100755
--- a/tests/functional/036
+++ b/tests/functional/036
@@ -9,7 +9,7 @@ for i in `seq 0 7`; do
done
while true; do
- $COLLIE cluster format 2> /dev/null
+ $DOG cluster format 2> /dev/null
if [ $? == 0 ]; then
break
fi
@@ -30,6 +30,6 @@ kill $pid > /dev/null 2>&1
_wait_for_sheep 8
for i in `seq 0 7`; do
- $COLLIE cluster info -p 700$i | head -1
- $COLLIE node list -p 700$i
+ $DOG cluster info -p 700$i | head -1
+ $DOG node list -p 700$i
done
diff --git a/tests/functional/037 b/tests/functional/037
index a4753c8..c203752 100755
--- a/tests/functional/037
+++ b/tests/functional/037
@@ -10,13 +10,13 @@ done
_wait_for_sheep 8
-$COLLIE cluster format &
+$DOG cluster format &
for i in `seq 5 7`; do
_kill_sheep $i
done
-# wait for collie to finish
+# wait for dog to finish
wait
for i in `seq 5 7`; do
@@ -26,6 +26,6 @@ done
_wait_for_sheep "8"
for i in `seq 0 7`; do
- $COLLIE cluster info -p 700$i | head -1
- $COLLIE node list -p 700$i
+ $DOG cluster info -p 700$i | head -1
+ $DOG node list -p 700$i
done
diff --git a/tests/functional/038 b/tests/functional/038
index 4b07ee1..0c62988 100755
--- a/tests/functional/038
+++ b/tests/functional/038
@@ -9,7 +9,7 @@ for i in `seq 0 7`; do
done
while true; do
- $COLLIE cluster format 2> /dev/null
+ $DOG cluster format 2> /dev/null
if [ $? == 0 ]; then
break
fi
@@ -21,7 +21,7 @@ for i in `seq 4 7`; do
_kill_sheep $i
done
-# wait for collie to finish
+# wait for dog to finish
for cnt in `seq 60`; do # wait at most 60 seconds
jobs 1 > /dev/null 2>&1
if [ $? != 0 ]; then
@@ -38,6 +38,6 @@ done
_wait_for_sheep "8"
for i in `seq 0 7`; do
- $COLLIE cluster info -p 700$i | head -1
- $COLLIE node list -p 700$i
+ $DOG cluster info -p 700$i | head -1
+ $DOG node list -p 700$i
done
diff --git a/tests/functional/039 b/tests/functional/039
index 74bf2e1..b7e1f57 100755
--- a/tests/functional/039
+++ b/tests/functional/039
@@ -11,46 +11,46 @@ done
_wait_for_sheep 5
_cluster_format
-$COLLIE vdi create test 4G
+$DOG vdi create test 4G
$QEMU_IO -c "write 0 512 -P 1" sheepdog:test | _filter_qemu_io
-$COLLIE vdi snapshot test -s snap1
+$DOG vdi snapshot test -s snap1
$QEMU_IO -c "write 0 512 -P 2" sheepdog:test | _filter_qemu_io
-echo yes | $COLLIE vdi rollback test -s snap1
+echo yes | $DOG vdi rollback test -s snap1
$QEMU_IO -c "read 0 512 -P 1" sheepdog:test | _filter_qemu_io
-$COLLIE vdi tree | _filter_short_date
+$DOG vdi tree | _filter_short_date
_vdi_list
$QEMU_IO -c "write 0 512 -P 2" sheepdog:test | _filter_qemu_io
-$COLLIE vdi snapshot test -s snap2
+$DOG vdi snapshot test -s snap2
$QEMU_IO -c "write 0 512 -P 3" sheepdog:test | _filter_qemu_io
-echo yes | $COLLIE vdi rollback test -s snap1
+echo yes | $DOG vdi rollback test -s snap1
$QEMU_IO -c "read 0 512 -P 1" sheepdog:test | _filter_qemu_io
-$COLLIE vdi tree | _filter_short_date
+$DOG vdi tree | _filter_short_date
_vdi_list
-echo yes | $COLLIE vdi rollback test -s snap2
+echo yes | $DOG vdi rollback test -s snap2
$QEMU_IO -c "read 0 512 -P 2" sheepdog:test | _filter_qemu_io
-$COLLIE vdi tree | _filter_short_date
+$DOG vdi tree | _filter_short_date
_vdi_list
-echo yes | $COLLIE vdi rollback test -s snap1
+echo yes | $DOG vdi rollback test -s snap1
$QEMU_IO -c "read 0 512 -P 1" sheepdog:test | _filter_qemu_io
-$COLLIE vdi tree | _filter_short_date
+$DOG vdi tree | _filter_short_date
_vdi_list
$QEMU_IO -c "write 0 512 -P 3" sheepdog:test | _filter_qemu_io
-$COLLIE vdi snapshot test -s snap3
+$DOG vdi snapshot test -s snap3
$QEMU_IO -c "write 0 512 -P 4" sheepdog:test | _filter_qemu_io
-$COLLIE vdi snapshot test -s snap4
+$DOG vdi snapshot test -s snap4
# these fail since the snap ids don't belong to snapshots
-echo yes | $COLLIE vdi rollback test -s 0
-echo yes | $COLLIE vdi rollback test -s 5
+echo yes | $DOG vdi rollback test -s 0
+echo yes | $DOG vdi rollback test -s 5
-echo yes | $COLLIE vdi rollback test -s snap3
+echo yes | $DOG vdi rollback test -s snap3
$QEMU_IO -c "read 0 512 -P 3" sheepdog:test | _filter_qemu_io
-$COLLIE vdi tree | _filter_short_date
+$DOG vdi tree | _filter_short_date
_vdi_list
diff --git a/tests/functional/040 b/tests/functional/040
index 2935226..77bbb61 100755
--- a/tests/functional/040
+++ b/tests/functional/040
@@ -10,7 +10,7 @@ _wait_for_sheep 1
_cluster_format -c 1
# create vdi in background
-$COLLIE vdi create test 4G &
+$DOG vdi create test 4G &
# the created vdi object will be move from sheep 0 to sheep 1
_start_sheep 1
diff --git a/tests/functional/041 b/tests/functional/041
index f72708d..6b9d87b 100755
--- a/tests/functional/041
+++ b/tests/functional/041
@@ -11,51 +11,51 @@ done
_wait_for_sheep 5
_cluster_format
-$COLLIE vdi create test 12M
+$DOG vdi create test 12M
# create the first object
-echo 0 | $COLLIE vdi write test 0 512
-$COLLIE vdi snapshot test -s snap1
+echo 0 | $DOG vdi write test 0 512
+$DOG vdi snapshot test -s snap1
# create the second object
-echo 1 | $COLLIE vdi write test $((4 * 1024 * 1024)) 512
-$COLLIE vdi snapshot test -s snap2
+echo 1 | $DOG vdi write test $((4 * 1024 * 1024)) 512
+$DOG vdi snapshot test -s snap2
# update the first object
-echo 2 | $COLLIE vdi write test 0 512
-$COLLIE vdi snapshot test -s snap3
+echo 2 | $DOG vdi write test 0 512
+$DOG vdi snapshot test -s snap3
# check vdis
_vdi_list
-$COLLIE vdi tree | _filter_short_date
+$DOG vdi tree | _filter_short_date
for i in `seq 1 3`; do
- $COLLIE vdi read test -s snap$i | md5sum
+ $DOG vdi read test -s snap$i | md5sum
done
# create backup files between snapshots
-$COLLIE vdi backup test -F snap1 -s snap2 > $STORE/backup.1.2
-$COLLIE vdi backup test -F snap1 -s snap3 > $STORE/backup.1.3
-$COLLIE vdi backup test -F snap2 -s snap3 > $STORE/backup.2.3
+$DOG vdi backup test -F snap1 -s snap2 > $STORE/backup.1.2
+$DOG vdi backup test -F snap1 -s snap3 > $STORE/backup.1.3
+$DOG vdi backup test -F snap2 -s snap3 > $STORE/backup.2.3
# restore backups
-$COLLIE vdi restore test -s snap1 < $STORE/backup.1.2
+$DOG vdi restore test -s snap1 < $STORE/backup.1.2
_vdi_list
-$COLLIE vdi tree | _filter_short_date
+$DOG vdi tree | _filter_short_date
-$COLLIE vdi restore test -s 4 < $STORE/backup.2.3
+$DOG vdi restore test -s 4 < $STORE/backup.2.3
_vdi_list
-$COLLIE vdi tree | _filter_short_date
+$DOG vdi tree | _filter_short_date
-$COLLIE vdi restore test -s snap1 < $STORE/backup.1.3
+$DOG vdi restore test -s snap1 < $STORE/backup.1.3
_vdi_list
-$COLLIE vdi tree | _filter_short_date
+$DOG vdi tree | _filter_short_date
-$COLLIE vdi restore test -s snap2 < $STORE/backup.2.3
+$DOG vdi restore test -s snap2 < $STORE/backup.2.3
_vdi_list
-$COLLIE vdi tree | _filter_short_date
+$DOG vdi tree | _filter_short_date
# check vdi contents
-$COLLIE vdi read test | md5sum
-for i in `seq 1 $($COLLIE vdi list | grep "^s " | wc -l)`; do
- $COLLIE vdi read test -s $i | md5sum
+$DOG vdi read test | md5sum
+for i in `seq 1 $($DOG vdi list | grep "^s " | wc -l)`; do
+ $DOG vdi read test -s $i | md5sum
done
diff --git a/tests/functional/042 b/tests/functional/042
index df706a1..54e8a33 100755
--- a/tests/functional/042
+++ b/tests/functional/042
@@ -25,8 +25,8 @@ _wait_for_sheep 4
_cluster_format
# create two VDIs before there are enough spaces
-$COLLIE vdi create test0 100M
-$COLLIE vdi create test1 100M
+$DOG vdi create test0 100M
+$DOG vdi create test1 100M
# make sheep 0 and 1 disk full
dd if=/dev/zero of=$STORE/2/zero > /dev/null 2>&1
@@ -34,16 +34,16 @@ dd if=/dev/zero of=$STORE/3/zero > /dev/null 2>&1
# test data write against disk-full cluster
for i in `seq 0 10`; do
- echo $i | $COLLIE vdi write test0 $((i * 4 * 1024 * 1024)) 512 -p 7000
- echo $i | $COLLIE vdi write test1 $((i * 4 * 1024 * 1024)) 512 -p 7002
+ echo $i | $DOG vdi write test0 $((i * 4 * 1024 * 1024)) 512 -p 7000
+ echo $i | $DOG vdi write test1 $((i * 4 * 1024 * 1024)) 512 -p 7002
done
# test vdi creation against disk-full cluster
-$COLLIE vdi create test2 100M -p 7000
-$COLLIE vdi create test3 100M -p 7002
+$DOG vdi create test2 100M -p 7000
+$DOG vdi create test3 100M -p 7002
for i in `seq 0 3`; do
- $COLLIE node list -p 700$i
+ $DOG node list -p 700$i
done
_node_info
ls $STORE/*/obj/* | _filter_store | sort
diff --git a/tests/functional/043 b/tests/functional/043
index 2a59a4e..d336cf5 100755
--- a/tests/functional/043
+++ b/tests/functional/043
@@ -12,43 +12,43 @@ _wait_for_sheep 5
_cluster_format
-$COLLIE vdi create test 40M
+$DOG vdi create test 40M
for i in `seq 0 10`; do
- echo $i | $COLLIE vdi write test $((i * 4 * 1024 * 1024)) 512
+ echo $i | $DOG vdi write test $((i * 4 * 1024 * 1024)) 512
done
for i in 0 1 2 3 4; do
- $COLLIE vdi read test -p 700$i | md5sum
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG vdi read test -p 700$i | md5sum
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
# remove obj directory to occur EIO
_safe_remove $STORE/4/obj
for i in `seq 0 10`; do
- echo $(($i + 100)) | $COLLIE vdi write test $((i * 4 * 1024 * 1024)) 512
+ echo $(($i + 100)) | $DOG vdi write test $((i * 4 * 1024 * 1024)) 512
done
for i in 0 1 2 3 4; do
- $COLLIE vdi read test -p 700$i | md5sum
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG vdi read test -p 700$i | md5sum
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
# check whether sheep 4 can receive confchg event
_kill_sheep 3
for i in `seq 0 10`; do
- echo $(($i + 200)) | $COLLIE vdi write test $((i * 4 * 1024 * 1024)) 512
+ echo $(($i + 200)) | $DOG vdi write test $((i * 4 * 1024 * 1024)) 512
done
for i in 0 1 2 4; do
- $COLLIE vdi read test -p 700$i | md5sum
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG vdi read test -p 700$i | md5sum
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
# check whether sheep 4 can receive notify event
-$COLLIE vdi create test2 20M
+$DOG vdi create test2 20M
for i in 0 1 2 4; do
_vdi_list -p 700$i
@@ -56,4 +56,4 @@ done
# check whether we can write to a gateway after EIO
_safe_remove $STORE/0/obj
-echo hello | $COLLIE vdi write test 0 512
+echo hello | $DOG vdi write test 0 512
diff --git a/tests/functional/044 b/tests/functional/044
index 75a427c..fc5d8be 100755
--- a/tests/functional/044
+++ b/tests/functional/044
@@ -11,55 +11,55 @@ done
_wait_for_sheep 3
_cluster_format
-$COLLIE vdi create base1 20M -p 7000
-$COLLIE vdi create base2 20M -p 7001
-$COLLIE vdi create base3 20M -p 7002
+$DOG vdi create base1 20M -p 7000
+$DOG vdi create base2 20M -p 7001
+$DOG vdi create base3 20M -p 7002
for i in `seq 0 4`; do
- echo $i | $COLLIE vdi write base1 $((i * 4 * 1024 * 1024)) 512
+ echo $i | $DOG vdi write base1 $((i * 4 * 1024 * 1024)) 512
done &
for i in `seq 0 4`; do
- echo $i | $COLLIE vdi write base2 $((i * 4 * 1024 * 1024)) 512
+ echo $i | $DOG vdi write base2 $((i * 4 * 1024 * 1024)) 512
done &
for i in `seq 0 4`; do
- echo $i | $COLLIE vdi write base3 $((i * 4 * 1024 * 1024)) 512
+ echo $i | $DOG vdi write base3 $((i * 4 * 1024 * 1024)) 512
done &
wait
-$COLLIE vdi snapshot -s snap0 base1 -p 7000
-$COLLIE vdi snapshot -s snap0 base2 -p 7001
-$COLLIE vdi snapshot -s snap0 base3 -p 7002
+$DOG vdi snapshot -s snap0 base1 -p 7000
+$DOG vdi snapshot -s snap0 base2 -p 7001
+$DOG vdi snapshot -s snap0 base3 -p 7002
sleep 1
for i in `seq 1 10`; do
- $COLLIE vdi snapshot -s snap$i base1 -p 7000
- $COLLIE vdi delete -s snap$(($i - 1)) base1 -p 7000
+ $DOG vdi snapshot -s snap$i base1 -p 7000
+ $DOG vdi delete -s snap$(($i - 1)) base1 -p 7000
sleep 1
done &
for i in `seq 1 10`; do
- $COLLIE vdi snapshot -s snap$i base2 -p 7001
- $COLLIE vdi delete -s snap$(($i - 1)) base2 -p 7001
+ $DOG vdi snapshot -s snap$i base2 -p 7001
+ $DOG vdi delete -s snap$(($i - 1)) base2 -p 7001
sleep 1
done &
for i in `seq 1 10`; do
- $COLLIE vdi snapshot -s snap$i base3 -p 7002
- $COLLIE vdi delete -s snap$(($i - 1)) base3 -p 7002
+ $DOG vdi snapshot -s snap$i base3 -p 7002
+ $DOG vdi delete -s snap$(($i - 1)) base3 -p 7002
sleep 1
done &
wait
-$COLLIE vdi delete base1 -p 7000
-$COLLIE vdi delete base2 -p 7001
-$COLLIE vdi delete base3 -p 7002
-$COLLIE vdi delete -s snap10 base1 -p 7000
-$COLLIE vdi delete -s snap10 base2 -p 7001
-$COLLIE vdi delete -s snap10 base3 -p 7002
+$DOG vdi delete base1 -p 7000
+$DOG vdi delete base2 -p 7001
+$DOG vdi delete base3 -p 7002
+$DOG vdi delete -s snap10 base1 -p 7000
+$DOG vdi delete -s snap10 base2 -p 7001
+$DOG vdi delete -s snap10 base3 -p 7002
echo there should be no vdi
_vdi_list
diff --git a/tests/functional/045 b/tests/functional/045
index d8f6583..530af28 100755
--- a/tests/functional/045
+++ b/tests/functional/045
@@ -11,14 +11,14 @@ done
_wait_for_sheep 3
_cluster_format -c 2
-$COLLIE vdi create test 4M
+$DOG vdi create test 4M
for i in `seq 0 7`; do
- echo $i | $COLLIE vdi write test $(($i * 1536 + 512)) 512
+ echo $i | $DOG vdi write test $(($i * 1536 + 512)) 512
done
for i in `seq 0 7`; do
- $COLLIE vdi read test $(($i * 1536 + 512)) 512 | md5sum
+ $DOG vdi read test $(($i * 1536 + 512)) 512 | md5sum
done
-$COLLIE vdi read test | md5sum
+$DOG vdi read test | md5sum
diff --git a/tests/functional/046 b/tests/functional/046
index 84b2a21..9d58658 100755
--- a/tests/functional/046
+++ b/tests/functional/046
@@ -13,27 +13,27 @@ _wait_for_sheep 3
_cluster_format -c 2
echo "delete snapshot image before current one"
-$COLLIE vdi create test 4G
-$COLLIE vdi snapshot test -s snap
+$DOG vdi create test 4G
+$DOG vdi snapshot test -s snap
_vdi_list
-$COLLIE vdi delete test -s snap
-$COLLIE vdi delete test -s snap # error
+$DOG vdi delete test -s snap
+$DOG vdi delete test -s snap # error
_vdi_list
-$COLLIE vdi delete test
-$COLLIE vdi delete test # error
+$DOG vdi delete test
+$DOG vdi delete test # error
_vdi_list
echo "delete current image before snapshot one"
-$COLLIE vdi create test 4G
-$COLLIE vdi snapshot test -s snap
+$DOG vdi create test 4G
+$DOG vdi snapshot test -s snap
_vdi_list
-$COLLIE vdi delete test
-$COLLIE vdi delete test # error
+$DOG vdi delete test
+$DOG vdi delete test # error
_vdi_list
-$COLLIE vdi delete test -s snap
-$COLLIE vdi delete test -s snap # error
+$DOG vdi delete test -s snap
+$DOG vdi delete test -s snap # error
_vdi_list
diff --git a/tests/functional/047 b/tests/functional/047
index feda20b..675f74e 100755
--- a/tests/functional/047
+++ b/tests/functional/047
@@ -10,11 +10,11 @@ _wait_for_sheep 1
_cluster_format -c 1
-$COLLIE vdi create test 4G
+$DOG vdi create test 4G
# write something to vdi 'test'
-echo "hello" | $COLLIE vdi write test 0 512
-echo "sheepdog" | $COLLIE vdi write test 4M 512
+echo "hello" | $DOG vdi write test 0 512
+echo "sheepdog" | $DOG vdi write test 4M 512
# corrupt the vdi...
_kill_sheep 0
if $MD; then
@@ -32,7 +32,7 @@ _wait_for_sheep 1
sleep 3
_vdi_list
-$COLLIE vdi read test 0 512 | tr -d [:cntrl:]
+$DOG vdi read test 0 512 | tr -d [:cntrl:]
echo -n ' '
-$COLLIE vdi read test 4M 512 | tr -d [:cntrl:]
+$DOG vdi read test 4M 512 | tr -d [:cntrl:]
echo ''
diff --git a/tests/functional/048 b/tests/functional/048
index b44819e..c487704 100755
--- a/tests/functional/048
+++ b/tests/functional/048
@@ -1,6 +1,6 @@
#!/bin/bash
-# Test some collie commands
+# Test some dog commands
. ./common
@@ -12,14 +12,14 @@ _wait_for_sheep 3
_cluster_format
-$COLLIE vdi create test 1G
+$DOG vdi create test 1G
-echo hello | $COLLIE vdi write test 4M 512
+echo hello | $DOG vdi write test 4M 512
# kill the master gracefully
-$COLLIE node kill 0
+$DOG node kill 0
sleep 2
_wait_for_sheep_recovery 1
-$COLLIE node list -p 7001
+$DOG node list -p 7001
nr=2
for i in 3 4 0; do
@@ -29,12 +29,12 @@ for i in 3 4 0; do
done
_wait_for_sheep_recovery 0
-$COLLIE vdi track test
-$COLLIE vdi track -i 1 test
+$DOG vdi track test
+$DOG vdi track -i 1 test
_vdi_list test
-$COLLIE vdi list -r test | awk '{$7="MASKED";print $0}'
+$DOG vdi list -r test | awk '{$7="MASKED";print $0}'
-$COLLIE vdi check test
+$DOG vdi check test
# clear the 'first' data block
dd if=/dev/zero of=$STORE/0/obj/007c2b2500000001 bs=1M count=4 > /dev/null 2>&1
-$COLLIE vdi check test | sort | uniq
+$DOG vdi check test | sort | uniq
diff --git a/tests/functional/049 b/tests/functional/049
index bcc1025..d466130 100755
--- a/tests/functional/049
+++ b/tests/functional/049
@@ -12,10 +12,10 @@ _wait_for_sheep 3
_cluster_format -c 1
-$COLLIE vdi create test 20M
-_random | $COLLIE vdi write -w test
+$DOG vdi create test 20M
+_random | $DOG vdi write -w test
-$COLLIE cluster shutdown
+$DOG cluster shutdown
_wait_for_sheep_stop
#trigger an object reclaim at startup
diff --git a/tests/functional/050 b/tests/functional/050
index a44fb8a..8a35c59 100755
--- a/tests/functional/050
+++ b/tests/functional/050
@@ -22,14 +22,14 @@ _wait_for_sheep 3
_cluster_format
-$COLLIE vdi create test 100M
-dd if=/dev/zero | $COLLIE vdi write test &
+$DOG vdi create test 100M
+dd if=/dev/zero | $DOG vdi write test &
# simulate IO NIC down of sheep 1
iptables -A INPUT -p tcp --sport 8001 -j DROP
iptables -A INPUT -p tcp --dport 8001 -j DROP
-# wait for collie to finish
+# wait for dog to finish
wait
# Logger flush in 1 second internval. We need assure log is flushed.
sleep 1
@@ -37,6 +37,6 @@ sleep 1
if [ "`grep fallback $STORE/0/sheep.log`" ];then
echo fallback done
fi
-$COLLIE vdi check test
+$DOG vdi check test
status=0
diff --git a/tests/functional/051 b/tests/functional/051
index c2c96c6..b128660 100755
--- a/tests/functional/051
+++ b/tests/functional/051
@@ -9,12 +9,12 @@ for i in 0 1; do
done
_wait_for_sheep 2
_cluster_format
-$COLLIE cluster info | _filter_cluster_info
+$DOG cluster info | _filter_cluster_info
_start_sheep 2
_wait_for_sheep 3
-$COLLIE cluster info | _filter_cluster_info
+$DOG cluster info | _filter_cluster_info
_kill_sheep 2
_wait_for_sheep 2
-$COLLIE cluster info | _filter_cluster_info
+$DOG cluster info | _filter_cluster_info
diff --git a/tests/functional/052 b/tests/functional/052
index 679a698..bff9d52 100755
--- a/tests/functional/052
+++ b/tests/functional/052
@@ -9,10 +9,10 @@ for i in 0 1 2 3; do
done
_wait_for_sheep 4
_cluster_format
-$COLLIE vdi create test 20M -P
-$COLLIE cluster info | _filter_cluster_info
+$DOG vdi create test 20M -P
+$DOG cluster info | _filter_cluster_info
-$COLLIE cluster shutdown
+$DOG cluster shutdown
_wait_for_sheep_stop
for i in 0 1 2 4; do
@@ -20,24 +20,24 @@ for i in 0 1 2 4; do
done
_wait_for_sheep 4
for i in 0 1 2 4; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
_vdi_list
done
-echo yes | $COLLIE cluster recover force
+echo yes | $DOG cluster recover force
echo ""
_wait_for_sheep_recovery 0
-$COLLIE vdi check test | sort
+$DOG vdi check test | sort
for i in 0 1 2 4; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
_vdi_list
done
_start_sheep 3
_wait_for_sheep 5
for i in 0 1 2 3 4; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
_vdi_list
done
diff --git a/tests/functional/053 b/tests/functional/053
index 3874a7e..be2dd36 100755
--- a/tests/functional/053
+++ b/tests/functional/053
@@ -14,9 +14,9 @@ _wait_for_sheep 4
_cluster_format -c 2
for i in 0 1 2 3; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
-$COLLIE cluster shutdown
+$DOG cluster shutdown
_wait_for_sheep_stop
_start_sheep 0 -g
@@ -27,7 +27,7 @@ _start_sheep 2
_start_sheep 3
_wait_for_sheep 4
for i in 0 1 2 3; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
_start_sheep 4
@@ -35,7 +35,7 @@ _wait_for_sheep 5
_start_sheep 5
_wait_for_sheep 6
for i in 0 1 2 3 4 5; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
_kill_sheep 3
@@ -43,5 +43,5 @@ _wait_for_sheep 5
_kill_sheep 4
_wait_for_sheep 4
for i in 0 1 2 5; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
diff --git a/tests/functional/054 b/tests/functional/054
index 5ecbc41..3b28bae 100755
--- a/tests/functional/054
+++ b/tests/functional/054
@@ -17,15 +17,15 @@ done
_wait_for_sheep 3
_cluster_format
-$COLLIE vdi create test 100M -P
-$COLLIE cluster info | _filter_cluster_info
+$DOG vdi create test 100M -P
+$DOG cluster info | _filter_cluster_info
#start recovery
_start_sheep 3
_wait_for_sheep 4
_wait_for_sheep_recovery 0
-$COLLIE cluster info | _filter_cluster_info
+$DOG cluster info | _filter_cluster_info
#test no object in .stale
ls $STORE/*/*/.stale | grep ^- | wc -l
diff --git a/tests/functional/055 b/tests/functional/055
index 0e78e2a..ac54011 100755
--- a/tests/functional/055
+++ b/tests/functional/055
@@ -11,34 +11,34 @@ for i in 0 1 2; do
done
_wait_for_sheep 3
_cluster_format -c 2
-$COLLIE vdi create test 200M -P
+$DOG vdi create test 200M -P
# simulate one disk failure
_safe_remove $STORE/0/d0
-_random | $COLLIE vdi write test
+_random | $DOG vdi write test
_wait_for_sheep_recovery 0
-$COLLIE vdi check test
-$COLLIE cluster info | _filter_cluster_info
+$DOG vdi check test
+$DOG cluster info | _filter_cluster_info
# simulate multiple disk failure
_safe_remove $STORE/1/d0
-_random | $COLLIE vdi write test &
+_random | $DOG vdi write test &
sleep 1
_safe_remove $STORE/1/d1
_wait_for_sheep_recovery 0
wait
-$COLLIE vdi check test
-$COLLIE cluster info | _filter_cluster_info
+$DOG vdi check test
+$DOG cluster info | _filter_cluster_info
# simulate all disks failure
_safe_remove $STORE/1/d2
-_random | $COLLIE vdi write test
-$COLLIE vdi check test
-$COLLIE cluster info | _filter_cluster_info
+_random | $DOG vdi write test
+$DOG vdi check test
+$DOG cluster info | _filter_cluster_info
# simulate simultaneous multiple disks failure
_safe_remove $STORE/2/d0
_safe_remove $STORE/2/d1
-dd if=/dev/zero | $COLLIE vdi write test
-$COLLIE vdi check test
-$COLLIE cluster info | _filter_cluster_info
+dd if=/dev/zero | $DOG vdi write test
+$DOG vdi check test
+$DOG cluster info | _filter_cluster_info
diff --git a/tests/functional/056 b/tests/functional/056
index d2b1ebc..9530a6d 100755
--- a/tests/functional/056
+++ b/tests/functional/056
@@ -11,28 +11,28 @@ for i in 0 1 2; do
done
_wait_for_sheep 3
_cluster_format
-$COLLIE vdi create test 200M -P
+$DOG vdi create test 200M -P
# node event after disk failure
_safe_remove $STORE/0/d0
-_random | $COLLIE vdi write test &
+_random | $DOG vdi write test &
sleep 1
_start_sheep 3
_wait_for_sheep 4
_wait_for_sheep_recovery 0
-wait # collie
-$COLLIE vdi check test
-$COLLIE cluster info | _filter_cluster_info
+wait # dog
+$DOG vdi check test
+$DOG cluster info | _filter_cluster_info
# disk failures after node event
_safe_remove $STORE/1/d0
-dd if=/dev/zero | $COLLIE vdi write test &
+dd if=/dev/zero | $DOG vdi write test &
sleep 1
_kill_sheep 2
_wait_for_sheep 3
_safe_remove $STORE/1/d1
_wait_for_sheep_recovery 0
-wait # collie
-$COLLIE vdi check test
-$COLLIE cluster info | _filter_cluster_info
+wait # dog
+$DOG vdi check test
+$DOG cluster info | _filter_cluster_info
diff --git a/tests/functional/057 b/tests/functional/057
index ab47ffc..d1c95f5 100755
--- a/tests/functional/057
+++ b/tests/functional/057
@@ -15,36 +15,36 @@ for i in 0 1 2; do
done
_wait_for_sheep 3
_cluster_format
-$COLLIE vdi create test 100M -P
+$DOG vdi create test 100M -P
_md_info
# plug during node event
_start_sheep 3
_wait_for_sheep 4
-$COLLIE node md plug $STORE/0/d3,$STORE/0/d4
+$DOG node md plug $STORE/0/d3,$STORE/0/d4
_wait_for_sheep_recovery 0
_md_info
-$COLLIE vdi check test
-$COLLIE cluster info | _filter_cluster_info
+$DOG vdi check test
+$DOG cluster info | _filter_cluster_info
# plug duplicate path
-$COLLIE node md plug $STORE/0/d3
-$COLLIE node recovery
+$DOG node md plug $STORE/0/d3
+$DOG node recovery
_md_info
# unplug
-$COLLIE node md unplug $STORE/0/d0,$STORE/0/d1
+$DOG node md unplug $STORE/0/d0,$STORE/0/d1
_wait_for_sheep_recovery 0
_md_info
-$COLLIE vdi check test
-$COLLIE cluster info | _filter_cluster_info
+$DOG vdi check test
+$DOG cluster info | _filter_cluster_info
# unplug invalid path
-$COLLIE node md unplug $STORE/0/d0
-$COLLIE node recovery
+$DOG node md unplug $STORE/0/d0
+$DOG node recovery
_md_info
-$COLLIE cluster info | _filter_cluster_info
+$DOG cluster info | _filter_cluster_info
# check stale object purging
find $STORE/*/d*/.stale/ -type f | _filter_store
diff --git a/tests/functional/058 b/tests/functional/058
index 53393c0..ea584de 100755
--- a/tests/functional/058
+++ b/tests/functional/058
@@ -8,11 +8,11 @@ for i in 0 1 2; do
done
_wait_for_sheep 3
_cluster_format
-$COLLIE vdi create test 100M
-dd if=/dev/zero | $COLLIE vdi write -w test
+$DOG vdi create test 100M
+dd if=/dev/zero | $DOG vdi write -w test
$QEMU_IO -c "discard 0 100m" sheepdog:test | _filter_qemu_io
-$COLLIE vdi check test
+$DOG vdi check test
for i in `seq 0 24`; do
- $COLLIE vdi object test -i $i;
+ $DOG vdi object test -i $i;
done
_node_info
diff --git a/tests/functional/059 b/tests/functional/059
index 3c133ec..b719a58 100755
--- a/tests/functional/059
+++ b/tests/functional/059
@@ -11,14 +11,14 @@ done
_wait_for_sheep 3
_cluster_format -c 3
-$COLLIE vdi create test 4M
+$DOG vdi create test 4M
_input()
{
for i in `seq 1 10`; do
echo "multiwrite -P $i 0 1k ; 2k 1k ; 4k 1k ; 8k 1k"
sleep 1
- $COLLIE vdi snapshot test -s snap$i
+ $DOG vdi snapshot test -s snap$i
done
echo quit
@@ -27,8 +27,8 @@ _input()
_input | $QEMU_IO sheepdog:test > /dev/null
_vdi_list
-$COLLIE vdi tree | _filter_short_date
+$DOG vdi tree | _filter_short_date
for i in `seq 1 10`; do
- $COLLIE vdi read test -s snap$i | md5sum
+ $DOG vdi read test -s snap$i | md5sum
done
diff --git a/tests/functional/060 b/tests/functional/060
index b5c1384..fb6bc31 100755
--- a/tests/functional/060
+++ b/tests/functional/060
@@ -1,6 +1,6 @@
#!/bin/bash
-# Test reboot sheepdog without collie shutdown
+# Test reboot sheepdog without dog shutdown
. ./common
for i in `seq 0 7`; do
@@ -12,19 +12,19 @@ _wait_for_sheep 8
_cluster_format
for i in `seq 0 3`; do
- $COLLIE vdi create test$i 100M
+ $DOG vdi create test$i 100M
for j in `seq 0 24`; do
- echo "$i $j" | $COLLIE vdi write test$i $(($j * 4 * 1024 ** 2)) 512
+ echo "$i $j" | $DOG vdi write test$i $(($j * 4 * 1024 ** 2)) 512
done &
done
wait
for i in `seq 0 3`; do
- $COLLIE vdi read test$i | md5sum
+ $DOG vdi read test$i | md5sum
done
-_reboot_without_collie_shutdown()
+_reboot_without_dog_shutdown()
{
local i
for i in `seq 0 7`; do
@@ -41,14 +41,14 @@ _reboot_without_collie_shutdown()
}
for i in 0 1 2; do
- _reboot_without_collie_shutdown
+ _reboot_without_dog_shutdown
done
for i in `seq 0 7`; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info > $STORE/cinfo.$i
+ $DOG cluster info -p 700$i | _filter_cluster_info > $STORE/cinfo.$i
_vdi_list -p 700$i
for j in `seq 0 3`; do
- $COLLIE vdi read test$j -p 700$i | md5sum > $STORE/csum.$i.$j &
+ $DOG vdi read test$j -p 700$i | md5sum > $STORE/csum.$i.$j &
done
wait
for j in `seq 0 3`; do
diff --git a/tests/functional/061 b/tests/functional/061
index 26b8daf..5e03ba0 100755
--- a/tests/functional/061
+++ b/tests/functional/061
@@ -12,11 +12,11 @@ _wait_for_sheep 3
_cluster_format -c 1
-$COLLIE vdi create test 40M -P
+$DOG vdi create test 40M -P
_kill_sheep 2
_wait_for_sheep_recovery 0
_start_sheep 2
_wait_for_sheep_recovery 0
-$COLLIE vdi check test
+$DOG vdi check test
diff --git a/tests/functional/062 b/tests/functional/062
index 6bd84ee..5133287 100755
--- a/tests/functional/062
+++ b/tests/functional/062
@@ -1,6 +1,6 @@
#!/bin/bash
-# Test unaligned collie vdi read/write
+# Test unaligned dog vdi read/write
. ./common
@@ -12,21 +12,21 @@ _wait_for_sheep 3
_cluster_format
-$COLLIE vdi create test 1234
+$DOG vdi create test 1234
sleep 1
-$COLLIE vdi list -r test | awk '{$7="MASKED";print $0}'
-
-echo hello | $COLLIE vdi write test 1 6
-$COLLIE vdi read test 1 6
-echo world | $COLLIE vdi write test 1 6
-$COLLIE vdi read test 1 6
-
-echo h*** | $COLLIE vdi write test 510 512
-echo h!!! | $COLLIE vdi write test 510 512
-$COLLIE vdi read test 510 5
-echo ^^ | $COLLIE vdi write test 511 2
-$COLLIE vdi read test 510 5
-echo xxx | $COLLIE vdi write test 1020 4
-$COLLIE vdi read test 1020 4
-$COLLIE vdi read test 510 5
-$COLLIE vdi read test 1 6
+$DOG vdi list -r test | awk '{$7="MASKED";print $0}'
+
+echo hello | $DOG vdi write test 1 6
+$DOG vdi read test 1 6
+echo world | $DOG vdi write test 1 6
+$DOG vdi read test 1 6
+
+echo h*** | $DOG vdi write test 510 512
+echo h!!! | $DOG vdi write test 510 512
+$DOG vdi read test 510 5
+echo ^^ | $DOG vdi write test 511 2
+$DOG vdi read test 510 5
+echo xxx | $DOG vdi write test 1020 4
+$DOG vdi read test 1020 4
+$DOG vdi read test 510 5
+$DOG vdi read test 1 6
diff --git a/tests/functional/063 b/tests/functional/063
index b43f374..8a648c6 100755
--- a/tests/functional/063
+++ b/tests/functional/063
@@ -20,17 +20,17 @@ _start_sheep 3 "-g"
_wait_for_sheep 4
_cluster_format -c 1
-$COLLIE vdi create test 200M -P
+$DOG vdi create test 200M -P
_node_info
-$COLLIE node list
+$DOG node list
-$COLLIE node md plug $STORE/4
+$DOG node md plug $STORE/4
_wait_for_sheep_recovery 0
-$COLLIE cluster reweight
+$DOG cluster reweight
_start_sheep 5
_wait_for_sheep 5
_wait_for_sheep_recovery 0
_node_info
-$COLLIE node list
-$COLLIE cluster info | _filter_cluster_info
+$DOG node list
+$DOG cluster info | _filter_cluster_info
diff --git a/tests/functional/064 b/tests/functional/064
index 77304fe..3a6f168 100755
--- a/tests/functional/064
+++ b/tests/functional/064
@@ -17,25 +17,25 @@ done
_wait_for_sheep 3
_cluster_format -c 2
-$COLLIE vdi create test 100M -P
+$DOG vdi create test 100M -P
_node_info
-$COLLIE node list
+$DOG node list
-$COLLIE node md plug $STORE/3
+$DOG node md plug $STORE/3
_wait_for_sheep_recovery 0
_node_info
-$COLLIE node list
+$DOG node list
-$COLLIE cluster reweight
+$DOG cluster reweight
# restart sheep1 while reweighting
_kill_sheep 2
_wait_for_sheep_recovery 0
_node_info | grep -v ^2 # the content of sheep 2 is non-deterministic
-$COLLIE node list
+$DOG node list
_start_sheep 2
_wait_for_sheep_recovery 0
_node_info
-$COLLIE node list
-$COLLIE cluster info | _filter_cluster_info
+$DOG node list
+$DOG cluster info | _filter_cluster_info
diff --git a/tests/functional/065 b/tests/functional/065
index 388d7e8..e0ee1ae 100755
--- a/tests/functional/065
+++ b/tests/functional/065
@@ -11,16 +11,16 @@ done
_wait_for_sheep 2
_cluster_format -c 2
-$COLLIE vdi create t 1G -P
+$DOG vdi create t 1G -P
# move objects into stale directory
_kill_sheep 0
_start_sheep 0 "-w size=400"
_wait_for_sheep 2
-dd if=/dev/zero | $COLLIE vdi write -w t &
+dd if=/dev/zero | $DOG vdi write -w t &
_wait_for_sheep_recovery 1
wait
-$COLLIE cluster info | _filter_cluster_info
+$DOG cluster info | _filter_cluster_info
diff --git a/tests/functional/066 b/tests/functional/066
index 1a36492..97f0b9f 100755
--- a/tests/functional/066
+++ b/tests/functional/066
@@ -11,13 +11,13 @@ done
_wait_for_sheep 3
_cluster_format -c 2
-$COLLIE vdi create t 300M -P
-$COLLIE vdi create t0 300M -P
-$COLLIE vdi create t1 300M -P
+$DOG vdi create t 300M -P
+$DOG vdi create t0 300M -P
+$DOG vdi create t1 300M -P
-dd if=/dev/zero | $COLLIE vdi write -w t &
+dd if=/dev/zero | $DOG vdi write -w t &
for j in 0 1; do
- dd if=/dev/zero | $COLLIE vdi write -w t$j -p 700$j &
+ dd if=/dev/zero | $DOG vdi write -w t$j -p 700$j &
done
for i in `seq 3 7`; do
@@ -30,5 +30,5 @@ done
wait
for i in 0 1 7; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
diff --git a/tests/functional/067 b/tests/functional/067
index c47d387..8b309ef 100755
--- a/tests/functional/067
+++ b/tests/functional/067
@@ -12,7 +12,7 @@ _wait_for_sheep 3
_cluster_format
-$COLLIE node list
+$DOG node list
# make sure sheep1 and sheep2 quit simutaniously
_kill_sheep 1 &
@@ -33,5 +33,5 @@ sleep 1
echo check whether all nodes have the same cluster info
for i in 1 2; do
- $COLLIE node list -p 700$i
+ $DOG node list -p 700$i
done
diff --git a/tests/functional/068 b/tests/functional/068
index 28afe4e..7d53d63 100755
--- a/tests/functional/068
+++ b/tests/functional/068
@@ -10,7 +10,7 @@ done
_wait_for_sheep 3
-$COLLIE cluster format
+$DOG cluster format
sleep 1
# kill a non-master sheep
@@ -26,10 +26,10 @@ _kill_zk_session 0
sleep 5
for i in 0 1 2; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
-$COLLIE vdi create test 10M
+$DOG vdi create test 10M
for i in 0 1 2; do
_vdi_list -p $((7000+$i))
done
diff --git a/tests/functional/069 b/tests/functional/069
index cf19f50..0e974e2 100755
--- a/tests/functional/069
+++ b/tests/functional/069
@@ -16,7 +16,7 @@ _cluster_format
# kill sheep 0 so that sheep 2 has larger epoch
_kill_sheep 0
-$COLLIE cluster shutdown -p 7001
+$DOG cluster shutdown -p 7001
_wait_for_sheep_stop
# clean up sheep 0 and sheep 1
@@ -32,7 +32,7 @@ _wait_for_sheep 2
# start Sheepdog with 2 nodes
_cluster_format
-$COLLIE cluster shutdown
+$DOG cluster shutdown
_wait_for_sheep_stop
# sheep 2 should fail to join because it was formatted at the different time
@@ -45,5 +45,5 @@ _start_sheep 1
_wait_for_sheep 2
for i in 0 1; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
diff --git a/tests/functional/070 b/tests/functional/070
index 1f7660e..a78f271 100755
--- a/tests/functional/070
+++ b/tests/functional/070
@@ -13,7 +13,7 @@ _wait_for_sheep 3
# start Sheepdog with 3 nodes
_cluster_format
-$COLLIE cluster shutdown -p 7000
+$DOG cluster shutdown -p 7000
_wait_for_sheep_stop
for i in 3 4 5; do
@@ -29,5 +29,5 @@ done
_wait_for_sheep 6
for i in `seq 0 5`; do
- $COLLIE cluster info -p 700$i | _filter_cluster_info
+ $DOG cluster info -p 700$i | _filter_cluster_info
done
diff --git a/tests/functional/071 b/tests/functional/071
index acf8b9f..de935a4 100755
--- a/tests/functional/071
+++ b/tests/functional/071
@@ -12,7 +12,7 @@ _wait_for_sheep 3
_cluster_format
-$COLLIE vdi create test 4M
+$DOG vdi create test 4M
# Create a 28 KB file. The first 12 KB (3 blocks) is filled with zero,
# next 4 KB is filled with one, and the rest is filled with zero.
@@ -25,9 +25,9 @@ for skip in 0 1 2 3; do
for offset in 0 512; do
for length in $((4 * 4096)) $((4 * 4096 - 512)); do
dd if=$DATA_FILE bs=4k skip=$skip count=4 2> /dev/null \
- | $COLLIE vdi write test $offset $length
+ | $DOG vdi write test $offset $length
- $COLLIE vdi read test $offset $length | hd
+ $DOG vdi read test $offset $length | hd
done
done
done
diff --git a/tests/functional/072 b/tests/functional/072
index b10f204..4f7a7c3 100755
--- a/tests/functional/072
+++ b/tests/functional/072
@@ -16,8 +16,8 @@ _cluster_format -c 1
_start_sheep 2
_wait_for_sheep 3
-$COLLIE vdi create test 8M -P
-$COLLIE cluster shutdown
+$DOG vdi create test 8M -P
+$DOG cluster shutdown
mv $STORE/0/obj/007c2b2500000001 $STORE/0/obj/.stale/007c2b2500000001.1
mv $STORE/1/obj/807c2b2500000000 $STORE/1/obj/.stale/807c2b2500000000.1
@@ -33,4 +33,4 @@ for i in 0 1 2; do
_vdi_list -p $((7000+$i))
done
-$COLLIE vdi check test
+$DOG vdi check test
diff --git a/tests/functional/check b/tests/functional/check
index 5addc23..e7b7a17 100755
--- a/tests/functional/check
+++ b/tests/functional/check
@@ -314,7 +314,7 @@ fi
if $valgrind; then
export SHEEP=_valgrind_sheep
- export COLLIE=_valgrind_collie
+ export DOG=_valgrind_dog
fi
# we need common.rc
diff --git a/tests/functional/common.config b/tests/functional/common.config
index db7d757..a946f2e 100644
--- a/tests/functional/common.config
+++ b/tests/functional/common.config
@@ -78,8 +78,8 @@ export STORE=$WD
export SHEEP_PROG=${SHEEP_PROG:-../../sheep/sheep}
export SHEEP=${SHEEP:-$SHEEP_PROG}
export SHEEP_OPTIONS=${SHEEP_OPTIONS:-"-n -y 127.0.0.1 -d"}
-export COLLIE_PROG=${COLLIE_PROG:-../../collie/collie}
-export COLLIE=${COLLIE:-$COLLIE_PROG}
+export DOG_PROG=${DOG_PROG:-../../dog/dog}
+export DOG=${DOG:-$DOG_PROG}
export VALGRIND_OPTIONS=${VALGRIND_OPTIONS:-"-q"}
export MD=${MD:-false}
export QEMU_IO=${QEMU_IO_PROG:-qemu-io}
diff --git a/tests/functional/common.filter b/tests/functional/common.filter
index f1fffc4..2c62ef2 100644
--- a/tests/functional/common.filter
+++ b/tests/functional/common.filter
@@ -145,7 +145,7 @@ _filter_spaces()
sed -e 's/ *$//'
}
-# normalize collie cluster info output
+# normalize dog cluster info output
_filter_cluster_info()
{
_filter_date | _filter_iso_date
diff --git a/tests/functional/common.rc b/tests/functional/common.rc
index 83fb195..2a64b53 100644
--- a/tests/functional/common.rc
+++ b/tests/functional/common.rc
@@ -141,7 +141,7 @@ _die()
_cleanup()
{
local i
- _kill_all_collies
+ _kill_all_dogs
_kill_all_sheeps
_cleanup_devices
@@ -225,7 +225,7 @@ _wait_for_sheep()
_die "should have $1, but have $(_count_sheep_processes) sheep"
fi
- node_list="$($COLLIE node list -p $PORT 2> /dev/null)"
+ node_list="$($DOG node list -p $PORT 2> /dev/null)"
if [ $? != 0 ]; then
# sheep is not ready yet
@@ -270,10 +270,10 @@ _valgrind_sheep()
done
}
-_valgrind_collie()
+_valgrind_dog()
{
local logfile=$(mktemp)
- valgrind --log-file=$logfile --error-exitcode=99 ${VALGRIND_OPTIONS} $COLLIE_PROG $*
+ valgrind --log-file=$logfile --error-exitcode=99 ${VALGRIND_OPTIONS} $DOG_PROG $*
local ret=$?
if [ $ret == 99 ]; then
cat $logfile 1>&2
@@ -311,12 +311,12 @@ _start_sheep()
fi
}
-_kill_all_collies()
+_kill_all_dogs()
{
- pkill -9 -f "$COLLIE_PROG (cluster|vdi|node|debug)"
+ pkill -9 -f "$DOG_PROG (cluster|vdi|node|debug)"
while [ $? == 0 ]; do
- pgrep -f "$COLLIE_PROG (cluster|vdi|node|debug)" > /dev/null
+ pgrep -f "$DOG_PROG (cluster|vdi|node|debug)" > /dev/null
done
}
@@ -342,7 +342,7 @@ _wait_for_sheep_recovery()
{
while true; do
sleep 2
- recovery_info="$($COLLIE node recovery -p $((7000+$1)))"
+ recovery_info="$($DOG node recovery -p $((7000+$1)))"
if [ $? != 0 ]; then
_die "failed to get recovery info"
@@ -459,18 +459,18 @@ _cluster_format()
local args=$*
local port_opt=$(echo $args | grep -oE '\-*p[^ ]* 7...')
- $COLLIE cluster format $args
+ $DOG cluster format $args
if [ $? != 0 ]; then
_die "failed to format cluster"
fi
# wait for all the sheeps to be running
- local ports=$($COLLIE node list -r $port_opt | perl -ne 'print "$1\n" if /:(\d+)/')
+ local ports=$($DOG node list -r $port_opt | perl -ne 'print "$1\n" if /:(\d+)/')
local port
for port in $ports; do
local cnt
for cnt in `seq 10`; do # wait at most 10 seconds
- $COLLIE cluster info -p $port | grep -E running > /dev/null
+ $DOG cluster info -p $port | grep -E running > /dev/null
if [ $? == 0 ]; then
continue 2
fi
@@ -507,7 +507,7 @@ _kill_zk_session()
_vdi_list()
{
local args=$*
- $COLLIE vdi list $args | _filter_short_date
+ $DOG vdi list $args | _filter_short_date
}
# make sure this script returns success
diff --git a/tests/functional/group b/tests/functional/group
index dfa6558..1749e13 100644
--- a/tests/functional/group
+++ b/tests/functional/group
@@ -11,7 +11,7 @@
# cluster: cluster drivers tests: join/leave/etc
# store: basic data integrity
# vdi: qemu I/O, snapshots, volume creation and deletion
-# collie: check collie commands
+# dog: check dog commands
# md: multi-disk tests
#
001 auto quick cluster md
@@ -61,7 +61,7 @@
045 auto quick store md
046 auto quick vdi md
047 auto quick vdi md
-048 auto quick collie
+048 auto quick dog
049 auto quick cache md
050 auto quick cluster md
051 auto quick cluster md
diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am
index 3e6255a..11ddf52 100644
--- a/tests/unit/Makefile.am
+++ b/tests/unit/Makefile.am
@@ -1,3 +1,3 @@
MAINTAINERCLEANFILES = Makefile.in
-SUBDIRS = mock collie sheep
+SUBDIRS = mock dog sheep
diff --git a/tests/unit/collie/Makefile.am b/tests/unit/collie/Makefile.am
deleted file mode 100644
index 404bc66..0000000
--- a/tests/unit/collie/Makefile.am
+++ /dev/null
@@ -1,23 +0,0 @@
-MAINTAINERCLEANFILES = Makefile.in
-
-TESTS = test_common
-
-check_PROGRAMS = ${TESTS}
-
-INCLUDES = -I$(top_srcdir)/include \
- -I$(top_srcdir)/collie \
- -I$(top_srcdir)/collie/farm \
- -I../mock \
- @CHECK_CFLAGS@
-
-LIBS = $(top_srcdir)/lib/libsheepdog.a -lpthread \
- ../mock/libmock.a @CHECK_LIBS@
-
-test_common_SOURCES = test_common.c mock_collie.c \
- $(top_srcdir)/collie/common.c
-
-clean-local:
- rm -f ${check_PROGRAMS} *.o
-
-coverage:
- @lcov -d . -c -o collie.info
diff --git a/tests/unit/collie/mock_collie.c b/tests/unit/collie/mock_collie.c
deleted file mode 100644
index ff52ed1..0000000
--- a/tests/unit/collie/mock_collie.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2013 Zelin.io
- *
- * Kai Zhang <kyle at zelin.io>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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 "collie.h"
-#include "mock.h"
-
-/* collie mock */
-uint8_t sdhost[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1 };
-int sdport = 7000, sd_vnodes_nr = 100;
-bool highlight = true;
-bool raw_output;
-struct sd_vnode sd_vnodes[SD_MAX_VNODES];
-
-MOCK_METHOD(update_node_list, int, 0, int max_nodes)
-MOCK_VOID_METHOD(subcommand_usage, char *cmd, char *subcmd, int status)
diff --git a/tests/unit/collie/test_common.c b/tests/unit/collie/test_common.c
deleted file mode 100644
index ee3c8ff..0000000
--- a/tests/unit/collie/test_common.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2013 Zelin.io
- *
- * Kai Zhang <kyle at zelin.io>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * 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 <check.h>
-
-#include "collie.h"
-
-/* test */
-START_TEST(test_common)
-{
- char str[100];
-
- raw_output = true;
- ck_assert_str_eq(size_to_str(10, str, 100), "10");
- ck_assert_str_eq(size_to_str(10000, str, 100), "10000");
- ck_assert_str_eq(size_to_str(100000000, str, 100), "100000000");
-
- raw_output = false;
- ck_assert_str_eq(size_to_str(10, str, 100), "0.0 MB");
- ck_assert_str_eq(size_to_str(10000, str, 100), "0.0 MB");
- ck_assert_str_eq(size_to_str(100000000, str, 100), "95 MB");
-}
-END_TEST
-
-static Suite *test_suite(void)
-{
- Suite *s = suite_create("test common");
-
- TCase *tc_common = tcase_create("common");
- tcase_add_test(tc_common, test_common);
-
- suite_add_tcase(s, tc_common);
-
- return s;
-}
-
-int main(void)
-{
- int number_failed;
- Suite *s = test_suite();
- SRunner *sr = srunner_create(s);
- srunner_run_all(sr, CK_NORMAL);
- number_failed = srunner_ntests_failed(sr);
- srunner_free(sr);
- return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
-}
diff --git a/tests/unit/dog/Makefile.am b/tests/unit/dog/Makefile.am
new file mode 100644
index 0000000..6d5978b
--- /dev/null
+++ b/tests/unit/dog/Makefile.am
@@ -0,0 +1,23 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+TESTS = test_common
+
+check_PROGRAMS = ${TESTS}
+
+INCLUDES = -I$(top_srcdir)/include \
+ -I$(top_srcdir)/dog \
+ -I$(top_srcdir)/dog/farm \
+ -I../mock \
+ @CHECK_CFLAGS@
+
+LIBS = $(top_srcdir)/lib/libsheepdog.a -lpthread \
+ ../mock/libmock.a @CHECK_LIBS@
+
+test_common_SOURCES = test_common.c mock_dog.c \
+ $(top_srcdir)/dog/common.c
+
+clean-local:
+ rm -f ${check_PROGRAMS} *.o
+
+coverage:
+ @lcov -d . -c -o dog.info
diff --git a/tests/unit/dog/mock_dog.c b/tests/unit/dog/mock_dog.c
new file mode 100644
index 0000000..6059a0a
--- /dev/null
+++ b/tests/unit/dog/mock_dog.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2013 Zelin.io
+ *
+ * Kai Zhang <kyle at zelin.io>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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 "dog.h"
+#include "mock.h"
+
+/* dog mock */
+uint8_t sdhost[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1 };
+int sdport = 7000, sd_vnodes_nr = 100;
+bool highlight = true;
+bool raw_output;
+struct sd_vnode sd_vnodes[SD_MAX_VNODES];
+
+MOCK_METHOD(update_node_list, int, 0, int max_nodes)
+MOCK_VOID_METHOD(subcommand_usage, char *cmd, char *subcmd, int status)
diff --git a/tests/unit/dog/test_common.c b/tests/unit/dog/test_common.c
new file mode 100644
index 0000000..6fec940
--- /dev/null
+++ b/tests/unit/dog/test_common.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 Zelin.io
+ *
+ * Kai Zhang <kyle at zelin.io>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * 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 <check.h>
+
+#include "dog.h"
+
+/* test */
+START_TEST(test_common)
+{
+ char str[100];
+
+ raw_output = true;
+ ck_assert_str_eq(size_to_str(10, str, 100), "10");
+ ck_assert_str_eq(size_to_str(10000, str, 100), "10000");
+ ck_assert_str_eq(size_to_str(100000000, str, 100), "100000000");
+
+ raw_output = false;
+ ck_assert_str_eq(size_to_str(10, str, 100), "0.0 MB");
+ ck_assert_str_eq(size_to_str(10000, str, 100), "0.0 MB");
+ ck_assert_str_eq(size_to_str(100000000, str, 100), "95 MB");
+}
+END_TEST
+
+static Suite *test_suite(void)
+{
+ Suite *s = suite_create("test common");
+
+ TCase *tc_common = tcase_create("common");
+ tcase_add_test(tc_common, test_common);
+
+ suite_add_tcase(s, tc_common);
+
+ return s;
+}
+
+int main(void)
+{
+ int number_failed;
+ Suite *s = test_suite();
+ SRunner *sr = srunner_create(s);
+ srunner_run_all(sr, CK_NORMAL);
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
--
1.7.9.5
More information about the sheepdog
mailing list