summaryrefslogtreecommitdiff
path: root/src/mds/snap.h
blob: 4c4eb07da09e103fb458e79af342f6bb54256ae6 (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
// -*- 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) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * 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 CEPH_MDS_SNAP_H
#define CEPH_MDS_SNAP_H

#include "mds_types.h"

#include "include/xlist.h"
#include "include/elist.h"
#include "common/snap_types.h"

/*
 * generic snap descriptor.
 */
struct SnapInfo {
  snapid_t snapid;
  inodeno_t ino;
  utime_t stamp;
  string name, long_name;
  
  void encode(bufferlist& bl) const {
    __u8 struct_v = 1;
    ::encode(struct_v, bl);
    ::encode(snapid, bl);
    ::encode(ino, bl);
    ::encode(stamp, bl);
    ::encode(name, bl);
  }
  void decode(bufferlist::iterator& bl) {
    __u8 struct_v;
    ::decode(struct_v, bl);
    ::decode(snapid, bl);
    ::decode(ino, bl);
    ::decode(stamp, bl);
    ::decode(name, bl);
  }
  const string& get_long_name();
};
WRITE_CLASS_ENCODER(SnapInfo)

inline ostream& operator<<(ostream& out, const SnapInfo &sn) {
  return out << "snap(" << sn.snapid
	     << " " << sn.ino
	     << " '" << sn.name
	     << "' " << sn.stamp << ")";
}



/*
 * SnapRealm - a subtree that shares the same set of snapshots.
 */
struct SnapRealm;
struct CapabilityGroup;
class CInode;
class MDCache;
class MDRequest;



#include "Capability.h"

struct snaplink_t {
  inodeno_t ino;
  snapid_t first;
  void encode(bufferlist& bl) const {
    __u8 struct_v = 1;
    ::encode(struct_v, bl);
    ::encode(ino, bl);
    ::encode(first, bl);
  }
  void decode(bufferlist::iterator& bl) {
    __u8 struct_v;
    ::decode(struct_v, bl);
    ::decode(ino, bl);
    ::decode(first, bl);
  }
};
WRITE_CLASS_ENCODER(snaplink_t)

inline ostream& operator<<(ostream& out, const snaplink_t &l)
{
  return out << l.ino << "@" << l.first;
}

// carry data about a specific version of a SnapRealm
struct sr_t {
  snapid_t seq;                     // basically, a version/seq # for changes to _this_ realm.
  snapid_t created;                 // when this realm was created.
  snapid_t last_created;            // last snap created in _this_ realm.
  snapid_t last_destroyed;          // seq for last removal
  snapid_t current_parent_since;
  map<snapid_t, SnapInfo> snaps;
  map<snapid_t, snaplink_t> past_parents;  // key is "last" (or NOSNAP)

  sr_t() :
    seq(0), created(0),
    last_created(0), last_destroyed(0),
    current_parent_since(1)
  {}


  void encode(bufferlist& bl) const {
    __u8 struct_v = 3;
    ::encode(struct_v, bl);
    ::encode(seq, bl);
    ::encode(created, bl);
    ::encode(last_created, bl);
    ::encode(last_destroyed, bl);
    ::encode(current_parent_since, bl);
    ::encode(snaps, bl);
    ::encode(past_parents, bl);
  }
  void decode(bufferlist::iterator& p) {
    __u8 struct_v;
    ::decode(struct_v, p);
    if (struct_v == 2)
      ::decode(struct_v, p);  // yes, really: extra byte for v2 encoding only, see 6ee52e7d.
    ::decode(seq, p);
    ::decode(created, p);
    ::decode(last_created, p);
    ::decode(last_destroyed, p);
    ::decode(current_parent_since, p);
    ::decode(snaps, p);
    ::decode(past_parents, p);
  }
};
WRITE_CLASS_ENCODER(sr_t);

struct SnapRealm {
  // realm state

  sr_t srnode;

  // in-memory state
  MDCache *mdcache;
  CInode *inode;

  bool open;                        // set to true once all past_parents are opened
  SnapRealm *parent;
  set<SnapRealm*> open_children;    // active children that are currently open
  map<inodeno_t,SnapRealm*> open_past_parents;  // these are explicitly pinned.

  // cache
  snapid_t cached_seq;           // max seq over self and all past+present parents.
  snapid_t cached_last_created;  // max last_created over all past+present parents
  snapid_t cached_last_destroyed;
  set<snapid_t> cached_snaps;
  SnapContext cached_snap_context;

  bufferlist cached_snap_trace;

  elist<CInode*> inodes_with_caps;             // for efficient realm splits
  map<client_t, xlist<Capability*>* > client_caps;   // to identify clients who need snap notifications

  SnapRealm(MDCache *c, CInode *in) : 
    srnode(),
    mdcache(c), inode(in),
    open(false), parent(0),
    inodes_with_caps(0) 
  { }

  bool exists(const string &name) {
    for (map<snapid_t,SnapInfo>::iterator p = srnode.snaps.begin();
	 p != srnode.snaps.end();
	 p++)
      if (p->second.name == name)
	return true;
    return false;
  }

  bool _open_parents(Context *retryorfinish, snapid_t first=1, snapid_t last=CEPH_NOSNAP);
  bool open_parents(Context *retryorfinish) {
    if (!_open_parents(retryorfinish))
      return false;
    delete retryorfinish;
    return true;
  }
  bool have_past_parents_open(snapid_t first=1, snapid_t last=CEPH_NOSNAP);
  void add_open_past_parent(SnapRealm *parent);
  void close_parents();

  void prune_past_parents();
  bool has_past_parents() { return !srnode.past_parents.empty(); }

  void build_snap_set(set<snapid_t>& s, 
		      snapid_t& max_seq, snapid_t& max_last_created, snapid_t& max_last_destroyed,
		      snapid_t first, snapid_t last);
  void get_snap_info(map<snapid_t,SnapInfo*>& infomap, snapid_t first=0, snapid_t last=CEPH_NOSNAP);

  const bufferlist& get_snap_trace();
  void build_snap_trace(bufferlist& snapbl);

  const string& get_snapname(snapid_t snapid, inodeno_t atino);
  snapid_t resolve_snapname(const string &name, inodeno_t atino, snapid_t first=0, snapid_t last=CEPH_NOSNAP);

  void check_cache();
  const set<snapid_t>& get_snaps();
  const SnapContext& get_snap_context();
  void invalidate_cached_snaps() {
    cached_seq = 0;
  }
  snapid_t get_last_created() {
    check_cache();
    return cached_last_created;
  }
  snapid_t get_last_destroyed() {
    check_cache();
    return cached_last_destroyed;
  }
  snapid_t get_newest_snap() {
    check_cache();
    if (cached_snaps.empty())
      return 0;
    else
      return *cached_snaps.rbegin();
  }
  snapid_t get_newest_seq() {
    check_cache();
    return cached_seq;
  }

  snapid_t get_snap_following(snapid_t follows) {
    check_cache();
    set<snapid_t> s = get_snaps();
    set<snapid_t>::iterator p = s.upper_bound(follows);
    if (p != s.end())
      return *p;
    return CEPH_NOSNAP;
  }

  void adjust_parent();

  void split_at(SnapRealm *child);
  void join(SnapRealm *child);

  void add_cap(client_t client, Capability *cap) {
    if (client_caps.count(client) == 0)
      client_caps[client] = new xlist<Capability*>;
    client_caps[client]->push_back(&cap->item_snaprealm_caps);
  }
  void remove_cap(client_t client, Capability *cap) {
    cap->item_snaprealm_caps.remove_myself();
    if (client_caps[client]->empty()) {
      delete client_caps[client];
      client_caps.erase(client);
    }
  }

};

ostream& operator<<(ostream& out, const SnapRealm &realm);





#endif