1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
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.
15 #include "SnapServer.h"
17 #include "osd/OSDMap.h"
18 #include "osdc/Objecter.h"
19 #include "mon/MonClient.h"
21 #include "include/types.h"
22 #include "messages/MMDSTableRequest.h"
23 #include "messages/MRemoveSnaps.h"
25 #include "msg/Messenger.h"
27 #include "common/config.h"
28 #include "include/assert.h"
30 #define dout_context g_ceph_context
31 #define dout_subsys ceph_subsys_mds
33 #define dout_prefix *_dout << "mds." << rank << ".snap "
36 void SnapServer::reset_state()
38 last_snap
= 1; /* snapid 1 reserved for initial root snaprealm */
40 need_to_purge
.clear();
42 // find any removed snapshot in data pools
43 if (mds
) { // only if I'm running in a live MDS
44 snapid_t first_free
= 0;
45 mds
->objecter
->with_osdmap([&](const OSDMap
& o
) {
46 for (const auto p
: mds
->mdsmap
->get_data_pools()) {
47 const pg_pool_t
*pi
= o
.get_pg_pool(p
);
49 // If pool isn't in OSDMap yet then can't have any snaps
50 // needing removal, skip.
53 if (!pi
->removed_snaps
.empty() &&
54 pi
->removed_snaps
.range_end() > first_free
)
55 first_free
= pi
->removed_snaps
.range_end();
58 if (first_free
> last_snap
)
59 last_snap
= first_free
;
66 void SnapServer::_prepare(bufferlist
&bl
, uint64_t reqid
, mds_rank_t bymds
)
68 bufferlist::iterator p
= bl
.begin();
78 ::decode(info
.ino
, p
);
80 ::decode(info
.name
, p
);
81 ::decode(info
.stamp
, p
);
82 info
.snapid
= ++last_snap
;
83 info
.long_name
= "create";
84 pending_update
[version
] = info
;
85 dout(10) << "prepare v" << version
<< " create " << info
<< dendl
;
87 pending_noop
.insert(version
);
88 dout(10) << "prepare v" << version
<< " noop" << dendl
;
91 ::encode(last_snap
, bl
);
95 case TABLE_OP_DESTROY
:
99 ::decode(ino
, p
); // not used, currently.
103 // bump last_snap... we use it as a version value on the snaprealm.
106 pending_destroy
[version
] = pair
<snapid_t
,snapid_t
>(snapid
, last_snap
);
107 dout(10) << "prepare v" << version
<< " destroy " << snapid
<< " seq " << last_snap
<< dendl
;
110 ::encode(last_snap
, bl
);
114 case TABLE_OP_UPDATE
:
117 ::decode(info
.ino
, p
);
118 ::decode(info
.snapid
, p
);
119 ::decode(info
.name
, p
);
120 ::decode(info
.stamp
, p
);
121 info
.long_name
= "update";
124 // bump last_snap... we use it as a version value on the snaprealm.
126 pending_update
[version
] = info
;
127 dout(10) << "prepare v" << version
<< " update " << info
<< dendl
;
130 ::encode(last_snap
, bl
);
140 bool SnapServer::_is_prepared(version_t tid
) const
143 pending_update
.count(tid
) ||
144 pending_destroy
.count(tid
);
147 bool SnapServer::_commit(version_t tid
, MMDSTableRequest
*req
)
149 if (pending_update
.count(tid
)) {
150 SnapInfo
&info
= pending_update
[tid
];
152 if (info
.long_name
.empty())
155 opname
.swap(info
.long_name
);
156 if (info
.stamp
== utime_t() && snaps
.count(info
.snapid
))
157 info
.stamp
= snaps
[info
.snapid
].stamp
;
158 dout(7) << "commit " << tid
<< " " << opname
<< " " << info
<< dendl
;
159 snaps
[info
.snapid
] = info
;
160 pending_update
.erase(tid
);
163 else if (pending_destroy
.count(tid
)) {
164 snapid_t sn
= pending_destroy
[tid
].first
;
165 snapid_t seq
= pending_destroy
[tid
].second
;
166 dout(7) << "commit " << tid
<< " destroy " << sn
<< " seq " << seq
<< dendl
;
169 for (const auto p
: mds
->mdsmap
->get_data_pools()) {
170 need_to_purge
[p
].insert(sn
);
171 need_to_purge
[p
].insert(seq
);
174 pending_destroy
.erase(tid
);
176 else if (pending_noop
.count(tid
)) {
177 dout(7) << "commit " << tid
<< " noop" << dendl
;
178 pending_noop
.erase(tid
);
189 void SnapServer::_rollback(version_t tid
)
191 if (pending_update
.count(tid
)) {
192 SnapInfo
&info
= pending_update
[tid
];
194 if (info
.long_name
.empty())
197 opname
.swap(info
.long_name
);
198 dout(7) << "rollback " << tid
<< " " << opname
<< " " << info
<< dendl
;
199 pending_update
.erase(tid
);
202 else if (pending_destroy
.count(tid
)) {
203 dout(7) << "rollback " << tid
<< " destroy " << pending_destroy
[tid
] << dendl
;
204 pending_destroy
.erase(tid
);
207 else if (pending_noop
.count(tid
)) {
208 dout(7) << "rollback " << tid
<< " noop" << dendl
;
209 pending_noop
.erase(tid
);
220 void SnapServer::_server_update(bufferlist
& bl
)
222 bufferlist::iterator p
= bl
.begin();
223 map
<int, vector
<snapid_t
> > purge
;
226 dout(7) << "_server_update purged " << purge
<< dendl
;
227 for (map
<int, vector
<snapid_t
> >::iterator p
= purge
.begin();
230 for (vector
<snapid_t
>::iterator q
= p
->second
.begin();
231 q
!= p
->second
.end();
233 need_to_purge
[p
->first
].erase(*q
);
234 if (need_to_purge
[p
->first
].empty())
235 need_to_purge
.erase(p
->first
);
241 void SnapServer::handle_query(MMDSTableRequest
*req
)
248 void SnapServer::check_osd_map(bool force
)
250 if (!force
&& version
== last_checked_osdmap
) {
251 dout(10) << "check_osd_map - version unchanged" << dendl
;
254 dout(10) << "check_osd_map need_to_purge=" << need_to_purge
<< dendl
;
256 map
<int, vector
<snapid_t
> > all_purge
;
257 map
<int, vector
<snapid_t
> > all_purged
;
259 mds
->objecter
->with_osdmap(
260 [this, &all_purged
, &all_purge
](const OSDMap
& osdmap
) {
261 for (const auto& p
: need_to_purge
) {
263 const pg_pool_t
*pi
= osdmap
.get_pg_pool(id
);
265 // The pool is gone. So are the snapshots.
266 all_purged
[id
] = std::vector
<snapid_t
>(p
.second
.begin(),
271 for (const auto& q
: p
.second
) {
272 if (pi
->is_removed_snap(q
)) {
273 dout(10) << " osdmap marks " << q
<< " as removed" << dendl
;
274 all_purged
[id
].push_back(q
);
276 all_purge
[id
].push_back(q
);
282 if (!all_purged
.empty()) {
283 // prepare to remove from need_to_purge list
285 ::encode(all_purged
, bl
);
286 do_server_update(bl
);
289 if (!all_purge
.empty()) {
290 dout(10) << "requesting removal of " << all_purge
<< dendl
;
291 MRemoveSnaps
*m
= new MRemoveSnaps(all_purge
);
292 mon_client
->send_mon_message(m
);
295 last_checked_osdmap
= version
;
299 void SnapServer::dump(Formatter
*f
) const
301 f
->open_object_section("snapserver");
303 f
->dump_int("last_snap", last_snap
.val
);
305 f
->open_array_section("pending_noop");
306 for(set
<version_t
>::const_iterator i
= pending_noop
.begin(); i
!= pending_noop
.end(); ++i
) {
307 f
->dump_unsigned("version", *i
);
311 f
->open_array_section("snaps");
312 for (map
<snapid_t
, SnapInfo
>::const_iterator i
= snaps
.begin(); i
!= snaps
.end(); ++i
) {
313 f
->open_object_section("snap");
319 f
->open_object_section("need_to_purge");
320 for (map
<int, set
<snapid_t
> >::const_iterator i
= need_to_purge
.begin(); i
!= need_to_purge
.end(); ++i
) {
321 stringstream pool_id
;
323 f
->open_array_section(pool_id
.str().c_str());
324 for (set
<snapid_t
>::const_iterator s
= i
->second
.begin(); s
!= i
->second
.end(); ++s
) {
325 f
->dump_unsigned("snapid", s
->val
);
331 f
->open_array_section("pending_update");
332 for(map
<version_t
, SnapInfo
>::const_iterator i
= pending_update
.begin(); i
!= pending_update
.end(); ++i
) {
333 f
->open_object_section("snap");
334 f
->dump_unsigned("version", i
->first
);
335 f
->open_object_section("snapinfo");
342 f
->open_array_section("pending_destroy");
343 for(map
<version_t
, pair
<snapid_t
, snapid_t
> >::const_iterator i
= pending_destroy
.begin(); i
!= pending_destroy
.end(); ++i
) {
344 f
->open_object_section("snap");
345 f
->dump_unsigned("version", i
->first
);
346 f
->dump_unsigned("removed_snap", i
->second
.first
);
347 f
->dump_unsigned("seq", i
->second
.second
);
355 void SnapServer::generate_test_instances(list
<SnapServer
*>& ls
)
357 list
<SnapInfo
*> snapinfo_instances
;
358 SnapInfo::generate_test_instances(snapinfo_instances
);
359 SnapInfo populated_snapinfo
= *(snapinfo_instances
.back());
360 for (list
<SnapInfo
*>::iterator i
= snapinfo_instances
.begin(); i
!= snapinfo_instances
.end(); ++i
) {
364 SnapServer
*blank
= new SnapServer();
366 SnapServer
*populated
= new SnapServer();
367 populated
->last_snap
= 123;
368 populated
->snaps
[456] = populated_snapinfo
;
369 populated
->need_to_purge
[2].insert(012);
370 populated
->pending_update
[234] = populated_snapinfo
;
371 populated
->pending_destroy
[345].first
= 567;
372 populated
->pending_destroy
[345].second
= 768;
373 populated
->pending_noop
.insert(890);
375 ls
.push_back(populated
);