]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2015 Red Hat | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include "include/rados/librados.hpp" | |
16 | #include "common/errno.h" | |
17 | ||
18 | #include "PoolDump.h" | |
19 | ||
20 | using namespace librados; | |
21 | ||
22 | #define dout_context g_ceph_context | |
23 | #define dout_subsys ceph_subsys_rados | |
24 | ||
25 | /** | |
26 | * Export RADOS objects from a live cluster | |
27 | * to a serialized format via a file descriptor. | |
28 | * | |
29 | * @returns 0 on success, else error code | |
30 | */ | |
31 | int PoolDump::dump(IoCtx *io_ctx) | |
32 | { | |
11fdf7f2 | 33 | ceph_assert(io_ctx != NULL); |
7c673cae FG |
34 | |
35 | int r = 0; | |
36 | write_super(); | |
37 | ||
38 | r = write_simple(TYPE_POOL_BEGIN, file_fd); | |
39 | if (r != 0) { | |
40 | return r; | |
41 | } | |
42 | ||
43 | io_ctx->set_namespace(all_nspaces); | |
44 | librados::NObjectIterator i = io_ctx->nobjects_begin(); | |
45 | ||
46 | librados::NObjectIterator i_end = io_ctx->nobjects_end(); | |
47 | for (; i != i_end; ++i) { | |
48 | const std::string oid = i->get_oid(); | |
49 | dout(10) << "OID '" << oid << "'" << dendl; | |
50 | ||
51 | // Compose OBJECT_BEGIN | |
52 | // ==================== | |
53 | object_begin obj_begin; | |
54 | obj_begin.hoid.hobj.oid = i->get_oid(); | |
55 | obj_begin.hoid.hobj.nspace = i->get_nspace(); | |
56 | obj_begin.hoid.hobj.set_key(i->get_locator()); | |
57 | ||
58 | // Only output head, RadosImport only wants that | |
59 | obj_begin.hoid.hobj.snap = CEPH_NOSNAP; | |
60 | ||
61 | // Skip setting object_begin.oi, RadosImport doesn't care | |
62 | ||
63 | r = write_section(TYPE_OBJECT_BEGIN, obj_begin, file_fd); | |
64 | if (r != 0) { | |
65 | return r; | |
66 | } | |
67 | ||
68 | // Compose TYPE_DATA chunks | |
69 | // ======================== | |
70 | const uint32_t op_size = 4096 * 1024; | |
71 | uint64_t offset = 0; | |
72 | io_ctx->set_namespace(i->get_nspace()); | |
73 | while (true) { | |
74 | bufferlist outdata; | |
75 | r = io_ctx->read(oid, outdata, op_size, offset); | |
76 | if (r <= 0) { | |
77 | // Error or no data | |
78 | break; | |
79 | } | |
80 | ||
81 | r = write_section(TYPE_DATA, | |
82 | data_section(offset, outdata.length(), outdata), file_fd); | |
83 | if (r != 0) { | |
84 | // Output stream error | |
85 | return r; | |
86 | } | |
87 | ||
88 | if (outdata.length() < op_size) { | |
89 | // No more data | |
7c673cae FG |
90 | break; |
91 | } | |
92 | offset += outdata.length(); | |
93 | } | |
94 | ||
95 | // Compose TYPE_ATTRS chunk | |
96 | // ======================== | |
97 | std::map<std::string, bufferlist> raw_xattrs; | |
98 | std::map<std::string, bufferlist> xattrs; | |
99 | r = io_ctx->getxattrs(oid, raw_xattrs); | |
100 | if (r < 0) { | |
101 | cerr << "error getting xattr set " << oid << ": " << cpp_strerror(r) | |
102 | << std::endl; | |
103 | return r; | |
104 | } | |
105 | // Prepend "_" to mimic how user keys are represented in a pg export | |
106 | for (std::map<std::string, bufferlist>::iterator i = raw_xattrs.begin(); | |
107 | i != raw_xattrs.end(); ++i) { | |
108 | std::pair< std::string, bufferlist> item(std::string("_") + std::string(i->first.c_str()), i->second); | |
109 | xattrs.insert(item); | |
110 | } | |
111 | r = write_section(TYPE_ATTRS, attr_section(xattrs), file_fd); | |
112 | if (r != 0) { | |
113 | return r; | |
114 | } | |
115 | ||
116 | // Compose TYPE_OMAP_HDR section | |
117 | // ============================= | |
118 | bufferlist omap_header; | |
119 | r = io_ctx->omap_get_header(oid, &omap_header); | |
120 | if (r < 0) { | |
121 | cerr << "error getting omap header " << oid | |
122 | << ": " << cpp_strerror(r) << std::endl; | |
123 | return r; | |
124 | } | |
125 | r = write_section(TYPE_OMAP_HDR, omap_hdr_section(omap_header), file_fd); | |
126 | if (r != 0) { | |
127 | return r; | |
128 | } | |
129 | ||
130 | // Compose TYPE_OMAP | |
131 | int MAX_READ = 512; | |
132 | string last_read = ""; | |
133 | do { | |
134 | map<string, bufferlist> values; | |
135 | r = io_ctx->omap_get_vals(oid, last_read, MAX_READ, &values); | |
136 | if (r < 0) { | |
137 | cerr << "error getting omap keys " << oid << ": " | |
138 | << cpp_strerror(r) << std::endl; | |
139 | return r; | |
140 | } | |
141 | if (values.size()) { | |
142 | last_read = values.rbegin()->first; | |
143 | } else { | |
144 | break; | |
145 | } | |
146 | ||
147 | r = write_section(TYPE_OMAP, omap_section(values), file_fd); | |
148 | if (r != 0) { | |
149 | return r; | |
150 | } | |
151 | r = values.size(); | |
152 | } while (r == MAX_READ); | |
7c673cae FG |
153 | |
154 | // Close object | |
155 | // ============= | |
156 | r = write_simple(TYPE_OBJECT_END, file_fd); | |
157 | if (r != 0) { | |
158 | return r; | |
159 | } | |
160 | } | |
161 | ||
162 | r = write_simple(TYPE_POOL_END, file_fd); | |
163 | #if defined(__linux__) | |
164 | if (file_fd != STDOUT_FILENO) | |
165 | posix_fadvise(file_fd, 0, 0, POSIX_FADV_DONTNEED); | |
166 | #endif | |
167 | return r; | |
168 | } |