summaryrefslogtreecommitdiffstats
path: root/src/tools/RadosDump.h
blob: 83f02e69d5184003e5ab54219abd761545eb95e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2015 Red Hat
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#ifndef RADOS_DUMP_H_
#define RADOS_DUMP_H_

#include <stdint.h>

#include "include/buffer.h"
#include "include/encoding.h"

#include "osd/osd_types.h"
#include "osd/OSDMap.h"

typedef uint8_t sectiontype_t;
typedef uint32_t mymagic_t;
typedef int64_t mysize_t;

enum {
    TYPE_NONE = 0,
    TYPE_PG_BEGIN,
    TYPE_PG_END,
    TYPE_OBJECT_BEGIN,
    TYPE_OBJECT_END,
    TYPE_DATA,
    TYPE_ATTRS,
    TYPE_OMAP_HDR,
    TYPE_OMAP,
    TYPE_PG_METADATA,
    TYPE_POOL_BEGIN,
    TYPE_POOL_END,
    END_OF_TYPES,	//Keep at the end
};

const uint16_t shortmagic = 0xffce;	//goes into stream as "ceff"
//endmagic goes into stream as "ceff ffec"
const mymagic_t endmagic = (0xecff << 16) | shortmagic;

//The first FIXED_LENGTH bytes are a fixed
//portion of the export output.  This includes the overall
//version number, and size of header and footer.
//THIS STRUCTURE CAN ONLY BE APPENDED TO.  If it needs to expand,
//the version can be bumped and then anything
//can be added to the export format.
struct super_header {
  static const uint32_t super_magic = (shortmagic << 16) | shortmagic;
  // ver = 1, Initial version
  // ver = 2, Add OSDSuperblock to pg_begin
  static const uint32_t super_ver = 2;
  static const uint32_t FIXED_LENGTH = 16;
  uint32_t magic;
  uint32_t version;
  uint32_t header_size;
  uint32_t footer_size;

  super_header() : magic(0), version(0), header_size(0), footer_size(0) { }

  void encode(bufferlist& bl) const {
    using ceph::encode;
    encode(magic, bl);
    encode(version, bl);
    encode(header_size, bl);
    encode(footer_size, bl);
  }
  void decode(bufferlist::const_iterator& bl) {
    using ceph::decode;
    decode(magic, bl);
    decode(version, bl);
    decode(header_size, bl);
    decode(footer_size, bl);
  }
};

struct header {
  sectiontype_t type;
  mysize_t size;
  header(sectiontype_t type, mysize_t size) :
    type(type), size(size) { }
  header(): type(0), size(0) { }

  void encode(bufferlist& bl) const {
    uint32_t debug_type = (type << 24) | (type << 16) | shortmagic;
    ENCODE_START(1, 1, bl);
    encode(debug_type, bl);
    encode(size, bl);
    ENCODE_FINISH(bl);
  }
  void decode(bufferlist::const_iterator& bl) {
    uint32_t debug_type;
    DECODE_START(1, bl);
    decode(debug_type, bl);
    type = debug_type >> 24;
    decode(size, bl);
    DECODE_FINISH(bl);
  }
};

struct footer {
  mymagic_t magic;
  footer() : magic(endmagic) { }

  void encode(bufferlist& bl) const {
    ENCODE_START(1, 1, bl);
    encode(magic, bl);
    ENCODE_FINISH(bl);
  }
  void decode(bufferlist::const_iterator& bl) {
    DECODE_START(1, bl);
    decode(magic, bl);
    DECODE_FINISH(bl);
  }
};

struct pg_begin {
  spg_t pgid;
  OSDSuperblock superblock;

  pg_begin(spg_t pg, const OSDSuperblock& sb):
    pgid(pg), superblock(sb) { }
  pg_begin() { }

