]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/migration/Utils.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / librbd / migration / Utils.cc
CommitLineData
f67539c2
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "librbd/migration/Utils.h"
5#include "common/dout.h"
6#include "common/errno.h"
7#include <boost/lexical_cast.hpp>
8#include <regex>
9
10namespace librbd {
11namespace migration {
12namespace util {
13
14#define dout_subsys ceph_subsys_rbd
15#undef dout_prefix
16#define dout_prefix *_dout << "librbd::migration::util::" << __func__ << ": "
17
18int parse_url(CephContext* cct, const std::string& url, UrlSpec* url_spec) {
19 ldout(cct, 10) << "url=" << url << dendl;
20 *url_spec = UrlSpec{};
21
22 // parse the provided URL (scheme, user, password, host, port, path,
23 // parameters, query, and fragment)
24 std::regex url_regex(
25 R"(^(?:([^:/]*)://)?(?:(\w+)(?::(\w+))?@)?([^/;\?:#]+)(?::([^/;\?#]+))?)"
26 R"((?:/([^;\?#]*))?(?:;([^\?#]+))?(?:\?([^#]+))?(?:#(\w+))?$)");
27 std::smatch match;
28 if(!std::regex_match(url, match, url_regex)) {
29 lderr(cct) << "invalid url: '" << url << "'" << dendl;
30 return -EINVAL;
31 }
32
33 auto& scheme = match[1];
34 if (scheme == "http" || scheme == "") {
35 url_spec->scheme = URL_SCHEME_HTTP;
36 } else if (scheme == "https") {
37 url_spec->scheme = URL_SCHEME_HTTPS;
38 url_spec->port = "443";
39 } else {
40 lderr(cct) << "invalid url scheme: '" << url << "'" << dendl;
41 return -EINVAL;
42 }
43
44 url_spec->host = match[4];
45 auto& port = match[5];
46 if (port.matched) {
47 try {
48 boost::lexical_cast<uint16_t>(port);
49 } catch (boost::bad_lexical_cast&) {
50 lderr(cct) << "invalid url port: '" << url << "'" << dendl;
51 return -EINVAL;
52 }
53 url_spec->port = port;
54 }
55
56 auto& path = match[6];
57 if (path.matched) {
58 url_spec->path += path;
59 }
60 return 0;
61}
62
63void zero_shrunk_snapshot(CephContext* cct, const io::Extents& image_extents,
64 uint64_t snap_id, uint64_t new_size,
65 std::optional<uint64_t> *previous_size,
66 io::SparseExtents* sparse_extents) {
67 if (*previous_size && **previous_size > new_size) {
68 ldout(cct, 20) << "snapshot resize " << **previous_size << " -> "
69 << new_size << dendl;
70 interval_set<uint64_t> zero_interval;
71 zero_interval.insert(new_size, **previous_size - new_size);
72
73 for (auto& image_extent : image_extents) {
74 interval_set<uint64_t> image_interval;
75 image_interval.insert(image_extent.first, image_extent.second);
76
77 image_interval.intersection_of(zero_interval);
78 for (auto [image_offset, image_length] : image_interval) {
79 ldout(cct, 20) << "zeroing extent " << image_offset << "~"
80 << image_length << " at snapshot " << snap_id << dendl;
81 sparse_extents->insert(image_offset, image_length,
82 {io::SPARSE_EXTENT_STATE_ZEROED, image_length});
83 }
84 }
85 }
86 *previous_size = new_size;
87}
88
89void merge_snapshot_delta(const io::SnapIds& snap_ids,
90 io::SnapshotDelta* snapshot_delta) {
91 io::SnapshotDelta orig_snapshot_delta = std::move(*snapshot_delta);
92 snapshot_delta->clear();
93
94 auto snap_id_it = snap_ids.begin();
95 ceph_assert(snap_id_it != snap_ids.end());
96
97 // merge any snapshot intervals that were not requested
98 std::list<io::SparseExtents*> pending_sparse_extents;
99 for (auto& [snap_key, sparse_extents] : orig_snapshot_delta) {
100 // advance to next valid requested snap id
101 while (snap_id_it != snap_ids.end() && *snap_id_it < snap_key.first) {
102 ++snap_id_it;
103 }
104 if (snap_id_it == snap_ids.end()) {
105 break;
106 }
107
108 // loop through older write/read snapshot sparse extents to remove any
109 // overlaps with the current sparse extent
110 for (auto prev_sparse_extents : pending_sparse_extents) {
111 for (auto& sparse_extent : sparse_extents) {
112 prev_sparse_extents->erase(sparse_extent.get_off(),
113 sparse_extent.get_len());
114 }
115 }
116
117 auto write_read_snap_ids = std::make_pair(*snap_id_it, snap_key.second);
118 (*snapshot_delta)[write_read_snap_ids] = std::move(sparse_extents);
119
120 if (write_read_snap_ids.first > snap_key.first) {
121 // the current snapshot wasn't requested so it might need to get
122 // merged with a later snapshot
123 pending_sparse_extents.push_back(&(*snapshot_delta)[write_read_snap_ids]);
124 } else {
125 // we don't merge results passed a valid requested snapshot
126 pending_sparse_extents.clear();
127 }
128 }
129}
130
131} // namespace util
132} // namespace migration
133} // namespace librbd