Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rbd: introduce v2 format for rbd export/import. #10487

Merged
merged 25 commits into from Feb 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
636d7cd
rbd/Import: fix the indent of labels
yangdongsheng Jul 28, 2016
e10b0c0
rbd: remove image in error handling of importing
yangdongsheng Jul 28, 2016
4658cf1
rbd: finish the pc in importing even if from_stdin.
yangdongsheng Jul 29, 2016
12f50c4
rbd: use macro for rbd diff tags
yangdongsheng Jul 6, 2016
262c8d3
rbd: squash ExportDiff.cc into Export.cc
yangdongsheng Oct 11, 2016
f6192de
rbd: squash ImportDiff.cc into Import.cc.
yangdongsheng Oct 11, 2016
21be324
rbd: move do_export_diff out from namespace of export_diff.
yangdongsheng Oct 11, 2016
de671d7
rbd: move do_import_diff out from namespace of import_diff
yangdongsheng Oct 11, 2016
bc80b14
rbd: refactor do_export_diff to accept fd
yangdongsheng Oct 11, 2016
58c8e8c
rbd: refactor do_import_diff to accept fd.
yangdongsheng Oct 11, 2016
5e03460
rbd: introduce --import-format to import command
yangdongsheng Jul 28, 2016
26b858e
rbd: introduce --export-format to export command
yangdongsheng Jul 28, 2016
55edd81
qa/workunit/rbd: add test case for --import/export-format in import_e…
yangdongsheng Jul 29, 2016
8679521
rbd: import/export image_order.
yangdongsheng Oct 13, 2016
912ff4d
rbd: import/export features of image
yangdongsheng Oct 14, 2016
d7479a0
rbd: import/export image stripe_unit and stripe_count.
yangdongsheng Oct 14, 2016
4ee764f
qa/workunit/rbd: import_export.sh: add image priorities exporting and…
yangdongsheng Oct 14, 2016
f16899a
rbd: use the unified --export-format option for rbd export and rbd im…
yangdongsheng Oct 20, 2016
08d0c2a
rbd: refactor export/import to v1 and v2 methods.
yangdongsheng Oct 20, 2016
435104a
rbd: import_diff/export_diff: encode length for each tag.
yangdongsheng Nov 2, 2016
c2356be
rbd: import: decode file data in le64 for compatability on different …
yangdongsheng Nov 3, 2016
8d2a613
rbd: combine the namespaces of export_diff and export_full, import_di…
yangdongsheng Nov 2, 2016
aa913ce
rbd: add docs for new format of rbd export.
yangdongsheng Nov 2, 2016
fedf772
rbd: import: use read() instead of lseek() when from_stdin is true
yangdongsheng Nov 3, 2016
5b14582
rbd: import/export/mergediff: use STD[IN|OUT]_FILENO instead of 0 or 1
yangdongsheng Nov 3, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
77 changes: 77 additions & 0 deletions doc/dev/rbd-diff.rst
Expand Up @@ -60,6 +60,83 @@ Zero data
- le64: length


Final Record
~~~~~~~~~~~~

End
---

- u8: 'e'

Copy link