  void encode(bufferlist& bl) const {
    // If superblock doesn't include CEPH_FS_FEATURE_INCOMPAT_SHARDS then
    // shard will be NO_SHARD for a replicated pool.  This means
    // that we allow the decode by struct_v 2.
    ENCODE_START(3, 2, bl);
    encode(pgid.pgid, bl);
    encode(superblock, bl);
    encode(pgid.shard, bl);
    ENCODE_FINISH(bl);
  }
  // NOTE: New super_ver prevents decode from ver 1
  void decode(bufferlist::const_iterator& bl) {
    DECODE_START(3, bl);
    decode(pgid.pgid, bl);
    if (struct_v > 1) {
      decode(superblock, bl);
    }
    if (struct_v > 2) {
      decode(pgid.shard, bl);
    } else {
      pgid.shard = shard_id_t::NO_SHARD;
    }
    DECODE_FINISH(bl);
  }
};

struct object_begin {
  ghobject_t hoid;

  // Duplicate what is in the OI_ATTR so we have it at the start
  // of object processing.
  object_info_t oi;

  explicit object_begin(const ghobject_t &hoid): hoid(hoid) { }
  object_begin() { }

  // If superblock doesn't include CEPH_FS_FEATURE_INCOMPAT_SHARDS then
  // generation will be NO_GEN, shard_id will be NO_SHARD for a replicated
  // pool.  This means we will allow the decode by struct_v 1.
  void encode(bufferlist& bl) const {
    ENCODE_START(3, 1, bl);
    encode(hoid.hobj, bl);
    encode(hoid.generation, bl);
    encode(hoid.shard_id, bl);
    encode(oi, bl, -1);  /* FIXME: we always encode with full features */
    ENCODE_FINISH(bl);
  }
  void decode(bufferlist::const_iterator& bl) {
    DECODE_START(3, bl);
    decode(hoid.hobj, bl);
    if (struct_v > 1) {
      decode(hoid.generation, bl);
      decode(hoid.shard_id, bl);
    } else {
      hoid.generation = ghobject_t::NO_GEN;
      hoid.shard_id = shard_id_t::NO_SHARD;
    }
    if (struct_v > 2) {
      decode(oi, bl);
    }
    DECODE_FINISH(bl);
  }
};

struct data_section {
  uint64_t offset;
  uint64_t len;
  bufferlist databl;
  data_section(uint64_t offset, uint64_t len, bufferlist bl):
     offset(offset), len(len), databl(bl) { }
  data_section(): offset(0), len(0) { }

  void encode(bufferlist& bl) const {
    ENCODE_START(1, 1, bl);
    encode(offset, bl);
    encode(len, bl);
    encode(databl, bl);
    ENCODE_FINISH(bl);
  }
  void decode(bufferlist::const_iterator& bl) {
    DECODE_START(1, bl);
    decode(offset, bl);
    decode(len, bl);
    decode(databl, bl);
    DECODE_FINISH(bl);
  }
};

struct attr_section {
  map<string,bufferlist> data;
  explicit attr_section(const map<string,bufferlist> &data) : data(data) { }
  explicit attr_section(map<string, bufferptr> &data_)
  {
    for (std::map<std::string, bufferptr>::iterator i = data_.begin();
         i != data_.end(); ++i) {
      bufferlist bl;
      bl.push_back(i->second);
      data[i->first] = bl;
    }
  }

  attr_section() { }

  void encode(bufferlist& bl) const {
    ENCODE_START(1, 1, bl);
    encode(data, bl);
    ENCODE_FINISH(bl);
  }
  void decode(bufferlist::const_iterator& bl) {
    DECODE_START(1, bl);
    decode(data, bl);
    DECODE_FINISH(bl);
  }
};

struct omap_hdr_section {
  bufferlist hdr;
  explicit omap_hdr_section(bufferlist hdr) : hdr(hdr) { }
  omap_hdr_section() { }

  void encode(bufferlist& bl) const {
    ENCODE_START(1, 1, bl);
    encode(hdr, bl);
    ENCODE_FINISH(bl);
  }
  void decode(bufferlist::const_iterator& bl) {
    DECODE_START(1, bl);
    decode(hdr, bl);
    DECODE_FINISH(bl);
  }
};

struct omap_section {
  map<string, bufferlist> omap;
  explicit omap_section(const map<string, bufferlist> &omap) :
    omap(omap) { }
  omap_section() { }

