]>
Commit | Line | Data |
---|---|---|
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 | ||
10 | namespace librbd { | |
11 | namespace migration { | |
12 | namespace util { | |
13 | ||
14 | #define dout_subsys ceph_subsys_rbd | |
15 | #undef dout_prefix | |
16 | #define dout_prefix *_dout << "librbd::migration::util::" << __func__ << ": " | |
17 | ||
18 | int 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 | ||
63 | void 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 | ||
89 | void 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 |