]>
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) 2014 Red Hat | |
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 | */ | |
14 | ||
15 | #ifndef SCRUBSTACK_H_ | |
16 | #define SCRUBSTACK_H_ | |
17 | ||
18 | #include "CDir.h" | |
19 | #include "CDentry.h" | |
20 | #include "CInode.h" | |
21 | #include "MDSContext.h" | |
22 | #include "ScrubHeader.h" | |
23 | ||
24 | #include "include/elist.h" | |
25 | ||
26 | class MDCache; | |
27 | class Finisher; | |
28 | ||
29 | class ScrubStack { | |
30 | protected: | |
31 | /// A finisher needed so that we don't re-enter kick_off_scrubs | |
32 | Finisher *finisher; | |
33 | ||
34 | /// The stack of dentries we want to scrub | |
35 | elist<CInode*> inode_stack; | |
36 | /// current number of dentries we're actually scrubbing | |
37 | int scrubs_in_progress; | |
38 | ScrubStack *scrubstack; // hack for dout | |
39 | int stack_size; | |
40 | ||
41 | class C_KickOffScrubs : public MDSInternalContext { | |
42 | ScrubStack *stack; | |
43 | public: | |
44 | C_KickOffScrubs(MDCache *mdcache, ScrubStack *s); | |
45 | void finish(int r) override { } | |
46 | void complete(int r) override { | |
47 | stack->scrubs_in_progress--; | |
48 | stack->kick_off_scrubs(); | |
49 | // don't delete self | |
50 | } | |
51 | }; | |
52 | C_KickOffScrubs scrub_kick; | |
53 | ||
54 | public: | |
55 | MDCache *mdcache; | |
56 | ScrubStack(MDCache *mdc, Finisher *finisher_) : | |
57 | finisher(finisher_), | |
58 | inode_stack(member_offset(CInode, item_scrub)), | |
59 | scrubs_in_progress(0), | |
60 | scrubstack(this), | |
61 | stack_size(0), | |
62 | scrub_kick(mdc, this), | |
63 | mdcache(mdc) {} | |
64 | ~ScrubStack() { | |
65 | assert(inode_stack.empty()); | |
66 | assert(!scrubs_in_progress); | |
67 | } | |
68 | /** | |
69 | * Put a inode on the top of the scrub stack, so it is the highest priority. | |
70 | * If there are other scrubs in progress, they will not continue scrubbing new | |
71 | * entries until this one is completed. | |
72 | * @param in The inodey to scrub | |
73 | * @param header The ScrubHeader propagated from whereever this scrub | |
74 | * was initiated | |
75 | */ | |
b32b8144 | 76 | void enqueue_inode_top(CInode *in, ScrubHeaderRef& header, |
7c673cae FG |
77 | MDSInternalContextBase *on_finish) { |
78 | enqueue_inode(in, header, on_finish, true); | |
79 | } | |
80 | /** Like enqueue_inode_top, but we wait for all pending scrubs before | |
81 | * starting this one. | |
82 | */ | |
b32b8144 | 83 | void enqueue_inode_bottom(CInode *in, ScrubHeaderRef& header, |
7c673cae FG |
84 | MDSInternalContextBase *on_finish) { |
85 | enqueue_inode(in, header, on_finish, false); | |
86 | } | |
87 | ||
88 | private: | |
89 | /** | |
90 | * Put the inode at either the top or bottom of the stack, with | |
91 | * the given scrub params, and then try and kick off more scrubbing. | |
92 | */ | |
b32b8144 | 93 | void enqueue_inode(CInode *in, ScrubHeaderRef& header, |
7c673cae | 94 | MDSInternalContextBase *on_finish, bool top); |
b32b8144 | 95 | void _enqueue_inode(CInode *in, CDentry *parent, ScrubHeaderRef& header, |
7c673cae FG |
96 | MDSInternalContextBase *on_finish, bool top); |
97 | /** | |
98 | * Kick off as many scrubs as are appropriate, based on the current | |
99 | * state of the stack. | |
100 | */ | |
101 | void kick_off_scrubs(); | |
102 | /** | |
103 | * Push a indoe on top of the stack. | |
104 | */ | |
105 | inline void push_inode(CInode *in); | |
106 | /** | |
107 | * Push a inode to the bottom of the stack. | |
108 | */ | |
109 | inline void push_inode_bottom(CInode *in); | |
110 | /** | |
111 | * Pop the given inode off the stack. | |
112 | */ | |
113 | inline void pop_inode(CInode *in); | |
114 | ||
115 | /** | |
116 | * Scrub a file inode. | |
117 | * @param in The indoe to scrub | |
118 | */ | |
119 | void scrub_file_inode(CInode *in); | |
120 | ||
121 | /** | |
122 | * Callback from completion of CInode::validate_disk_state | |
123 | * @param in The inode we were validating | |
124 | * @param r The return status from validate_disk_state | |
125 | * @param result Populated results from validate_disk_state | |
126 | */ | |
127 | void _validate_inode_done(CInode *in, int r, | |
128 | const CInode::validated_data &result); | |
129 | friend class C_InodeValidated; | |
130 | ||
131 | /** | |
132 | * Make progress on scrubbing a directory-representing dirfrag and | |
133 | * its children.. | |
134 | * | |
135 | * 1) Select the next dirfrag which hasn't been scrubbed, and make progress | |
136 | * on it if possible. | |
137 | * | |
138 | * 2) If not, move on to the next dirfrag and start it up, if any. | |
139 | * | |
140 | * 3) If waiting for results from dirfrag scrubs, do nothing. | |
141 | * | |
142 | * 4) If all dirfrags have been scrubbed, scrub my inode. | |
143 | * | |
144 | * @param in The CInode to scrub as a directory | |
145 | * @param added_dentries set to true if we pushed some of our children | |
146 | * onto the ScrubStack | |
147 | * @param is_terminal set to true if there are no descendant dentries | |
148 | * remaining to start scrubbing. | |
149 | * @param done set to true if we and all our children have finished scrubbing | |
150 | */ | |
151 | void scrub_dir_inode(CInode *in, bool *added_children, bool *is_terminal, | |
152 | bool *done); | |
153 | /** | |
154 | * Make progress on scrubbing a dirfrag. It may return after each of the | |
155 | * following steps, but will report making progress on each one. | |
156 | * | |
157 | * 1) enqueues the next unscrubbed child directory dentry at the | |
158 | * top of the stack. | |
159 | * | |
160 | * 2) Initiates a scrub on the next unscrubbed file dentry | |
161 | * | |
162 | * If there are scrubs currently in progress on child dentries, no more child | |
163 | * dentries to scrub, and this function is invoked, it will report no | |
164 | * progress. Try again later. | |
165 | * | |
166 | */ | |
b32b8144 | 167 | void scrub_dirfrag(CDir *dir, ScrubHeaderRef& header, |
7c673cae FG |
168 | bool *added_children, bool *is_terminal, bool *done); |
169 | /** | |
170 | * Scrub a directory-representing dentry. | |
171 | * | |
172 | * @param in The directory inode we're doing final scrub on. | |
173 | */ | |
174 | void scrub_dir_inode_final(CInode *in); | |
175 | ||
176 | /** | |
177 | * Get a CDir into memory, and return it if it's already complete. | |
178 | * Otherwise, fetch it and kick off scrubbing when done. | |
179 | * | |
180 | * @param in The Inode to get the next directory from | |
181 | * @param new_dir The CDir we're returning to you. NULL if | |
182 | * not ready yet or there aren't any. | |
183 | * @returns false if you have to wait, true if there's no work | |
184 | * left to do (we returned it, or there are none left in this inode). | |
185 | */ | |
186 | bool get_next_cdir(CInode *in, CDir **new_dir); | |
187 | ||
188 | }; | |
189 | ||
190 | #endif /* SCRUBSTACK_H_ */ |