@dillaman dillaman Jan 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also would be good to add a 1-byte tag struct version and 1-byte tag struct minimum compatibility version with the new length field (i.e. we might want to add support for recording snapshot timestamps in the "to snap tag" or CRCs to the data tag, but we shouldn't need to create a new tags to handle it).

Basically, you can re-use the existing ENCODE_START/ENCODE_FINISH methods

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to make every tag as simple as possible. Then I think we can introduce a new tags for snap_timestamp and CRC in diffs. This way, we can also keep the backward compatibility, we only need to set the timestamp when we found a tag for it.


Header
~~~~~~

"rbd diff v2\\n"

Metadata records
~~~~~~~~~~~~~~~~

Every record has a one byte "tag" that identifies the record type,
followed by length of data, and then some other data.

Metadata records come in the first part of the image. Order is not
important, as long as all the metadata records come before the data
records.

In v2, we have the following metadata in each section:
(1 Bytes) tag.
(8 Bytes) length.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's safe to use a 32bit length -- the only thing that requires 64bit is the write/zero tag, but since the maximum object size is 32M, they technically only require 32bit lengths as well (and should be updated to reflect that).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but what about keeping 8Bytes here in case of we want to break the limit of 32M someday, and 4Bytes for each tag sounds not a big waste for an output file of a rbd export-diff.

(n Bytes) data.

In this way, we can skip the unrecognized tag.

From snap
---------

- u8: 'f'
- le64: length of appending data (4 + length)
- le32: snap name length
- snap name

To snap
-------

- u8: 't'
- le64: length of appending data (4 + length)
- le32: snap name length
- snap name

Size
----

- u8: 's'
- le64: length of appending data (8)
- le64: (ending) image size

Data Records
~~~~~~~~~~~~

These records come in the second part of the sequence.

Updated data
------------

- u8: 'w'
- le64: length of appending data (8 + 8 + length)
- le64: offset
- le64: length
- length bytes of actual data

Zero data
---------

- u8: 'z'
- le64: length of appending data (8 + 8)
- le64: offset
- le64: length


Final Record
~~~~~~~~~~~~

Expand Down
84 changes: 84 additions & 0 deletions doc/dev/rbd-export.rst
@@ -0,0 +1,84 @@
RBD Export & Import
===================

This is a file format of an RBD image or snapshot. It's a sparse format
for the full image. There are three recording sections in the file.

(1) Header.
(2) Metadata.
(3) Diffs.

Header
~~~~~~

"rbd image v2\\n"

Metadata records
~~~~~~~~~~~~~~~~

Every record has a one byte "tag" that identifies the record type,
followed by length of data, and then some other data.

Metadata records come in the first part of the image. Order is not
important, as long as all the metadata records come before the data
records.

In v2, we have the following metadata in each section:
(1 Bytes) tag.
(8 Bytes) length.
(n Bytes) data.

In this way, we can skip the unrecognized tag.

Image order
-----------

- u8: 'O'
- le64: length of appending data (8)
- le64: image order

Image format
------------

- u8: 'F'
- le64: length of appending data (8)
- le64: image format

Image Features
--------------

- u8: 'T'
- le64: length of appending data (8)
- le64: image features

Image Stripe unit
-----------------

- u8: 'U'
- le64: length of appending data (8)
- le64: image striping unit

Image Stripe count
------------------

- u8: 'C'
- le64: length of appending data (8)
- le64: image striping count

Final Record
~~~~~~~~~~~~

End
---

- u8: 'E'


Diffs records
~~~~~~~~~~~~~~~~~
Record the all snapshots and the HEAD in this section.

- le64: number of diffs
- Diffs ...

Detail please refer to rbd-diff.rst
9 changes: 7 additions & 2 deletions doc/man/8/rbd.rst
Expand Up @@ -224,10 +224,12 @@ Commands
Deletes an rbd image (including all data blocks). If the image has
snapshots, this fails and nothing is deleted.

:command:`export` (*image-spec* | *snap-spec*) [*dest-path*]
:command:`export` [--export-format *format (1 or 2)*] (*image-spec* | *snap-spec*) [*dest-path*]
Exports image to dest path (use - for stdout).
The --export-format accepts '1' or '2' currently. Format 2 allow us to export not only the content
of image, but also the snapshots and other properties, such as image_order, features.

:command:`import` [--image-format *format-id*] [--object-size *size-in-B/K/M*] [--stripe-unit *size-in-B/K/M* --stripe-count *num*] [--image-feature *feature-name*]... [--image-shared] *src-path* [*image-spec*]
:command:`import` [--export-format *format (1 or 2)*] [--image-format *format-id*] [--object-size *size-in-B/K/M*] [--stripe-unit *size-in-B/K/M* --stripe-count *num*] [--image-feature *feature-name*]... [--image-shared] *src-path* [*image-spec*]
Creates a new image and imports its data from path (use - for
stdin). The import operation will try to create sparse rbd images
if possible. For import from stdin, the sparsification unit is
Expand All @@ -236,6 +238,9 @@ Commands
The --stripe-unit and --stripe-count arguments are optional, but must be
used together.

The --export-format accepts '1' or '2' currently. Format 2 allow us to import not only the content
of image, but also the snapshots and other properties, such as image_order, features.

:command:`export-diff` [--from-snap *snap-name*] [--whole-object] (*image-spec* | *snap-spec*) *dest-path*
Exports an incremental diff for an image to dest path (use - for stdout). If
an initial snapshot is specified, only changes since that snapshot are included; otherwise,
Expand Down
64 changes: 64 additions & 0 deletions qa/workunits/rbd/import_export.sh
Expand Up @@ -74,6 +74,70 @@ cmp ${TMPDIR}/img ${TMPDIR}/img3

rm ${TMPDIR}/img ${TMPDIR}/img2 ${TMPDIR}/img3

# try with --export-format for snapshots
dd if=/bin/dd of=${TMPDIR}/img bs=1k count=10 seek=100
rbd import $RBD_CREATE_ARGS ${TMPDIR}/img testimg
rbd snap create testimg@snap
rbd export --export-format 2 testimg ${TMPDIR}/img_v2
rbd import --export-format 2 ${TMPDIR}/img_v2 testimg_import
rbd info testimg_import
rbd info testimg_import@snap

# compare the contents between testimg and testimg_import
rbd export testimg_import ${TMPDIR}/img_import
compare_files_and_ondisk_sizes ${TMPDIR}/img ${TMPDIR}/img_import

rbd export testimg@snap ${TMPDIR}/img_snap
rbd export testimg_import@snap ${TMPDIR}/img_snap_import
compare_files_and_ondisk_sizes ${TMPDIR}/img_snap ${TMPDIR}/img_snap_import

rm ${TMPDIR}/img_v2
rm ${TMPDIR}/img_import
rm ${TMPDIR}/img_snap
rm ${TMPDIR}/img_snap_import

rbd snap rm testimg_import@snap
rbd remove testimg_import
rbd snap rm testimg@snap
rbd rm testimg

# order
rbd import --order 20 ${TMPDIR}/img testimg
rbd export --export-format 2 testimg ${TMPDIR}/img_v2
rbd import --export-format 2 ${TMPDIR}/img_v2 testimg_import
rbd info testimg_import|grep order|awk '{print $2}'|grep 20

rm ${TMPDIR}/img_v2

rbd remove testimg_import
rbd remove testimg

# features
rbd import --image-feature layering ${TMPDIR}/img testimg
FEATURES_BEFORE=`rbd info testimg|grep features`
rbd export --export-format 2 testimg ${TMPDIR}/img_v2
rbd import --export-format 2 ${TMPDIR}/img_v2 testimg_import
FEATURES_AFTER=`rbd info testimg_import|grep features`
if [ "$FEATURES_BEFORE" != "$FEATURES_AFTER" ]; then
false
fi

rm ${TMPDIR}/img_v2

rbd remove testimg_import
rbd remove testimg

# stripe
rbd import --stripe-count 1000 --stripe-unit 4096 ${TMPDIR}/img testimg
rbd export --export-format 2 testimg ${TMPDIR}/img_v2
rbd import --export-format 2 ${TMPDIR}/img_v2 testimg_import
rbd info testimg_import|grep "stripe unit"|awk '{print $3}'|grep 4096
rbd info testimg_import|grep "stripe count"|awk '{print $3}'|grep 1000

rm ${TMPDIR}/img_v2

rbd remove testimg_import
rbd remove testimg

tiered=0
if ceph osd dump | grep ^pool | grep "'rbd'" | grep tier; then
Expand Down
6 changes: 5 additions & 1 deletion src/test/cli/rbd/help.t
Expand Up @@ -320,6 +320,7 @@
rbd help export
usage: rbd export [--pool <pool>] [--image <image>] [--snap <snap>]
[--path <path>] [--no-progress]
[--export-format <export-format>]
<source-image-or-snap-spec> <path-name>

Export image to file.
Expand All @@ -336,6 +337,7 @@
--snap arg source snapshot name
--path arg export file (or '-' for stdout)
--no-progress disable progress output
--export-format arg format of image file

rbd help export-diff
usage: rbd export-diff [--pool <pool>] [--image <image>] [--snap <snap>]
Expand Down Expand Up @@ -585,7 +587,8 @@
[--journal-splay-width <journal-splay-width>]
[--journal-object-size <journal-object-size>]
[--journal-pool <journal-pool>] [--no-progress]
[--pool <pool>] [--image <image>]
[--export-format <export-format>] [--pool <pool>]
[--image <image>]
<path-name> <dest-image-spec>

Import image from file.
Expand Down Expand Up @@ -616,6 +619,7 @@
--journal-object-size arg size of journal objects
--journal-pool arg pool for journal objects
--no-progress disable progress output
--export-format arg format of image file
-p [ --pool ] arg pool name (deprecated)
--image arg image name (deprecated)

Expand Down
19 changes: 19 additions & 0 deletions src/tools/rbd/ArgumentTypes.cc
Expand Up @@ -331,6 +331,11 @@ void add_no_error_option(boost::program_options::options_description *opt) {
(NO_ERROR.c_str(), po::bool_switch(), "continue after error");
}

void add_export_format_option(boost::program_options::options_description *opt) {
opt->add_options()
("export-format", po::value<ExportFormat>(), "format of image file");
}

std::string get_short_features_help(bool append_suffix) {
std::ostringstream oss;
bool first_feature = true;
Expand Down Expand Up @@ -492,5 +497,19 @@ void validate(boost::any& v, const std::vector<std::string>& values,
throw po::validation_error(po::validation_error::invalid_option_value);
}

void validate(boost::any& v, const std::vector<std::string>& values,
ExportFormat *target_type, int) {
po::validators::check_first_occurrence(v);
const std::string &s = po::validators::get_single_string(values);

std::string parse_error;
uint64_t format = strict_sistrtoll(s.c_str(), &parse_error);
if (!parse_error.empty() || (format != 1 && format != 2)) {
throw po::validation_error(po::validation_error::invalid_option_value);
}

v = boost::any(format);
}

} // namespace argument_types
} // namespace rbd
7 changes: 7 additions & 0 deletions src/tools/rbd/ArgumentTypes.h
Expand Up @@ -114,6 +114,13 @@ struct Format : public TypedValue<std::string> {

struct JournalObjectSize {};

struct ExportFormat {};

void validate(boost::any& v, const std::vector<std::string>& values,
ExportFormat *target_type, int);

void add_export_format_option(boost::program_options::options_description *opt);

std::string get_name_prefix(ArgumentModifier modifier);
std::string get_description_prefix(ArgumentModifier modifier);

Expand Down
2 changes: 0 additions & 2 deletions src/tools/rbd/CMakeLists.txt
Expand Up @@ -13,13 +13,11 @@ set(rbd_srcs
action/Diff.cc
action/DiskUsage.cc
action/Export.cc
action/ExportDiff.cc
action/Feature.cc
action/Flatten.cc
action/Group.cc
action/ImageMeta.cc
action/Import.cc
action/ImportDiff.cc
action/Info.cc
action/Journal.cc
action/Kernel.cc
Expand Down
17 changes: 17 additions & 0 deletions src/tools/rbd/Utils.h
Expand Up @@ -16,6 +16,23 @@ namespace utils {

static const std::string RBD_DIFF_BANNER ("rbd diff v1\n");

static const std::string RBD_IMAGE_BANNER_V2 ("rbd image v2\n");
static const std::string RBD_IMAGE_DIFFS_BANNER_V2 ("rbd image diffss v2\n");
static const std::string RBD_DIFF_BANNER_V2 ("rbd diff v2\n");

#define RBD_DIFF_FROM_SNAP 'f'
#define RBD_DIFF_TO_SNAP 't'
#define RBD_DIFF_IMAGE_SIZE 's'
#define RBD_DIFF_WRITE 'w'
#define RBD_DIFF_ZERO 'z'
#define RBD_DIFF_END 'e'

#define RBD_EXPORT_IMAGE_ORDER 'O'
#define RBD_EXPORT_IMAGE_FEATURES 'T'
#define RBD_EXPORT_IMAGE_STRIPE_UNIT 'U'
#define RBD_EXPORT_IMAGE_STRIPE_COUNT 'C'
#define RBD_EXPORT_IMAGE_END 'E'

enum SnapshotPresence {
SNAPSHOT_PRESENCE_NONE,
SNAPSHOT_PRESENCE_PERMITTED,
Expand Down