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) 2013 Inktank <info@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 "HitSet.h"
16   	#include "common/Formatter.h"
17   	
18   	using std::ostream;
19   	using std::list;
20   	using ceph::Formatter;
21   	
22   	// -- HitSet --
23   	
24   	HitSet::HitSet(const HitSet::Params& params)
25   	  : sealed(false)
26   	{
27   	  switch (params.get_type()) {
28   	  case TYPE_BLOOM:
29   	    {
30   	      BloomHitSet::Params *p =
31   		static_cast<BloomHitSet::Params*>(params.impl.get());
32   	      impl.reset(new BloomHitSet(p));
33   	    }
34   	    break;
35   	
36   	  case TYPE_EXPLICIT_HASH:
37   	    impl.reset(new ExplicitHashHitSet(static_cast<ExplicitHashHitSet::Params*>(params.impl.get())));
38   	    break;
39   	
40   	  case TYPE_EXPLICIT_OBJECT:
41   	    impl.reset(new ExplicitObjectHitSet(static_cast<ExplicitObjectHitSet::Params*>(params.impl.get())));
42   	    break;
43   	
44   	  default:
45   	    assert (0 == "unknown HitSet type");
46   	  }
47   	}
48   	
49   	void HitSet::encode(ceph::buffer::list &bl) const
50   	{
51   	  ENCODE_START(1, 1, bl);
52   	  encode(sealed, bl);
(1) Event cond_false: Condition "this->impl.operator bool()", taking false branch.
53   	  if (impl) {
54   	    encode((__u8)impl->get_type(), bl);
55   	    impl->encode(bl);
(2) Event else_branch: Reached else branch.
56   	  } else {
(3) Event overrun-buffer-val: Overrunning buffer pointed to by "__u8 const(0)" of 1 bytes by passing it to a function which accesses it at byte offset 7. [details]
57   	    encode((__u8)TYPE_NONE, bl);
58   	  }
59   	  ENCODE_FINISH(bl);
60   	}
61   	
62   	void HitSet::decode(ceph::buffer::list::const_iterator& bl)
63   	{
64   	  DECODE_START(1, bl);
65   	  decode(sealed, bl);
66   	  __u8 type;
67   	  decode(type, bl);
68   	  switch ((impl_type_t)type) {
69   	  case TYPE_EXPLICIT_HASH:
70   	    impl.reset(new ExplicitHashHitSet);
71   	    break;
72   	  case TYPE_EXPLICIT_OBJECT:
73   	    impl.reset(new ExplicitObjectHitSet);
74   	    break;
75   	  case TYPE_BLOOM:
76   	    impl.reset(new BloomHitSet);
77   	    break;
78   	  case TYPE_NONE:
79   	    impl.reset(NULL);
80   	    break;
81   	  default:
82   	    throw ceph::buffer::malformed_input("unrecognized HitMap type");
83   	  }
84   	  if (impl)
85   	    impl->decode(bl);
86   	  DECODE_FINISH(bl);
87   	}
88   	
89   	void HitSet::dump(Formatter *f) const
90   	{
91   	  f->dump_string("type", get_type_name());
92   	  f->dump_string("sealed", sealed ? "yes" : "no");
93   	  if (impl)
94   	    impl->dump(f);
95   	}
96   	
97   	void HitSet::generate_test_instances(list<HitSet*>& o)
98   	{
99   	  o.push_back(new HitSet);
100  	  o.push_back(new HitSet(new BloomHitSet(10, .1, 1)));
101  	  o.back()->insert(hobject_t());
102  	  o.back()->insert(hobject_t("asdf", "", CEPH_NOSNAP, 123, 1, ""));
103  	  o.back()->insert(hobject_t("qwer", "", CEPH_NOSNAP, 456, 1, ""));
104  	  o.push_back(new HitSet(new ExplicitHashHitSet));
105  	  o.back()->insert(hobject_t());
106  	  o.back()->insert(hobject_t("asdf", "", CEPH_NOSNAP, 123, 1, ""));
107  	  o.back()->insert(hobject_t("qwer", "", CEPH_NOSNAP, 456, 1, ""));
108  	  o.push_back(new HitSet(new ExplicitObjectHitSet));
109  	  o.back()->insert(hobject_t());
110  	  o.back()->insert(hobject_t("asdf", "", CEPH_NOSNAP, 123, 1, ""));
111  	  o.back()->insert(hobject_t("qwer", "", CEPH_NOSNAP, 456, 1, ""));
112  	}
113  	
114  	HitSet::Params::Params(const Params& o) noexcept
115  	{
116  	  if (o.get_type() != TYPE_NONE) {
117  	    create_impl(o.get_type());
118  	    // it's annoying to write virtual operator= methods; use encode/decode
119  	    // instead.
120  	    ceph::buffer::list bl;
121  	    o.impl->encode(bl);
122  	    auto p = bl.cbegin();
123  	    impl->decode(p);
124  	  } // else we don't need to do anything
125  	}
126  	
127  	const HitSet::Params& HitSet::Params::operator=(const Params& o)
128  	{
129  	  create_impl(o.get_type());
130  	  if (o.impl) {
131  	    // it's annoying to write virtual operator= methods; use encode/decode
132  	    // instead.
133  	    ceph::buffer::list bl;
134  	    o.impl->encode(bl);
135  	    auto p = bl.cbegin();
136  	    impl->decode(p);
137  	  }
138  	  return *this;
139  	}
140  	
141  	void HitSet::Params::encode(ceph::buffer::list &bl) const
142  	{
143  	  ENCODE_START(1, 1, bl);
144  	  if (impl) {
145  	    encode((__u8)impl->get_type(), bl);
146  	    impl->encode(bl);
147  	  } else {
148  	    encode((__u8)TYPE_NONE, bl);
149  	  }
150  	  ENCODE_FINISH(bl);
151  	}
152  	
153  	bool HitSet::Params::create_impl(impl_type_t type)
154  	{
155  	  switch ((impl_type_t)type) {
156  	  case TYPE_EXPLICIT_HASH:
157  	    impl.reset(new ExplicitHashHitSet::Params);
158  	    break;
159  	  case TYPE_EXPLICIT_OBJECT:
160  	    impl.reset(new ExplicitObjectHitSet::Params);
161  	    break;
162  	  case TYPE_BLOOM:
163  	    impl.reset(new BloomHitSet::Params);
164  	    break;
165  	  case TYPE_NONE:
166  	    impl.reset(NULL);
167  	    break;
168  	  default:
169  	    return false;
170  	  }
171  	  return true;
172  	}
173  	
174  	void HitSet::Params::decode(ceph::buffer::list::const_iterator& bl)
175  	{
176  	  DECODE_START(1, bl);
177  	  __u8 type;
178  	  decode(type, bl);
179  	  if (!create_impl((impl_type_t)type))
180  	    throw ceph::buffer::malformed_input("unrecognized HitMap type");
181  	  if (impl)
182  	    impl->decode(bl);
183  	  DECODE_FINISH(bl);
184  	}
185  	
186  	void HitSet::Params::dump(Formatter *f) const
187  	{
188  	  f->dump_string("type", HitSet::get_type_name(get_type()));
189  	  if (impl)
190  	    impl->dump(f);
191  	}
192  	
193  	void HitSet::Params::generate_test_instances(list<HitSet::Params*>& o)
194  	{
195  	#define loop_hitset_params(kind) \
196  	{ \
197  	  list<kind::Params*> params; \
198  	  kind::Params::generate_test_instances(params); \
199  	  for (list<kind::Params*>::iterator i = params.begin(); \
200  	  i != params.end(); ++i) \
201  	    o.push_back(new Params(*i)); \
202  	}
203  	  o.push_back(new Params);
204  	  o.push_back(new Params(new BloomHitSet::Params));
205  	  loop_hitset_params(BloomHitSet);
206  	  o.push_back(new Params(new ExplicitHashHitSet::Params));
207  	  loop_hitset_params(ExplicitHashHitSet);
208  	  o.push_back(new Params(new ExplicitObjectHitSet::Params));
209  	  loop_hitset_params(ExplicitObjectHitSet);
210  	}
211  	
212  	ostream& operator<<(ostream& out, const HitSet::Params& p) {
213  	  out << HitSet::get_type_name(p.get_type());
214  	  if (p.impl) {
215  	    out << "{";
216  	    p.impl->dump_stream(out);
217  	  }
218  	  out << "}";
219  	  return out;
220  	}
221  	
222  	
223  	void ExplicitHashHitSet::dump(Formatter *f) const {
224  	  f->dump_unsigned("insert_count", count);
225  	  f->open_array_section("hash_set");
226  	  for (ceph::unordered_set<uint32_t>::const_iterator p = hits.begin();
227  	       p != hits.end();
228  	       ++p)
229  	    f->dump_unsigned("hash", *p);
230  	  f->close_section();
231  	}
232  	
233  	void ExplicitObjectHitSet::dump(Formatter *f) const {
234  	  f->dump_unsigned("insert_count", count);
235  	  f->open_array_section("set");
236  	  for (ceph::unordered_set<hobject_t>::const_iterator p = hits.begin();
237  	       p != hits.end();
238  	       ++p) {
239  	    f->open_object_section("object");
240  	    p->dump(f);
241  	    f->close_section();
242  	  }
243  	  f->close_section();
244  	}
245  	
246  	void BloomHitSet::Params::dump(Formatter *f) const {
247  	  f->dump_float("false_positive_probability", get_fpp());
248  	  f->dump_int("target_size", target_size);
249  	  f->dump_int("seed", seed);
250  	}
251  	
252  	void BloomHitSet::dump(Formatter *f) const {
253  	  f->open_object_section("bloom_filter");
254  	  bloom.dump(f);
255  	  f->close_section();
256  	}
257