summaryrefslogtreecommitdiffstats
path: root/src/cls/cas/cls_cas_internal.cc
blob: edaa96d2737053bcea3c58ddf0e0b43bb4d2d06b (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
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab

#include "cls_cas_internal.h"


chunk_refs_t::chunk_refs_t(const chunk_refs_t& other)
{
  *this = other;
}

chunk_refs_t& chunk_refs_t::operator=(const chunk_refs_t& other)
{
  // this is inefficient, but easy.
  bufferlist bl;
  other.encode(bl);
  auto p = bl.cbegin();
  decode(p);
  return *this;
}

void chunk_refs_t::clear()
{
  // default to most precise impl
  r.reset(new chunk_refs_by_object_t);
}


void chunk_refs_t::encode(ceph::buffer::list& bl) const
{
  bufferlist t;
  _encode_r(t);
  _encode_final(bl, t);
}

void chunk_refs_t::_encode_r(ceph::bufferlist& bl) const
{
  using ceph::encode;
  switch (r->get_type()) {
  case TYPE_BY_OBJECT:
    encode(*(chunk_refs_by_object_t*)r.get(), bl);
    break;
  case TYPE_BY_HASH:
    encode(*(chunk_refs_by_hash_t*)r.get(), bl);
    break;
  case TYPE_BY_POOL:
    encode(*(chunk_refs_by_pool_t*)r.get(), bl);
    break;
  case TYPE_COUNT:
    encode(*(chunk_refs_count_t*)r.get(), bl);
    break;
  default:
    ceph_abort("unrecognized ref type");
  }
}

void chunk_refs_t::dynamic_encode(ceph::buffer::list& bl, size_t max)
{
  bufferlist t;
  while (true) {
    _encode_r(t);
    // account for the additional overhead in _encode_final
    if (t.length() + 8 <= max) {
      break;
    }
    // downgrade resolution
    std::unique_ptr<refs_t> n;
    switch (r->get_type()) {
    case TYPE_BY_OBJECT:
      r.reset(new chunk_refs_by_hash_t(
		static_cast<chunk_refs_by_object_t*>(r.get())));
      break;
    case TYPE_BY_HASH:
      if (!static_cast<chunk_refs_by_hash_t*>(r.get())->shrink()) {
	r.reset(new chunk_refs_by_pool_t(
		  static_cast<chunk_refs_by_hash_t*>(r.get())));
      }
      break;
    case TYPE_BY_POOL:
      r.reset(new chunk_refs_count_t(r.get()));
      break;
    }
    t.clear();
  }
  _encode_final(bl, t);
}

void chunk_refs_t::_encode_final(bufferlist& bl, bufferlist& t) const
{
  ENCODE_START(1, 1, bl);
  encode(r->get_type(), bl);
  bl.claim_append(t);
  ENCODE_FINISH(bl);
}

void chunk_refs_t::decode(ceph::buffer::list::const_iterator& p)
{
  DECODE_START(1, p);
  uint8_t t;
  decode(t, p);
  switch (t) {
  case TYPE_BY_OBJECT:
    {
      auto n = new chunk_refs_by_object_t();
      decode(*n, p);
      r.reset(n);
    }
    break;
  case TYPE_BY_HASH:
    {
      auto n = new chunk_refs_by_hash_t();
      decode(*n, p);
      r.reset(n);
    }
    break;
  case TYPE_BY_POOL:
    {
      auto n = new chunk_refs_by_pool_t();
      decode(*n, p);
      r.reset(n);
    }
    break;
  case TYPE_COUNT:
    {
      auto n = new chunk_refs_count_t();
      decode(*n, p);
      r.reset(n);
    }
    break;
  default:
    throw ceph::buffer::malformed_input(
      "unrecognized chunk ref encoding type "s + stringify((int)t));
  }
  DECODE_FINISH(p);
}