]>
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) 2012 New Dream Network | |
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 | #include <stdio.h> | |
14 | #include <stdlib.h> | |
15 | #include <map> | |
16 | #include <boost/scoped_ptr.hpp> | |
17 | #include "common/debug.h" | |
18 | #include "os/filestore/FileStore.h" | |
19 | #include "common/config.h" | |
20 | ||
21 | #include "FileStoreDiff.h" | |
22 | ||
23 | #define dout_context g_ceph_context | |
24 | #define dout_subsys ceph_subsys_filestore | |
25 | #undef dout_prefix | |
26 | #define dout_prefix *_dout << "filestore_diff " | |
27 | ||
20effc67 TL |
28 | using namespace std; |
29 | ||
7c673cae FG |
30 | FileStoreDiff::FileStoreDiff(FileStore *a, FileStore *b) |
31 | : a_store(a), b_store(b) | |
32 | { | |
33 | int err; | |
34 | err = a_store->mount(); | |
35 | ceph_assert(err == 0); | |
36 | ||
37 | err = b_store->mount(); | |
38 | ceph_assert(err == 0); | |
39 | } | |
40 | ||
41 | FileStoreDiff::~FileStoreDiff() | |
42 | { | |
43 | a_store->umount(); | |
44 | b_store->umount(); | |
45 | } | |
46 | ||
47 | ||
20effc67 TL |
48 | bool FileStoreDiff::diff_attrs(std::map<std::string,bufferptr,std::less<>>& b, |
49 | std::map<std::string,bufferptr,std::less<>>& a) | |
7c673cae FG |
50 | { |
51 | bool ret = false; | |
20effc67 TL |
52 | auto b_it = b.begin(); |
53 | auto a_it = a.begin(); | |
7c673cae FG |
54 | for (; b_it != b.end(); ++b_it, ++a_it) { |
55 | if (b_it->first != a_it->first) { | |
28e407b8 AA |
56 | cout << "diff_attrs name mismatch (verify: " << b_it->first |
57 | << ", store: " << a_it->first << ")" << std::endl; | |
7c673cae FG |
58 | ret = true; |
59 | continue; | |
60 | } | |
61 | ||
62 | if (!b_it->second.cmp(a_it->second)) { | |
28e407b8 | 63 | cout << "diff_attrs contents mismatch on attr " << b_it->first << std::endl; |
7c673cae FG |
64 | ret = true; |
65 | continue; | |
66 | } | |
67 | } | |
68 | return ret; | |
69 | } | |
70 | ||
71 | static bool diff_omap(std::map<std::string,bufferlist>& b, | |
72 | std::map<std::string,bufferlist>& a) | |
73 | { | |
74 | bool ret = false; | |
75 | std::map<std::string, bufferlist>::iterator b_it = b.begin(); | |
76 | std::map<std::string, bufferlist>::iterator a_it = a.begin(); | |
77 | for (; b_it != b.end(); ++b_it, ++a_it) { | |
28e407b8 AA |
78 | if (a_it == a.end()) { |
79 | cout << __func__ << " a reached end before b, a missing " << b_it->first | |
80 | << std::endl; | |
81 | ret = true; | |
82 | break; | |
83 | } | |
7c673cae | 84 | if (b_it->first != a_it->first) { |
28e407b8 AA |
85 | cout << "diff_attrs name mismatch (verify: " << b_it->first |
86 | << ", store: " << a_it->first << ")" << std::endl; | |
7c673cae FG |
87 | ret = true; |
88 | continue; | |
89 | } | |
90 | ||
91 | if (!(b_it->second == a_it->second)) { | |
28e407b8 | 92 | cout << "diff_attrs contents mismatch on attr " << b_it->first << std::endl; |
7c673cae FG |
93 | ret = true; |
94 | continue; | |
95 | } | |
96 | } | |
97 | return ret; | |
98 | } | |
99 | ||
100 | bool FileStoreDiff::diff_objects_stat(struct stat& a, struct stat& b) | |
101 | { | |
102 | bool ret = false; | |
103 | ||
104 | if (a.st_uid != b.st_uid) { | |
28e407b8 AA |
105 | cout << "diff_objects_stat uid mismatch (A: " |
106 | << a.st_uid << " != B: " << b.st_uid << ")" << std::endl; | |
7c673cae FG |
107 | ret = true; |
108 | } | |
109 | ||
110 | if (a.st_gid != b.st_gid) { | |
28e407b8 AA |
111 | cout << "diff_objects_stat gid mismatch (A: " |
112 | << a.st_gid << " != B: " << b.st_gid << ")" << std::endl; | |
7c673cae FG |
113 | ret = true; |
114 | } | |
115 | ||
116 | if (a.st_mode != b.st_mode) { | |
28e407b8 AA |
117 | cout << "diff_objects_stat mode mismatch (A: " |
118 | << a.st_mode << " != B: " << b.st_mode << ")" << std::endl; | |
7c673cae FG |
119 | ret = true; |
120 | } | |
121 | ||
122 | if (a.st_nlink != b.st_nlink) { | |
28e407b8 AA |
123 | cout << "diff_objects_stat nlink mismatch (A: " |
124 | << a.st_nlink << " != B: " << b.st_nlink << ")" << std::endl; | |
7c673cae FG |
125 | ret = true; |
126 | } | |
127 | ||
128 | if (a.st_size != b.st_size) { | |
28e407b8 AA |
129 | cout << "diff_objects_stat size mismatch (A: " |
130 | << a.st_size << " != B: " << b.st_size << ")" << std::endl; | |
7c673cae FG |
131 | ret = true; |
132 | } | |
133 | return ret; | |
134 | } | |
135 | ||
136 | bool FileStoreDiff::diff_objects(FileStore *a_store, FileStore *b_store, coll_t coll) | |
137 | { | |
7c673cae FG |
138 | bool ret = false; |
139 | ||
140 | int err; | |
141 | std::vector<ghobject_t> b_objects, a_objects; | |
142 | err = b_store->collection_list(coll, ghobject_t(), ghobject_t::get_max(), | |
143 | INT_MAX, &b_objects, NULL); | |
144 | if (err < 0) { | |
28e407b8 AA |
145 | cout << "diff_objects list on verify coll " << coll.to_str() |
146 | << " returns " << err << std::endl; | |
7c673cae FG |
147 | return true; |
148 | } | |
149 | err = a_store->collection_list(coll, ghobject_t(), ghobject_t::get_max(), | |
150 | INT_MAX, &a_objects, NULL); | |
151 | if (err < 0) { | |
28e407b8 AA |
152 | cout << "diff_objects list on store coll " << coll.to_str() |
153 | << " returns " << err << std::endl; | |
7c673cae FG |
154 | return true; |
155 | } | |
156 | ||
157 | if (b_objects.size() != a_objects.size()) { | |
11fdf7f2 | 158 | cout << "diff_objects " << coll << " num objs mismatch (A: " << a_objects.size() |
28e407b8 | 159 | << ", B: " << b_objects.size() << ")" << std::endl; |
7c673cae | 160 | ret = true; |
11fdf7f2 TL |
161 | cout << "a: " << a_objects << std::endl; |
162 | cout << "b: " << b_objects << std::endl; | |
7c673cae FG |
163 | } |
164 | ||
11fdf7f2 TL |
165 | auto a_ch = a_store->open_collection(coll); |
166 | auto b_ch = b_store->open_collection(coll); | |
7c673cae FG |
167 | std::vector<ghobject_t>::iterator b_it = b_objects.begin(); |
168 | std::vector<ghobject_t>::iterator a_it = b_objects.begin(); | |
169 | for (; b_it != b_objects.end(); ++b_it, ++a_it) { | |
170 | ghobject_t b_obj = *b_it, a_obj = *a_it; | |
171 | if (b_obj.hobj.oid.name != a_obj.hobj.oid.name) { | |
28e407b8 | 172 | cout << "diff_objects name mismatch on A object " |
7c673cae | 173 | << coll << "/" << a_obj << " and B object " |
28e407b8 | 174 | << coll << "/" << b_obj << std::endl; |
7c673cae FG |
175 | ret = true; |
176 | continue; | |
177 | } | |
178 | ||
179 | struct stat b_stat, a_stat; | |
11fdf7f2 | 180 | err = b_store->stat(b_ch, b_obj, &b_stat); |
7c673cae | 181 | if (err < 0) { |
28e407b8 AA |
182 | cout << "diff_objects error stating B object " |
183 | << coll.to_str() << "/" << b_obj.hobj.oid.name << std::endl; | |
7c673cae FG |
184 | ret = true; |
185 | } | |
11fdf7f2 | 186 | err = a_store->stat(a_ch, a_obj, &a_stat); |
7c673cae | 187 | if (err < 0) { |
28e407b8 AA |
188 | cout << "diff_objects error stating A object " |
189 | << coll << "/" << a_obj << std::endl; | |
7c673cae FG |
190 | ret = true; |
191 | } | |
192 | ||
193 | if (diff_objects_stat(a_stat, b_stat)) { | |
28e407b8 AA |
194 | cout << "diff_objects stat mismatch on " |
195 | << coll << "/" << b_obj << std::endl; | |
7c673cae FG |
196 | ret = true; |
197 | } | |
198 | ||
199 | bufferlist a_obj_bl, b_obj_bl; | |
11fdf7f2 TL |
200 | b_store->read(b_ch, b_obj, 0, b_stat.st_size, b_obj_bl); |
201 | a_store->read(a_ch, a_obj, 0, a_stat.st_size, a_obj_bl); | |
7c673cae FG |
202 | |
203 | if (!a_obj_bl.contents_equal(b_obj_bl)) { | |
28e407b8 AA |
204 | cout << "diff_objects content mismatch on " |
205 | << coll << "/" << b_obj << std::endl; | |
7c673cae FG |
206 | ret = true; |
207 | } | |
208 | ||
20effc67 | 209 | std::map<std::string, bufferptr, std::less<>> a_obj_attrs_map, b_obj_attrs_map; |
11fdf7f2 | 210 | err = a_store->getattrs(a_ch, a_obj, a_obj_attrs_map); |
7c673cae | 211 | if (err < 0) { |
28e407b8 AA |
212 | cout << "diff_objects getattrs on A object " << coll << "/" << a_obj |
213 | << " returns " << err << std::endl; | |
7c673cae FG |
214 | ret = true; |
215 | } | |
11fdf7f2 | 216 | err = b_store->getattrs(b_ch, b_obj, b_obj_attrs_map); |
7c673cae | 217 | if (err < 0) { |
28e407b8 AA |
218 | cout << "diff_objects getattrs on B object " << coll << "/" << b_obj |
219 | << "returns " << err << std::endl; | |
7c673cae FG |
220 | ret = true; |
221 | } | |
222 | ||
223 | if (diff_attrs(b_obj_attrs_map, a_obj_attrs_map)) { | |
28e407b8 | 224 | cout << "diff_objects attrs mismatch on A object " |
7c673cae | 225 | << coll << "/" << a_obj << " and B object " |
28e407b8 | 226 | << coll << "/" << b_obj << std::endl; |
7c673cae FG |
227 | ret = true; |
228 | } | |
229 | ||
230 | std::map<std::string, bufferlist> a_obj_omap, b_obj_omap; | |
231 | std::set<std::string> a_omap_keys, b_omap_keys; | |
11fdf7f2 | 232 | err = a_store->omap_get_keys(a_ch, a_obj, &a_omap_keys); |
7c673cae | 233 | if (err < 0) { |
28e407b8 AA |
234 | cout << "diff_objects getomap on A object " << coll << "/" << a_obj |
235 | << " returns " << err << std::endl; | |
7c673cae FG |
236 | ret = true; |
237 | } | |
11fdf7f2 | 238 | err = a_store->omap_get_values(a_ch, a_obj, a_omap_keys, &a_obj_omap); |
7c673cae | 239 | if (err < 0) { |
28e407b8 AA |
240 | cout << "diff_objects getomap on A object " << coll << "/" << a_obj |
241 | << " returns " << err << std::endl; | |
7c673cae FG |
242 | ret = true; |
243 | } | |
11fdf7f2 | 244 | err = b_store->omap_get_keys(b_ch, b_obj, &b_omap_keys); |
7c673cae | 245 | if (err < 0) { |
28e407b8 AA |
246 | cout << "diff_objects getomap on A object " << coll << "/" << b_obj |
247 | << " returns " << err << std::endl; | |
7c673cae FG |
248 | ret = true; |
249 | } | |
11fdf7f2 | 250 | err = b_store->omap_get_values(b_ch, b_obj, b_omap_keys, &b_obj_omap); |
7c673cae | 251 | if (err < 0) { |
28e407b8 AA |
252 | cout << "diff_objects getomap on A object " << coll << "/" << b_obj |
253 | << " returns " << err << std::endl; | |
7c673cae FG |
254 | ret = true; |
255 | } | |
256 | if (diff_omap(a_obj_omap, b_obj_omap)) { | |
28e407b8 | 257 | cout << "diff_objects omap mismatch on A object " |
7c673cae | 258 | << coll << "/" << a_obj << " and B object " |
28e407b8 AA |
259 | << coll << "/" << b_obj << std::endl; |
260 | cout << "a: " << a_obj_omap << std::endl; | |
261 | cout << "b: " << b_obj_omap << std::endl; | |
7c673cae FG |
262 | ret = true; |
263 | } | |
264 | } | |
265 | ||
266 | return ret; | |
267 | } | |
268 | ||
269 | bool FileStoreDiff::diff() | |
270 | { | |
271 | bool ret = false; | |
272 | ||
273 | std::vector<coll_t> a_coll_list, b_coll_list; | |
274 | a_store->list_collections(a_coll_list); | |
275 | b_store->list_collections(b_coll_list); | |
276 | ||
277 | std::vector<coll_t>::iterator it = b_coll_list.begin(); | |
278 | for (; it != b_coll_list.end(); ++it) { | |
279 | coll_t b_coll = *it; | |
280 | if (!a_store->collection_exists(b_coll)) { | |
28e407b8 | 281 | cout << "diff B coll " << b_coll.to_str() << " DNE on A" << std::endl; |
7c673cae FG |
282 | ret = true; |
283 | continue; | |
284 | } | |
285 | for (std::vector<coll_t>::iterator j = a_coll_list.begin(); | |
286 | j != a_coll_list.end(); ++j) { | |
287 | if (*j == *it) { | |
288 | a_coll_list.erase(j); | |
289 | break; | |
290 | } | |
291 | } | |
292 | ||
293 | if (diff_objects(a_store, b_store, b_coll)) | |
294 | ret = true; | |
295 | } | |
296 | for (std::vector<coll_t>::iterator it = a_coll_list.begin(); | |
297 | it != a_coll_list.end(); ++it) { | |
28e407b8 | 298 | cout << "diff A coll " << *it << " DNE on B" << std::endl; |
7c673cae FG |
299 | ret = true; |
300 | } | |
301 | ||
302 | return ret; | |
303 | } |