Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / tools / cephfs / JournalFilter.cc
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 john spray <john.spray@inktank.com>
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 #include "JournalFilter.h"
16
17 #include "common/ceph_argparse.h"
18
19 #include "mds/events/ESession.h"
20 #include "mds/events/EUpdate.h"
21
22 #define dout_context g_ceph_context
23 #define dout_subsys ceph_subsys_mds
24
25
26 const string JournalFilter::range_separator("..");
27
28
29 /*
30  * Return whether a LogEvent is to be included or excluded.
31  *
32  * The filter parameters are applied on an AND basis: if any
33  * condition is not met, the event is excluded.  Try to do
34  * the fastest checks first.
35  */
36 bool JournalFilter::apply(uint64_t pos, LogEvent &le) const
37 {
38   /* Filtering by journal offset range */
39   if (pos < range_start || pos >= range_end) {
40     return false;
41   }
42
43   /* Filtering by event type */
44   if (event_type != 0) {
45     if (le.get_type() != event_type) {
46       return false;
47     }
48   }
49
50   /* Filtering by client */
51   if (client_name.num()) {
52     EMetaBlob const *metablob = le.get_metablob();
53     if (metablob) {
54       if (metablob->get_client_name() != client_name) {
55         return false;
56       }
57     } else if (le.get_type() == EVENT_SESSION) {
58       ESession *es = reinterpret_cast<ESession*>(&le);
59       if (es->get_client_inst().name != client_name) {
60         return false;
61       }
62     } else {
63       return false;
64     }
65   }
66
67   /* Filtering by inode */
68   if (inode) {
69     EMetaBlob const *metablob = le.get_metablob();
70     if (metablob) {
71       std::set<inodeno_t> inodes;
72       metablob->get_inodes(inodes);
73       bool match_any = false;
74       for (std::set<inodeno_t>::iterator i = inodes.begin(); i != inodes.end(); ++i) {
75         if (*i == inode) {
76           match_any = true;
77           break;
78         }
79       }
80       if (!match_any) {
81         return false;
82       }
83     } else {
84       return false;
85     }
86   }
87
88   /* Filtering by frag and dentry */
89   if (!frag_dentry.empty() || frag.ino) {
90     EMetaBlob const *metablob = le.get_metablob();
91     if (metablob) {
92       std::map<dirfrag_t, std::set<std::string> > dentries;
93       metablob->get_dentries(dentries);
94
95       if (frag.ino) {
96         bool match_any = false;
97         for (std::map<dirfrag_t, std::set<std::string> >::iterator i = dentries.begin();
98             i != dentries.end(); ++i) {
99           if (i->first == frag) {
100             match_any = true;
101             break;
102           }
103         }
104         if (!match_any) {
105           return false;
106         }
107       }
108
109       if (!frag_dentry.empty()) {
110         bool match_any = false;
111         for (std::map<dirfrag_t, std::set<std::string> >::iterator i = dentries.begin();
112             i != dentries.end() && !match_any; ++i) {
113           std::set<std::string> const &names = i->second;
114           for (std::set<std::string>::iterator j = names.begin();
115               j != names.end() && !match_any; ++j) {
116             if (*j == frag_dentry) {
117               match_any = true;
118             }
119           }
120         }
121         if (!match_any) {
122           return false;
123         }
124       }
125
126     } else {
127       return false;
128     }
129   }
130
131   /* Filtering by file path */
132   if (!path_expr.empty()) {
133     EMetaBlob const *metablob = le.get_metablob();
134     if (metablob) {
135       std::vector<std::string> paths;
136       metablob->get_paths(paths);
137       bool match_any = false;
138       for (std::vector<std::string>::iterator p = paths.begin(); p != paths.end(); ++p) {
139         if ((*p).find(path_expr) != std::string::npos) {
140           match_any = true;
141           break;
142         }
143       }
144       if (!match_any) {
145         return false;
146       }
147     } else {
148       return false;
149     }
150   }
151
152   return true;
153 }
154
155
156 int JournalFilter::parse_args(
157   std::vector<const char*> &argv, 
158   std::vector<const char*>::iterator &arg)
159 {
160   while(arg != argv.end()) {
161     std::string arg_str;
162     if (ceph_argparse_witharg(argv, arg, &arg_str, "--range", (char*)NULL)) {
163       size_t sep_loc = arg_str.find(JournalFilter::range_separator);
164       if (sep_loc == std::string::npos || arg_str.size() <= JournalFilter::range_separator.size()) {
165         derr << "Invalid range '" << arg_str << "'" << dendl;
166         return -EINVAL;
167       }
168
169       // We have a lower bound
170       if (sep_loc > 0) {
171         std::string range_start_str = arg_str.substr(0, sep_loc); 
172         std::string parse_err;
173         range_start = strict_strtoll(range_start_str.c_str(), 0, &parse_err);
174         if (!parse_err.empty()) {
175           derr << "Invalid lower bound '" << range_start_str << "': " << parse_err << dendl;
176           return -EINVAL;
177         }
178       }
179
180       if (sep_loc < arg_str.size() - JournalFilter::range_separator.size()) {
181         std::string range_end_str = arg_str.substr(sep_loc + range_separator.size()); 
182         std::string parse_err;
183         range_end = strict_strtoll(range_end_str.c_str(), 0, &parse_err);
184         if (!parse_err.empty()) {
185           derr << "Invalid upper bound '" << range_end_str << "': " << parse_err << dendl;
186           return -EINVAL;
187         }
188       }
189     } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--path", (char*)NULL)) {
190       dout(4) << "Filtering by path '" << arg_str << "'" << dendl;
191       path_expr = arg_str;
192     } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--inode", (char*)NULL)) {
193       dout(4) << "Filtering by inode '" << arg_str << "'" << dendl;
194       std::string parse_err;
195       inode = strict_strtoll(arg_str.c_str(), 0, &parse_err);
196       if (!parse_err.empty()) {
197         derr << "Invalid inode '" << arg_str << "': " << parse_err << dendl;
198         return -EINVAL;
199       }
200     } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--type", (char*)NULL)) {
201       std::string parse_err;
202       event_type = LogEvent::str_to_type(arg_str);
203       if (event_type == LogEvent::EventType(-1)) {
204         derr << "Invalid event type '" << arg_str << "': " << parse_err << dendl;
205         return -EINVAL;
206       }
207
208     } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--frag", (char*)NULL)) {
209       std::string const frag_sep = ".";
210       size_t sep_loc = arg_str.find(frag_sep);
211       std::string inode_str;
212       std::string frag_str;
213       if (sep_loc != std::string::npos) {
214         inode_str = arg_str.substr(0, sep_loc);
215         frag_str = arg_str.substr(sep_loc + 1);
216       } else {
217         inode_str = arg_str;
218         frag_str = "0";
219       }
220
221       std::string parse_err;
222       inodeno_t frag_ino = strict_strtoll(inode_str.c_str(), 0, &parse_err);
223       if (!parse_err.empty()) {
224         derr << "Invalid inode '" << inode_str << "': " << parse_err << dendl;
225         return -EINVAL;
226       }
227
228       uint32_t frag_enc = strict_strtoll(frag_str.c_str(), 0, &parse_err);
229       if (!parse_err.empty()) {
230         derr << "Invalid frag '" << frag_str << "': " << parse_err << dendl;
231         return -EINVAL;
232       }
233
234       frag = dirfrag_t(frag_ino, frag_t(frag_enc));
235       dout(4) << "dirfrag filter: '" << frag << "'" << dendl;
236     } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--dname", (char*)NULL)) {
237       frag_dentry = arg_str;
238       dout(4) << "dentry filter: '" << frag_dentry << "'" << dendl;
239     } else if (ceph_argparse_witharg(argv, arg, &arg_str, "--client", (char*)NULL)) {
240       std::string parse_err;
241       int64_t client_num = strict_strtoll(arg_str.c_str(), 0, &parse_err);
242       if (!parse_err.empty()) {
243         derr << "Invalid client number " << arg_str << dendl;
244         return -EINVAL;
245       }
246       client_name = entity_name_t::CLIENT(client_num);
247     } else {
248       // We're done with args the filter understands
249       break;
250     }
251   }
252
253   return 0;
254 }
255
256 /**
257  * If the filter params are only range, then return
258  * true and set start & end.  Else return false.
259  *
260  * Use this to discover if the user has requested a contiguous range
261  * rather than any per-event filtering.
262  */
263 bool JournalFilter::get_range(uint64_t &start, uint64_t &end) const
264 {
265   if (!path_expr.empty()
266       || inode != 0
267       || event_type != 0
268       || frag.ino != 0
269       || client_name.num() != 0
270       || (range_start == 0 && range_end == (uint64_t)(-1))) {
271     return false;
272   } else {
273     start = range_start;
274     end = range_end;
275     return true;
276   }
277 }