1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2    	// vim: ts=8 sw=2 smarttab
3    	
4    	#include "CrushCompiler.h"
5    	
6    	#if defined(_AIX)
7    	#define EBADE ECORRUPT
8    	#endif
9    	
10   	#ifndef EBADE
11   	#define EBADE EFTYPE
12   	#endif
13   	#include <string>
14   	#include "common/errno.h"
15   	#include <boost/algorithm/string.hpp>
16   	
17   	using std::cout;
18   	using std::istream;
19   	using std::map;
20   	using std::ostream;
21   	using std::set;
22   	using std::string;
23   	using std::vector;
24   	
25   	// -------------
26   	
27   	static void print_type_name(ostream& out, int t, CrushWrapper &crush)
28   	{
29   	  const char *name = crush.get_type_name(t);
30   	  if (name)
31   	    out << name;
32   	  else if (t == 0)
33   	    out << "device";
34   	  else
35   	    out << "type" << t;
36   	}
37   	
38   	static void print_item_name(ostream& out, int t, CrushWrapper &crush)
39   	{
40   	  const char *name = crush.get_item_name(t);
41   	  if (name)
42   	    out << name;
43   	  else if (t >= 0)
44   	    out << "device" << t;
45   	  else
46   	    out << "bucket" << (-1-t);
47   	}
48   	
49   	static void print_bucket_class_ids(ostream& out, int t, CrushWrapper &crush)
50   	{
51   	  if (crush.class_bucket.count(t) == 0)
52   	    return;
53   	  auto &class_to_id = crush.class_bucket[t];
54   	  for (auto &i : class_to_id) {
55   	    int c = i.first;
56   	    int cid = i.second;
57   	    const char* class_name = crush.get_class_name(c);
58   	    ceph_assert(class_name);
59   	    out << "\tid " << cid << " class " << class_name << "\t\t# do not change unnecessarily\n";
60   	  }
61   	}
62   	
63   	static void print_item_class(ostream& out, int t, CrushWrapper &crush)
64   	{
65   	  const char *c = crush.get_item_class(t);
66   	  if (c)
67   	    out << " class " << c;
68   	}
69   	
70   	static void print_class(ostream& out, int t, CrushWrapper &crush)
71   	{
72   	  const char *c = crush.get_class_name(t);
73   	  if (c)
74   	    out << " class " << c;
75   	  else
76   	    out << " # unexpected class " << t;
77   	}
78   	
79   	static void print_rule_name(ostream& out, int t, CrushWrapper &crush)
80   	{
81   	  const char *name = crush.get_rule_name(t);
82   	  if (name)
83   	    out << name;
84   	  else
85   	    out << "rule" << t;
86   	}
87   	
88   	static void print_fixedpoint(ostream& out, int i)
89   	{
90   	  char s[20];
91   	  snprintf(s, sizeof(s), "%.3f", (float)i / (float)0x10000);
92   	  out << s;
93   	}
94   	
95   	int CrushCompiler::decompile_bucket_impl(int i, ostream &out)
96   	{
97   	  const char *name = crush.get_item_name(i);
98   	  if (name && !crush.is_valid_crush_name(name))
99   	    return 0;
100  	  int type = crush.get_bucket_type(i);
101  	  print_type_name(out, type, crush);
102  	  out << " ";
103  	  print_item_name(out, i, crush);
104  	  out << " {\n";
105  	  out << "\tid " << i << "\t\t# do not change unnecessarily\n";
106  	  print_bucket_class_ids(out, i, crush);
107  	
108  	  out << "\t# weight ";
109  	  print_fixedpoint(out, crush.get_bucket_weight(i));
110  	  out << "\n";
111  	
112  	  int n = crush.get_bucket_size(i);
113  	
114  	  int alg = crush.get_bucket_alg(i);
115  	  out << "\talg " << crush_bucket_alg_name(alg);
116  	
117  	  // notate based on alg type
118  	  bool dopos = false;
119  	  switch (alg) {
120  	  case CRUSH_BUCKET_UNIFORM:
121  	    out << "\t# do not change bucket size (" << n << ") unnecessarily";
122  	    dopos = true;
123  	    break;
124  	  case CRUSH_BUCKET_LIST:
125  	    out << "\t# add new items at the end; do not change order unnecessarily";
126  	    break;
127  	  case CRUSH_BUCKET_TREE:
128  	    out << "\t# do not change pos for existing items unnecessarily";
129  	    dopos = true;
130  	    break;
131  	  }
132  	  out << "\n";
133  	
134  	  int hash = crush.get_bucket_hash(i);
135  	  out << "\thash " << hash << "\t# " << crush_hash_name(hash) << "\n";
136  	
137  	  for (int j=0; j<n; j++) {
138  	    int item = crush.get_bucket_item(i, j);
139  	    int w = crush.get_bucket_item_weight(i, j);
140  	    out << "\titem ";
141  	    print_item_name(out, item, crush);
142  	    out << " weight ";
143  	    print_fixedpoint(out, w);
144  	    if (dopos) 
145  	      out << " pos " << j;
146  	    
147  	    out << "\n";
148  	  }
149  	  out << "}\n";
150  	  return 0;
151  	}
152  	
153  	/* Basically, we just descend recursively into all of the buckets,
154  	 * executing a depth-first traversal of the graph. Since the buckets form a
155  	 * directed acyclic graph, this should work just fine. The graph isn't
156  	 * necessarily a tree, so we have to keep track of what buckets we already
157  	 * outputted. We don't want to output anything twice. We also keep track of
158  	 * what buckets are in progress so that we can detect cycles. These can
159  	 * arise through user error.
160  	 */
161  	int CrushCompiler::decompile_bucket(int cur,
162  					    std::map<int, dcb_state_t>& dcb_states,
163  					    ostream &out)
164  	{
165  	  if ((cur == 0) || (!crush.bucket_exists(cur)))
166  	    return 0;
167  	
168  	  std::map<int, dcb_state_t>::iterator c = dcb_states.find(cur);
169  	  if (c == dcb_states.end()) {
170  	    // Mark this bucket as "in progress."
171  	    std::map<int, dcb_state_t>::value_type val(cur, DCB_STATE_IN_PROGRESS);
172  	    std::pair <std::map<int, dcb_state_t>::iterator, bool> rval
173  	      (dcb_states.insert(val));
174  	    ceph_assert(rval.second);
175  	    c = rval.first;
176  	  }
177  	  else if (c->second == DCB_STATE_DONE) {
178  	    // We already did this bucket.
179  	    return 0;
180  	  }
181  	  else if (c->second == DCB_STATE_IN_PROGRESS) {
182  	    err << "decompile_crush_bucket: logic error: tried to decompile "
183  		"a bucket that is already being decompiled" << std::endl;
184  	    return -EBADE;
185  	  }
186  	  else {
187  	    err << "decompile_crush_bucket: logic error: illegal bucket state! "
188  		 << c->second << std::endl;
189  	    return -EBADE;
190  	  }
191  	
192  	  int bsize = crush.get_bucket_size(cur);
193  	  for (int i = 0; i < bsize; ++i) {
194  	    int item = crush.get_bucket_item(cur, i);
195  	    std::map<int, dcb_state_t>::iterator d = dcb_states.find(item);
196  	    if (d == dcb_states.end()) {
197  	      int ret = decompile_bucket(item, dcb_states, out);
198  	      if (ret)
199  		return ret;
200  	    }
201  	    else if (d->second == DCB_STATE_IN_PROGRESS) {
202  	      err << "decompile_crush_bucket: error: while trying to output bucket "
203  		   << cur << ", we found out that it contains one of the buckets that "
204  		   << "contain it. This is not allowed. The buckets must form a "
205  		   <<  "directed acyclic graph." << std::endl;
206  	      return -EINVAL;
207  	    }
208  	    else if (d->second != DCB_STATE_DONE) {
209  	      err << "decompile_crush_bucket: logic error: illegal bucket state "
210  		   << d->second << std::endl;
211  	      return -EBADE;
212  	    }
213  	  }
214  	  decompile_bucket_impl(cur, out);
215  	  c->second = DCB_STATE_DONE;
216  	  return 0;
217  	}
218  	
219  	int CrushCompiler::decompile_weight_set_weights(crush_weight_set weight_set,
220  	                                                ostream &out)
221  	{
222  	  out << "      [ ";
223  	  for (__u32 i = 0; i < weight_set.size; i++) {
224  	    print_fixedpoint(out, weight_set.weights[i]);
225  	    out << " ";
226  	  }
227  	  out << "]\n";
228  	  return 0;
229  	}
230  	
231  	int CrushCompiler::decompile_weight_set(crush_weight_set *weight_set,
232  	                                        __u32 size,
233  	                                        ostream &out)
234  	{
235  	  out << "    weight_set [\n";
236  	  for (__u32 i = 0; i < size; i++) {
237  	    int r = decompile_weight_set_weights(weight_set[i], out);
238  	    if (r < 0)
239  	      return r;
240  	  }
241  	  out << "    ]\n";
242  	  return 0;
243  	}
244  	
245  	int CrushCompiler::decompile_ids(__s32 *ids,
246  	                                 __u32 size,
247  	                                 ostream &out)
248  	{
249  	  out << "    ids [ ";
250  	  for (__u32 i = 0; i < size; i++)
251  	    out << ids[i] << " ";
252  	  out << "]\n";
253  	  return 0;
254  	}
255  	
256  	int CrushCompiler::decompile_choose_arg(crush_choose_arg *arg,
257  	                                        int bucket_id,
258  	                                        ostream &out)
259  	{
260  	  int r;
261  	  out << "  {\n";
262  	  out << "    bucket_id " << bucket_id << "\n";
263  	  if (arg->weight_set_positions > 0) {
264  	    r = decompile_weight_set(arg->weight_set, arg->weight_set_positions, out);
265  	    if (r < 0)
266  	      return r;
267  	  }
268  	  if (arg->ids_size > 0) {
269  	    r = decompile_ids(arg->ids, arg->ids_size, out);
270  	    if (r < 0)
271  	      return r;
272  	  }
273  	  out << "  }\n";
274  	  return 0;
275  	}
276  	
277  	int CrushCompiler::decompile_choose_arg_map(crush_choose_arg_map arg_map,
278  	                                            ostream &out)
279  	{
280  	  for (__u32 i = 0; i < arg_map.size; i++) {
281  	    if ((arg_map.args[i].ids_size == 0) &&
282  	        (arg_map.args[i].weight_set_positions == 0))
283  	      continue;
284  	    int r = decompile_choose_arg(&arg_map.args[i], -1-i, out);
285  	    if (r < 0)
286  	      return r;
287  	  }
288  	  return 0;
289  	}
290  	
291  	int CrushCompiler::decompile_choose_args(const std::pair<const long unsigned int, crush_choose_arg_map> &i,
292  	                                         ostream &out)
293  	{
294  	  out << "choose_args " << i.first << " {\n";
295  	  int r = decompile_choose_arg_map(i.second, out);
296  	  if (r < 0)
297  	    return r;
298  	  out << "}\n";
299  	  return 0;
300  	}
301  	
302  	int CrushCompiler::decompile(ostream &out)
303  	{
304  	  out << "# begin crush map\n";
305  	
306  	  // only dump tunables if they differ from the defaults
307  	  if (crush.get_choose_local_tries() != 2)
308  	    out << "tunable choose_local_tries " << crush.get_choose_local_tries() << "\n";
309  	  if (crush.get_choose_local_fallback_tries() != 5)
310  	    out << "tunable choose_local_fallback_tries " << crush.get_choose_local_fallback_tries() << "\n";
311  	  if (crush.get_choose_total_tries() != 19)
312  	    out << "tunable choose_total_tries " << crush.get_choose_total_tries() << "\n";
313  	  if (crush.get_chooseleaf_descend_once() != 0)
314  	    out << "tunable chooseleaf_descend_once " << crush.get_chooseleaf_descend_once() << "\n";
315  	  if (crush.get_chooseleaf_vary_r() != 0)
316  	    out << "tunable chooseleaf_vary_r " << crush.get_chooseleaf_vary_r() << "\n";
317  	  if (crush.get_chooseleaf_stable() != 0)
318  	    out << "tunable chooseleaf_stable " << crush.get_chooseleaf_stable() << "\n";
319  	  if (crush.get_straw_calc_version() != 0)
320  	    out << "tunable straw_calc_version " << crush.get_straw_calc_version() << "\n";
321  	  if (crush.get_allowed_bucket_algs() != CRUSH_LEGACY_ALLOWED_BUCKET_ALGS)
322  	    out << "tunable allowed_bucket_algs " << crush.get_allowed_bucket_algs()
323  		<< "\n";
324  	
325  	  out << "\n# devices\n";
326  	  for (int i=0; i<crush.get_max_devices(); i++) {
327  	    const char *name = crush.get_item_name(i);
328  	    if (name) {
329  	      out << "device " << i << " " << name;
330  	      print_item_class(out, i, crush);
331  	      out << "\n";
332  	    }
333  	  }
334  	  
335  	  out << "\n# types\n";
336  	  int n = crush.get_num_type_names();
337  	  for (int i=0; n; i++) {
338  	    const char *name = crush.get_type_name(i);
339  	    if (!name) {
340  	      if (i == 0) out << "type 0 osd\n";
341  	      continue;
342  	    }
343  	    n--;
344  	    out << "type " << i << " " << name << "\n";
345  	  }
346  	
347  	  out << "\n# buckets\n";
348  	  std::map<int, dcb_state_t> dcb_states;
349  	  for (int bucket = -1; bucket > -1-crush.get_max_buckets(); --bucket) {
350  	    int ret = decompile_bucket(bucket, dcb_states, out);
351  	    if (ret)
352  	      return ret;
353  	  }
354  	
355  	  out << "\n# rules\n";
356  	  for (int i=0; i<crush.get_max_rules(); i++) {
357  	    if (!crush.rule_exists(i))
358  	      continue;
359  	    out << "rule ";
360  	    if (crush.get_rule_name(i))
361  	      print_rule_name(out, i, crush);
362  	    out << " {\n";
363  	    out << "\tid " << i << "\n";
364  	    if (i != crush.get_rule_mask_ruleset(i)) {
365  	      out << "\t# WARNING: ruleset " << crush.get_rule_mask_ruleset(i) << " != id " << i << "; this will not recompile to the same map\n";
366  	    }
367  	
368  	    switch (crush.get_rule_mask_type(i)) {
369  	    case CEPH_PG_TYPE_REPLICATED:
370  	      out << "\ttype replicated\n";
371  	      break;
372  	    case CEPH_PG_TYPE_ERASURE:
373  	      out << "\ttype erasure\n";
374  	      break;
375  	    default:
376  	      out << "\ttype " << crush.get_rule_mask_type(i) << "\n";
377  	    }
378  	
379  	    out << "\tmin_size " << crush.get_rule_mask_min_size(i) << "\n";
380  	    out << "\tmax_size " << crush.get_rule_mask_max_size(i) << "\n";
381  	
382  	    for (int j=0; j<crush.get_rule_len(i); j++) {
383  	      switch (crush.get_rule_op(i, j)) {
384  	      case CRUSH_RULE_NOOP:
385  		out << "\tstep noop\n";
386  		break;
387  	      case CRUSH_RULE_TAKE:
388  		out << "\tstep take ";
389  		{
390  	          int step_item = crush.get_rule_arg1(i, j);
391  	          int original_item;
392  	          int c;
393  	          int res = crush.split_id_class(step_item, &original_item, &c);
394  	          if (res < 0)
395  	            return res;
396  		  if (c >= 0)
397  	            step_item = original_item;
398  	          print_item_name(out, step_item, crush);
399  		  if (c >= 0)
400  		    print_class(out, c, crush);
401  		}
402  		out << "\n";
403  		break;
404  	      case CRUSH_RULE_EMIT:
405  		out << "\tstep emit\n";
406  		break;
407  	      case CRUSH_RULE_SET_CHOOSE_TRIES:
408  		out << "\tstep set_choose_tries " << crush.get_rule_arg1(i, j)
409  		    << "\n";
410  		break;
411  	      case CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES:
412  		out << "\tstep set_choose_local_tries " << crush.get_rule_arg1(i, j)
413  		    << "\n";
414  		break;
415  	      case CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES:
416  		out << "\tstep set_choose_local_fallback_tries " << crush.get_rule_arg1(i, j)
417  		    << "\n";
418  		break;
419  	      case CRUSH_RULE_SET_CHOOSELEAF_TRIES:
420  		out << "\tstep set_chooseleaf_tries " << crush.get_rule_arg1(i, j)
421  		    << "\n";
422  		break;
423  	      case CRUSH_RULE_SET_CHOOSELEAF_VARY_R:
424  		out << "\tstep set_chooseleaf_vary_r " << crush.get_rule_arg1(i, j)
425  		    << "\n";
426  		break;
427  	      case CRUSH_RULE_SET_CHOOSELEAF_STABLE:
428  		out << "\tstep set_chooseleaf_stable " << crush.get_rule_arg1(i, j)
429  		    << "\n";
430  		break;
431  	      case CRUSH_RULE_CHOOSE_FIRSTN:
432  		out << "\tstep choose firstn "
433  		    << crush.get_rule_arg1(i, j) 
434  		    << " type ";
435  		print_type_name(out, crush.get_rule_arg2(i, j), crush);
436  		out << "\n";
437  		break;
438  	      case CRUSH_RULE_CHOOSE_INDEP:
439  		out << "\tstep choose indep "
440  		    << crush.get_rule_arg1(i, j) 
441  		    << " type ";
442  		print_type_name(out, crush.get_rule_arg2(i, j), crush);
443  		out << "\n";
444  		break;
445  	      case CRUSH_RULE_CHOOSELEAF_FIRSTN:
446  		out << "\tstep chooseleaf firstn "
447  		    << crush.get_rule_arg1(i, j) 
448  		    << " type ";
449  		print_type_name(out, crush.get_rule_arg2(i, j), crush);
450  		out << "\n";
451  		break;
452  	      case CRUSH_RULE_CHOOSELEAF_INDEP:
453  		out << "\tstep chooseleaf indep "
454  		    << crush.get_rule_arg1(i, j) 
455  		    << " type ";
456  		print_type_name(out, crush.get_rule_arg2(i, j), crush);
457  		out << "\n";
458  		break;
459  	      }
460  	    }
461  	    out << "}\n";
462  	  }
463  	  if (crush.choose_args.size() > 0) {
464  	    out << "\n# choose_args\n";
465  	    for (auto i : crush.choose_args) {
466  	      int ret = decompile_choose_args(i, out);
467  	      if (ret)
468  	        return ret;
469  	    }
470  	  }
471  	  out << "\n# end crush map" << std::endl;
472  	  return 0;
473  	}
474  	
475  	
476  	// ================================================================
477  	
478  	string CrushCompiler::string_node(node_t &node)
479  	{
480  	  return boost::trim_copy(string(node.value.begin(), node.value.end()));
481  	}
482  	
483  	int CrushCompiler::int_node(node_t &node) 
484  	{
485  	  string str = string_node(node);
486  	  return strtol(str.c_str(), 0, 10);
487  	}
488  	
489  	float CrushCompiler::float_node(node_t &node)
490  	{
491  	  string s = string_node(node);
492  	  return strtof(s.c_str(), 0);
493  	}
494  	
495  	int CrushCompiler::parse_device(iter_t const& i)
496  	{
497  	  int id = int_node(i->children[1]);
498  	
499  	  string name = string_node(i->children[2]);
500  	  crush.set_item_name(id, name.c_str());
501  	  if (item_id.count(name)) {
502  	    err << "item " << name << " defined twice" << std::endl;
503  	    return -1;
504  	  }    
505  	  item_id[name] = id;
506  	  id_item[id] = name;
507  	
508  	  if (verbose) err << "device " << id << " '" << name << "'";
509  	
510  	  if (i->children.size() > 3) {
511  	    string c = string_node(i->children[4]);
512  	    crush.set_item_class(id, c);
513  	    if (verbose) err << " class" << " '" << c << "'" << std::endl;
514  	  } else {
515  	    if (verbose) err << std::endl;
516  	  }
517  	  return 0;
518  	}
519  	
520  	int CrushCompiler::parse_tunable(iter_t const& i)
521  	{
522  	  string name = string_node(i->children[1]);
523  	  int val = int_node(i->children[2]);
524  	
525  	  if (name == "choose_local_tries")
526  	    crush.set_choose_local_tries(val);
527  	  else if (name == "choose_local_fallback_tries")
528  	    crush.set_choose_local_fallback_tries(val);
529  	  else if (name == "choose_total_tries")
530  	    crush.set_choose_total_tries(val);
531  	  else if (name == "chooseleaf_descend_once")
532  	    crush.set_chooseleaf_descend_once(val);
533  	  else if (name == "chooseleaf_vary_r")
534  	    crush.set_chooseleaf_vary_r(val);
535  	  else if (name == "chooseleaf_stable")
536  	    crush.set_chooseleaf_stable(val);
537  	  else if (name == "straw_calc_version")
538  	    crush.set_straw_calc_version(val);
539  	  else if (name == "allowed_bucket_algs")
540  	    crush.set_allowed_bucket_algs(val);
541  	  else {
542  	    err << "tunable " << name << " not recognized" << std::endl;
543  	    return -1;
544  	  }
545  	
546  	  /*
547  	
548  	    current crop of tunables are all now "safe".  re-enable this when we
549  	    add new ones that are ... new.
550  	
551  	  if (!unsafe_tunables) {
552  	    err << "tunables are NOT FULLY IMPLEMENTED; enable with --enable-unsafe-tunables to enable this feature" << std::endl;
553  	    return -1;
554  	  }
555  	  */
556  	
557  	  if (verbose) err << "tunable " << name << " " << val << std::endl;
558  	  return 0;
559  	}
560  	
561  	int CrushCompiler::parse_bucket_type(iter_t const& i)
562  	{
563  	  int id = int_node(i->children[1]);
564  	  string name = string_node(i->children[2]);
565  	  if (verbose) err << "type " << id << " '" << name << "'" << std::endl;
566  	  type_id[name] = id;
567  	  crush.set_type_name(id, name.c_str());
568  	  return 0;
569  	}
570  	
571  	int CrushCompiler::parse_bucket(iter_t const& i)
572  	{
573  	  string tname = string_node(i->children[0]);
574  	  if (!type_id.count(tname)) {
575  	    err << "bucket type '" << tname << "' is not defined" << std::endl;
576  	    return -1;
577  	  }
578  	  int type = type_id[tname];
579  	
580  	  string name = string_node(i->children[1]);
581  	  if (item_id.count(name)) {
582  	    err << "bucket or device '" << name << "' is already defined" << std::endl;
583  	    return -1;
584  	  }
585  	
586  	  int id = 0;  // none, yet!
587  	  int alg = -1;
588  	  int hash = 0;
589  	  set<int> used_items;
590  	  int size = 0;
591  	  map<int32_t, int32_t> class_id;
592  	  
593  	  for (unsigned p=3; p<i->children.size()-1; p++) {
594  	    iter_t sub = i->children.begin() + p;
595  	    string tag = string_node(sub->children[0]);
596  	    //err << "tag " << tag << std::endl;
597  	    if (tag == "id") {
598  	      int maybe_id = int_node(sub->children[1]);
599  	      if (verbose) err << "bucket " << name << " id " << maybe_id;
600  	      if (sub->children.size() > 2) {
601  	        string class_name = string_node(sub->children[3]);
602  	        // note that we do not verify class existence here,
603  	        // as this bucket might come from an empty shadow tree
604  	        // which currently has no OSDs but is still referenced by a rule!
605  	        int cid = crush.get_or_create_class_id(class_name);
606  	        if (class_id.count(cid) != 0) {
607  	          err << "duplicate device class " << class_name << " for bucket " << name << std::endl;
608  	          return -ERANGE;
609  	        }
610  	        class_id[cid] = maybe_id;
611  	        if (verbose) err << " class" << " '" << class_name << "'" << std::endl;
612  	      } else {
613  	        id = maybe_id;
614  	        if (verbose) err << std::endl;
615  	      }
616  	    } else if (tag == "alg") {
617  	      string a = string_node(sub->children[1]);
618  	      if (a == "uniform")
619  		alg = CRUSH_BUCKET_UNIFORM;
620  	      else if (a == "list")
621  		alg = CRUSH_BUCKET_LIST;
622  	      else if (a == "tree")
623  		alg = CRUSH_BUCKET_TREE;
624  	      else if (a == "straw")
625  		alg = CRUSH_BUCKET_STRAW;
626  	      else if (a == "straw2")
627  		alg = CRUSH_BUCKET_STRAW2;
628  	      else {
629  		err << "unknown bucket alg '" << a << "'" << std::endl << std::endl;
630  		return -EINVAL;
631  	      }
632  	    }
633  	    else if (tag == "hash") {
634  	      string a = string_node(sub->children[1]);
635  	      if (a == "rjenkins1")
636  		hash = CRUSH_HASH_RJENKINS1;
637  	      else
638  		hash = atoi(a.c_str());
639  	    }
640  	    else if (tag == "item") {
641  	      // first, just determine which item pos's are already used
642  	      size++;
643  	      for (unsigned q = 2; q < sub->children.size(); q++) {
644  		string tag = string_node(sub->children[q++]);
645  		if (tag == "pos") {
646  		  int pos = int_node(sub->children[q]);
647  		  if (used_items.count(pos)) {
648  		    err << "item '" << string_node(sub->children[1]) << "' in bucket '" << name << "' has explicit pos " << pos << ", which is occupied" << std::endl;
649  		    return -1;
650  		  }
651  		  used_items.insert(pos);
652  		}
653  	      }
654  	    }
655  	    else ceph_abort();
656  	  }
657  	
658  	  // now do the items.
659  	  if (!used_items.empty())
660  	    size = std::max(size, *used_items.rbegin());
661  	  vector<int> items(size);
662  	  vector<int> weights(size);
663  	
664  	  int curpos = 0;
665  	  unsigned bucketweight = 0;
666  	  bool have_uniform_weight = false;
667  	  unsigned uniform_weight = 0;
668  	  for (unsigned p=3; p<i->children.size()-1; p++) {
669  	    iter_t sub = i->children.begin() + p;
670  	    string tag = string_node(sub->children[0]);
671  	    if (tag == "item") {
672  	
673  	      string iname = string_node(sub->children[1]);
674  	      if (!item_id.count(iname)) {
675  		err << "item '" << iname << "' in bucket '" << name << "' is not defined" << std::endl;
676  		return -1;
677  	      }
678  	      int itemid = item_id[iname];
679  	
680  	      unsigned weight = 0x10000;
681  	      if (item_weight.count(itemid))
682  		weight = item_weight[itemid];
683  	
684  	      int pos = -1;
685  	      for (unsigned q = 2; q < sub->children.size(); q++) {
686  		string tag = string_node(sub->children[q++]);
687  		if (tag == "weight") {
688  		  weight = float_node(sub->children[q]) * (float)0x10000;
689  		  if (weight > CRUSH_MAX_DEVICE_WEIGHT && itemid >= 0) {
690  		    err << "device weight limited to " << CRUSH_MAX_DEVICE_WEIGHT / 0x10000 << std::endl;
691  		    return -ERANGE;
692  		  }
693  		  else if (weight > CRUSH_MAX_BUCKET_WEIGHT && itemid < 0) {
694  		    err << "bucket weight limited to " << CRUSH_MAX_BUCKET_WEIGHT / 0x10000
695  		        << " to prevent overflow" << std::endl;
696  		    return -ERANGE;
697  		  }
698  		}
699  		else if (tag == "pos") 
700  		  pos = int_node(sub->children[q]);
701  		else
702  		  ceph_abort();
703  	
704  	      }
705  	      if (alg == CRUSH_BUCKET_UNIFORM) {
706  		if (!have_uniform_weight) {
707  		  have_uniform_weight = true;
708  		  uniform_weight = weight;
709  		} else {
710  		  if (uniform_weight != weight) {
711  		    err << "item '" << iname << "' in uniform bucket '" << name << "' has weight " << weight
712  			<< " but previous item(s) have weight " << (float)uniform_weight/(float)0x10000
713  			<< "; uniform bucket items must all have identical weights." << std::endl;
714  		    return -1;
715  		  }
716  		}
717  	      }
718  	
719  	      if (pos >= size) {
720  		err << "item '" << iname << "' in bucket '" << name << "' has pos " << pos << " >= size " << size << std::endl;
721  		return -1;
722  	      }
723  	      if (pos < 0) {
724  		while (used_items.count(curpos)) curpos++;
725  		pos = curpos++;
726  	      }
727  	      //err << " item " << iname << " (" << itemid << ") pos " << pos << " weight " << weight << std::endl;
728  	      items[pos] = itemid;
729  	      weights[pos] = weight;
730  	
731  	      if (crush_addition_is_unsafe(bucketweight, weight)) {
732  	        err << "oh no! our bucket weights are overflowing all over the place, better lower the item weights" << std::endl;
733  	        return -ERANGE;
734  	      }
735  	
736  	      bucketweight += weight;
737  	    }
738  	  }
739  	
740  	  if (id == 0) {
741  	    for (id=-1; id_item.count(id); id--) ;
742  	    //err << "assigned id " << id << std::endl;
743  	  }
744  	
745  	  for (auto &i : class_id)
746  	    class_bucket[id][i.first] = i.second;
747  	
748  	  if (verbose) err << "bucket " << name << " (" << id << ") " << size << " items and weight "
749  			   << (float)bucketweight / (float)0x10000 << std::endl;
750  	  id_item[id] = name;
751  	  item_id[name] = id;
752  	  item_weight[id] = bucketweight;
753  	  
754  	  ceph_assert(id != 0);
755  	  int idout;
756  	  int r = crush.add_bucket(id, alg, hash, type, size,
757  	                           items.data(), weights.data(), &idout);
758  	  if (r < 0) {
759  	    if (r == -EEXIST)
760  	      err << "Duplicate bucket id " << id << std::endl;
761  	    else
762  	      err << "add_bucket failed " << cpp_strerror(r) << std::endl;
763  	    return r;
764  	  }
765  	  r = crush.set_item_name(id, name.c_str());
766  	  return r;
767  	}
768  	
769  	int CrushCompiler::parse_rule(iter_t const& i)
770  	{
771  	  int start;  // rule name is optional!
772  	 
773  	  string rname = string_node(i->children[1]);
774  	  if (rname != "{") {
775  	    if (rule_id.count(rname)) {
776  	      err << "rule name '" << rname << "' already defined\n" << std::endl;
777  	      return -1;
778  	    }
779  	    start = 4;
780  	  } else {
781  	    rname = string();
782  	    start = 3;
783  	  }
784  	
785  	  int ruleno = int_node(i->children[start]);
786  	
787  	  string tname = string_node(i->children[start+2]);
788  	  int type;
789  	  if (tname == "replicated")
790  	    type = CEPH_PG_TYPE_REPLICATED;
791  	  else if (tname == "erasure")
792  	    type = CEPH_PG_TYPE_ERASURE;
793  	  else 
794  	    ceph_abort();
795  	
796  	  int minsize = int_node(i->children[start+4]);
797  	  int maxsize = int_node(i->children[start+6]);
798  	  
799  	  int steps = i->children.size() - start - 8;
800  	  //err << "num steps " << steps << std::endl;
801  	
802  	  if (crush.rule_exists(ruleno)) {
803  	    err << "rule " << ruleno << " already exists" << std::endl;
804  	    return -1;
805  	  }
806  	  int r = crush.add_rule(ruleno, steps, type, minsize, maxsize);
807  	  if (r != ruleno) {
808  	    err << "unable to add rule id " << ruleno << " for rule '" << rname
809  		<< "'" << std::endl;
810  	    return -1;
811  	  }
812  	  if (rname.length()) {
813  	    crush.set_rule_name(ruleno, rname.c_str());
814  	    rule_id[rname] = ruleno;
815  	  }
816  	
817  	  int step = 0;
818  	  for (iter_t p = i->children.begin() + start + 7; step < steps; p++) {
819  	    iter_t s = p->children.begin() + 1;
820  	    int stepid = s->value.id().to_long();
821  	    switch (stepid) {
822  	    case crush_grammar::_step_take: 
823  	      {
824  		string item = string_node(s->children[1]);
825  		if (!item_id.count(item)) {
826  		  err << "in rule '" << rname << "' item '" << item << "' not defined" << std::endl;
827  		  return -1;
828  		}
829  	        int id = item_id[item];
830  	        int c = -1;
831  	        string class_name;
832  	        if (s->children.size() > 2) {
833  	          class_name = string_node(s->children[3]);
834  	          c = crush.get_class_id(class_name);
835  	          if (c < 0)
836  	            return c;
837  	          if (crush.class_bucket.count(id) == 0) {
838  	            err << "in rule '" << rname << "' step take " << item
839  	                << " has no class information" << std::endl;
840  	            return -EINVAL;
841  	          }
842  	          if (crush.class_bucket[id].count(c) == 0) {
843  	            err << "in rule '" << rname << "' step take " << item
844  	                << " no matching bucket for class " << class_name << std::endl;
845  	            return -EINVAL;
846  	          }
847  	          id = crush.class_bucket[id][c];
848  	        }
849  	        if (verbose) {
850  	          err << "rule " << rname << " take " << item;
851  	          if (c < 0)
852  	            err << std::endl;
853  	          else
854  	            err << " remapped to " << crush.get_item_name(id) << std::endl;
855  	        }
856  	
857  		crush.set_rule_step_take(ruleno, step++, id);
858  	      }
859  	      break;
860  	
861  	    case crush_grammar::_step_set_choose_tries:
862  	      {
863  		int val = int_node(s->children[1]);
864  		crush.set_rule_step_set_choose_tries(ruleno, step++, val);
865  	      }
866  	      break;
867  	
868  	    case crush_grammar::_step_set_choose_local_tries:
869  	      {
870  		int val = int_node(s->children[1]);
871  		crush.set_rule_step_set_choose_local_tries(ruleno, step++, val);
872  	      }
873  	      break;
874  	
875  	    case crush_grammar::_step_set_choose_local_fallback_tries:
876  	      {
877  		int val = int_node(s->children[1]);
878  		crush.set_rule_step_set_choose_local_fallback_tries(ruleno, step++, val);
879  	      }
880  	      break;
881  	
882  	    case crush_grammar::_step_set_chooseleaf_tries:
883  	      {
884  		int val = int_node(s->children[1]);
885  		crush.set_rule_step_set_chooseleaf_tries(ruleno, step++, val);
886  	      }
887  	      break;
888  	
889  	    case crush_grammar::_step_set_chooseleaf_vary_r:
890  	      {
891  		int val = int_node(s->children[1]);
892  		crush.set_rule_step_set_chooseleaf_vary_r(ruleno, step++, val);
893  	      }
894  	      break;
895  	
896  	    case crush_grammar::_step_set_chooseleaf_stable:
897  	      {
898  		int val = int_node(s->children[1]);
899  		crush.set_rule_step_set_chooseleaf_stable(ruleno, step++, val);
900  	      }
901  	      break;
902  	
903  	    case crush_grammar::_step_choose:
904  	    case crush_grammar::_step_chooseleaf:
905  	      {
906  		string type = string_node(s->children[4]);
907  		if (!type_id.count(type)) {
908  		  err << "in rule '" << rname << "' type '" << type << "' not defined" << std::endl;
909  		  return -1;
910  		}
911  		string choose = string_node(s->children[0]);
912  		string mode = string_node(s->children[1]);
913  		if (choose == "choose") {
914  		  if (mode == "firstn")
915  		    crush.set_rule_step_choose_firstn(ruleno, step++, int_node(s->children[2]), type_id[type]);
916  		  else if (mode == "indep")
917  		    crush.set_rule_step_choose_indep(ruleno, step++, int_node(s->children[2]), type_id[type]);
918  		  else ceph_abort();
919  		} else if (choose == "chooseleaf") {
920  		  if (mode == "firstn") 
921  		    crush.set_rule_step_choose_leaf_firstn(ruleno, step++, int_node(s->children[2]), type_id[type]);
922  		  else if (mode == "indep")
923  		    crush.set_rule_step_choose_leaf_indep(ruleno, step++, int_node(s->children[2]), type_id[type]);
924  		  else ceph_abort();
925  		} else ceph_abort();
926  	      }
927  	      break;
928  	
929  	    case crush_grammar::_step_emit:
930  	      crush.set_rule_step_emit(ruleno, step++);
931  	      break;
932  	
933  	    default:
934  	      err << "bad crush step " << stepid << std::endl;
935  	      return -1;
936  	    }
937  	  }
938  	  ceph_assert(step == steps);
939  	  return 0;
940  	}
941  	
942  	int CrushCompiler::parse_weight_set_weights(iter_t const& i, int bucket_id, crush_weight_set *weight_set)
943  	{
944  	  // -2 for the enclosing [ ]
945  	  __u32 size = i->children.size() - 2;
946  	  __u32 bucket_size = crush.get_bucket_size(bucket_id);
947  	  if (size != bucket_size) {
948  	    err << bucket_id << " needs exactly " << bucket_size
949  	        << " weights but got " << size << std::endl;
950  	    return -1;
951  	  }
952  	  weight_set->size = size;
953  	  weight_set->weights = (__u32 *)calloc(weight_set->size, sizeof(__u32));
954  	  __u32 pos = 0;
955  	  for (iter_t p = i->children.begin() + 1; p != i->children.end(); p++, pos++)
956  	    if (pos < size)
957  	      weight_set->weights[pos] = float_node(*p) * (float)0x10000;
958  	  return 0;
959  	}
960  	
961  	int CrushCompiler::parse_weight_set(iter_t const& i, int bucket_id, crush_choose_arg *arg)
962  	{
963  	  // -3 stands for the leading "weight_set" keyword and the enclosing [ ]
964  	  arg->weight_set_positions = i->children.size() - 3;
965  	  arg->weight_set = (crush_weight_set *)calloc(arg->weight_set_positions, sizeof(crush_weight_set));
966  	  __u32 pos = 0;
967  	  for (iter_t p = i->children.begin(); p != i->children.end(); p++) {
968  	    int r = 0;
969  	    switch((int)p->value.id().to_long()) {
970  	    case crush_grammar::_weight_set_weights:
971  	      if (pos < arg->weight_set_positions) {
972  	        r = parse_weight_set_weights(p, bucket_id, &arg->weight_set[pos]);
973  	        pos++;
974  	      } else {
975  	        err << "invalid weight_set syntax" << std::endl;
976  	        r = -1;
977  	      }
978  	    }
979  	    if (r < 0)
980  	      return r;
981  	  }
982  	  return 0;
983  	}
984  	
985  	int CrushCompiler::parse_choose_arg_ids(iter_t const& i, int bucket_id, crush_choose_arg *arg)
986  	{
987  	  // -3 for the leading "ids" keyword and the enclosing [ ]
988  	  __u32 size = i->children.size() - 3;
989  	  __u32 bucket_size = crush.get_bucket_size(bucket_id);
990  	  if (size != bucket_size) {
991  	    err << bucket_id << " needs exactly " << bucket_size
992  	        << " ids but got " << size << std::endl;
993  	    return -1;
994  	  }
995  	  arg->ids_size = size;
996  	  arg->ids = (__s32 *)calloc(arg->ids_size, sizeof(__s32));
997  	  __u32 pos = 0;
998  	  for (iter_t p = i->children.begin() + 2; pos < size; p++, pos++)
999  	    arg->ids[pos] = int_node(*p);
1000 	  return 0;
1001 	}
1002 	
1003 	int CrushCompiler::parse_choose_arg(iter_t const& i, crush_choose_arg *args)
1004 	{
1005 	  int bucket_id = int_node(i->children[2]);
1006 	  if (-1-bucket_id < 0 || -1-bucket_id >= crush.get_max_buckets()) {
1007 	    err << bucket_id << " is out of range" << std::endl;
1008 	    return -1;
1009 	  }
1010 	  if (!crush.bucket_exists(bucket_id)) {
1011 	    err << bucket_id << " does not exist" << std::endl;
1012 	    return -1;
1013 	  }
1014 	  crush_choose_arg *arg = &args[-1-bucket_id];
1015 	  for (iter_t p = i->children.begin(); p != i->children.end(); p++) {
1016 	    int r = 0;
1017 	    switch((int)p->value.id().to_long()) {
1018 	    case crush_grammar::_weight_set:
1019 	      r = parse_weight_set(p, bucket_id, arg);
1020 	      break;
1021 	    case crush_grammar::_choose_arg_ids:
1022 	      r = parse_choose_arg_ids(p, bucket_id, arg);
1023 	      break;
1024 	    }
1025 	    if (r < 0)
1026 	      return r;
1027 	  }
1028 	  return 0;
1029 	}
1030 	
1031 	int CrushCompiler::parse_choose_args(iter_t const& i)
1032 	{
1033 	  int choose_arg_index = int_node(i->children[1]);
1034 	  if (crush.choose_args.find(choose_arg_index) != crush.choose_args.end()) {
1035 	    err << choose_arg_index << " duplicated" << std::endl;
1036 	    return -1;
1037 	  }
1038 	  const auto max_buckets = crush.get_max_buckets();
1039 	  if (max_buckets < 0) {
1040 	    err << "get_max_buckets() returned error" << std::endl;
1041 	    return -1;
1042 	  }
1043 	  crush_choose_arg_map arg_map;
1044 	  arg_map.size = max_buckets;
1045 	  arg_map.args = (crush_choose_arg *)calloc(arg_map.size, sizeof(crush_choose_arg));
1046 	  for (iter_t p = i->children.begin() + 2; p != i->children.end(); p++) {
1047 	    int r = 0;
1048 	    switch((int)p->value.id().to_long()) {
1049 	    case crush_grammar::_choose_arg:
1050 	      r = parse_choose_arg(p, arg_map.args);
1051 	      break;
1052 	    }
1053 	    if (r < 0) {
1054 	      crush.destroy_choose_args(arg_map);
1055 	      return r;
1056 	    }
1057 	  }
1058 	  crush.choose_args[choose_arg_index] = arg_map;
1059 	  return 0;
1060 	}
1061 	
1062 	void CrushCompiler::find_used_bucket_ids(iter_t const& i)
1063 	{
1064 	  for (iter_t p = i->children.begin(); p != i->children.end(); p++) {
1065 	    if ((int)p->value.id().to_long() == crush_grammar::_bucket) {
1066 	      for (iter_t firstline = p->children.begin() + 3;
1067 		   firstline != p->children.end();
1068 		   ++firstline) {
1069 		string tag = string_node(firstline->children[0]);
1070 		if (tag != "id") {
1071 		  break;
1072 		}
1073 		int id = int_node(firstline->children[1]);
1074 		//err << "saw bucket id " << id << std::endl;
1075 		id_item[id] = string();
1076 	      }
1077 	    }
1078 	  }
1079 	}
1080 	
1081 	int CrushCompiler::parse_crush(iter_t const& i) 
1082 	{ 
1083 	  find_used_bucket_ids(i);
1084 	  bool saw_rule = false;
1085 	  for (iter_t p = i->children.begin(); p != i->children.end(); p++) {
1086 	    int r = 0;
1087 	    switch (p->value.id().to_long()) {
1088 	    case crush_grammar::_tunable:
1089 	      r = parse_tunable(p);
1090 	      break;
1091 	    case crush_grammar::_device: 
1092 	      r = parse_device(p);
1093 	      break;
1094 	    case crush_grammar::_bucket_type: 
1095 	      r = parse_bucket_type(p);
1096 	      break;
1097 	    case crush_grammar::_bucket:
1098 	      if (saw_rule) {
1099 		err << "buckets must be defined before rules" << std::endl;
1100 		return -1;
1101 	      }
1102 	      r = parse_bucket(p);
1103 	      break;
1104 	    case crush_grammar::_crushrule:
1105 	      if (!saw_rule) {
1106 		saw_rule = true;
1107 		crush.populate_classes(class_bucket);
1108 	      }
1109 	      r = parse_rule(p);
1110 	      break;
1111 	    case crush_grammar::_choose_args:
1112 	      r = parse_choose_args(p);
1113 	      break;
1114 	    default:
1115 	      ceph_abort();
1116 	    }
1117 	    if (r < 0) {
1118 	      return r;
1119 	    }
1120 	  }
1121 	
1122 	  //err << "max_devices " << crush.get_max_devices() << std::endl;
1123 	  crush.finalize();
1124 	
1125 	  return 0;
1126 	} 
1127 	
1128 	// squash runs of whitespace to one space, excepting newlines
1129 	string CrushCompiler::consolidate_whitespace(string in)
1130 	{
1131 	  string out;
1132 	
1133 	  bool white = false;
1134 	  for (unsigned p=0; p<in.length(); p++) {
1135 	    if (isspace(in[p]) && in[p] != '\n') {
1136 	      if (white)
1137 		continue;
1138 	      white = true;
1139 	    } else {
1140 	      if (white) {
1141 		if (out.length()) out += " ";
1142 		white = false;
1143 	      }
1144 	      out += in[p];
1145 	    }
1146 	  }
1147 	  if (verbose > 3)
1148 	    err << " \"" << in << "\" -> \"" << out << "\"" << std::endl;
1149 	  return out;
1150 	}
1151 	
1152 	void CrushCompiler::dump(iter_t const& i, int ind) 
1153 	{
1154 	  err << "dump"; 
1155 	  for (int j=0; j<ind; j++)
1156 	    cout << "\t"; 
1157 	  long id = i->value.id().to_long();
1158 	  err << id << "\t"; 
1159 	  err << "'" << string(i->value.begin(), i->value.end())  
1160 	      << "' " << i->children.size() << " children" << std::endl; 
1161 	  for (unsigned int j = 0; j < i->children.size(); j++)  
1162 	    dump(i->children.begin() + j, ind+1); 
1163 	}
1164 	
1165 	/**
1166 	*  This function fix the problem like below
1167 	*   rack using_foo { item foo }  
1168 	*   host foo { ... }
1169 	*
1170 	*  if an item being used by a bucket is defined after that bucket. 
1171 	*  CRUSH compiler will create a map by which we can 
1172 	*  not identify that item when selecting in that bucket.
1173 	**/
1174 	int CrushCompiler::adjust_bucket_item_place(iter_t const &i)
1175 	{
1176 	  map<string,set<string> > bucket_items;
1177 	  map<string,iter_t> bucket_itrer;
1178 	  vector<string> buckets;
1179 	  for (iter_t p = i->children.begin(); p != i->children.end(); ++p) {
1180 	    if ((int)p->value.id().to_long() == crush_grammar::_bucket) {
1181 	      string name = string_node(p->children[1]);
1182 	      buckets.push_back(name);
1183 	      bucket_itrer[name] = p;
1184 	      //skip non-bucket-item children in the bucket's parse tree
1185 	      for (unsigned q=3; q < p->children.size()-1; ++q) {
1186 	        iter_t sub = p->children.begin() + q;
1187 	        if ((int)sub->value.id().to_long() 
1188 	          == crush_grammar::_bucket_item) {
1189 	          string iname = string_node(sub->children[1]);
1190 	          bucket_items[name].insert(iname);
1191 	        }         
1192 	      }       
1193 	    }     
1194 	  }
1195 	  
1196 	  //adjust the bucket
(1) Event parameter_hidden: declaration hides parameter "i" (declared at line 1174)
(2) Event caretline: ^
1197 	  for (unsigned i=0; i < buckets.size(); ++i) { 
1198 	    for (unsigned j=i+1; j < buckets.size(); ++j) {
1199 	      if (bucket_items[buckets[i]].count(buckets[j])) {
1200 	        if (bucket_items[buckets[j]].count(buckets[i])) {
1201 	          err << "bucket  '" <<  buckets[i] << "' and bucket '"
1202 	          << buckets[j] << "' are included each other" << std::endl;
1203 	          return -1; 
1204 	        } else {  
1205 		   std::iter_swap(bucket_itrer[buckets[i]], bucket_itrer[buckets[j]]);
1206 	        } 
1207 	      } 
1208 	    }
1209 	  }
1210 		
1211 	  return 0;
1212 	}
1213 	
1214 	int CrushCompiler::compile(istream& in, const char *infn)
1215 	{
1216 	  if (!infn)
1217 	    infn = "<input>";
1218 	
1219 	  // always start with legacy tunables, so that the compiled result of
1220 	  // a given crush file is fixed for all time.
1221 	  crush.set_tunables_legacy();
1222 	
1223 	  string big;
1224 	  string str;
1225 	  int line = 1;
1226 	  map<int,int> line_pos;  // pos -> line
1227 	  map<int,string> line_val;
1228 	  while (getline(in, str)) {
1229 	    // remove newline
1230 	    int l = str.length();
1231 	    if (l && str[l - 1] == '\n')
1232 	      str.erase(l-1, 1);
1233 	
1234 	    line_val[line] = str;
1235 	
1236 	    // strip comment
1237 	    int n = str.find("#");
1238 	    if (n >= 0)
1239 	      str.erase(n, str.length()-n);
1240 	    
1241 	    if (verbose>1) err << line << ": " << str << std::endl;
1242 	
1243 	    // work around spirit crankiness by removing extraneous
1244 	    // whitespace.  there is probably a more elegant solution, but
1245 	    // this only broke with the latest spirit (with the switchover to
1246 	    // "classic"), i don't want to spend too much time figuring it
1247 	    // out.
1248 	    string stripped = consolidate_whitespace(str);
1249 	    if (stripped.length() && big.length() && big[big.length()-1] != ' ') big += " ";
1250 	
1251 	    line_pos[big.length()] = line;
1252 	    line++;
1253 	    big += stripped;
1254 	  }
1255 	  
1256 	  if (verbose > 2) err << "whole file is: \"" << big << "\"" << std::endl;
1257 	  
1258 	  crush_grammar crushg;
1259 	  const char *start = big.c_str();
1260 	  //tree_parse_info<const char *> info = ast_parse(start, crushg, space_p);
1261 	  auto info = ast_parse(start, crushg, boost::spirit::space_p);
1262 	
1263 	  // parse error?
1264 	  if (!info.full) {
1265 	    int cpos = info.stop - start;
1266 	    //out << "cpos " << cpos << std::endl;
1267 	    //out << " linemap " << line_pos << std::endl;
1268 	    ceph_assert(!line_pos.empty());
1269 	    map<int,int>::iterator p = line_pos.upper_bound(cpos);
1270 	    if (p != line_pos.begin())
1271 	      --p;
1272 	    int line = p->second;
1273 	    int pos = cpos - p->first;
1274 	    err << infn << ":" << line //<< ":" << (pos+1)
1275 		<< " error: parse error at '" << line_val[line].substr(pos) << "'" << std::endl;
1276 	    return -1;
1277 	  }
1278 	  
1279 	  int r = adjust_bucket_item_place(info.trees.begin());
1280 	  if (r < 0) {
1281 	    return r;
1282 	  }
1283 	  //out << "parsing succeeded\n";
1284 	  //dump(info.trees.begin());
1285 	  return parse_crush(info.trees.begin());
1286 	}
1287