  void encode(bufferlist& bl) const {
    ENCODE_START(1, 1, bl);
    encode(omap, bl);
    ENCODE_FINISH(bl);
  }
  void decode(bufferlist::const_iterator& bl) {
    DECODE_START(1, bl);
    decode(omap, bl);
    DECODE_FINISH(bl);
  }
};

struct metadata_section {
  // struct_ver is the on-disk version of original pg
  __u8 struct_ver;  // for reference
  epoch_t map_epoch;
  pg_info_t info;
  pg_log_t log;
  PastIntervals past_intervals;
  OSDMap osdmap;
  bufferlist osdmap_bl;  // Used in lieu of encoding osdmap due to crc checking
  map<eversion_t, hobject_t> divergent_priors;
  pg_missing_t missing;

  metadata_section(
    __u8 struct_ver,
    epoch_t map_epoch,
    const pg_info_t &info,
    const pg_log_t &log,
    const PastIntervals &past_intervals,
    const pg_missing_t &missing)
    : struct_ver(struct_ver),
      map_epoch(map_epoch),
      info(info),
      log(log),
      past_intervals(past_intervals),
      missing(missing) {}
  metadata_section()
    : struct_ver(0),
      map_epoch(0) { }

  void encode(bufferlist& bl) const {
    ENCODE_START(6, 6, bl);
    encode(struct_ver, bl);
    encode(map_epoch, bl);
    encode(info, bl);
    encode(log, bl);
    encode(past_intervals, bl);
    // Equivalent to osdmap.encode(bl, features); but
    // preserving exact layout for CRC checking.
    bl.append(osdmap_bl);
    encode(divergent_priors, bl);
    encode(missing, bl);
    ENCODE_FINISH(bl);
  }
  void decode(bufferlist::const_iterator& bl) {
    DECODE_START(6, bl);
    decode(struct_ver, bl);
    decode(map_epoch, bl);
    decode(info, bl);
    decode(log, bl);
    if (struct_v >= 6) {
      decode(past_intervals, bl);
    } else if (struct_v > 1) {
      cout << "NOTICE: Older export with classic past_intervals" << std::endl;
    } else {
      cout << "NOTICE: Older export without past_intervals" << std::endl;
    }
    if (struct_v > 2) {
      osdmap.decode(bl);
    } else {
      cout << "WARNING: Older export without OSDMap information" << std::endl;
    }
    if (struct_v > 3) {
      decode(divergent_priors, bl);
    }
    if (struct_v > 4) {
      decode(missing, bl);
    }
    DECODE_FINISH(bl);
  }
};

/**
 * Superclass for classes that will need to handle a serialized RADOS
 * dump.  Requires that the serialized dump be opened with a known FD.
 */
class RadosDump
{
  protected:
    int file_fd;
    super_header sh;
    bool dry_run;

  public:
    RadosDump(int file_fd_, bool dry_run_)
      : file_fd(file_fd_), dry_run(dry_run_)
    {}

    int read_super();
    int get_header(header *h);
    int get_footer(footer *f);
    int read_section(sectiontype_t *type, bufferlist *bl);
    int skip_object(bufferlist &bl);
    void write_super();

    // Define this in .h because it's templated
    template <typename T>
      int write_section(sectiontype_t type, const T& obj, int fd) {
        if (dry_run)
          return 0;
        bufferlist blhdr, bl, blftr;
        obj.encode(bl);
        header hdr(type, bl.length());
        hdr.encode(blhdr);
        footer ft;
        ft.encode(blftr);

        int ret = blhdr.write_fd(fd);
        if (ret) return ret;
        ret = bl.write_fd(fd);
        if (ret) return ret;
        ret = blftr.write_fd(fd);
        return ret;
      }

    int write_simple(sectiontype_t type, int fd)
    {
      if (dry_run)
        return 0;
      bufferlist hbl;

      header hdr(type, 0);
      hdr.encode(hbl);
      return hbl.write_fd(fd);
    }
};

#endif