]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/erasure-code/ErasureCodeExample.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph distributed storage system
6 * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
8 * Author: Loic Dachary <loic@dachary.org>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
17 #ifndef CEPH_ERASURE_CODE_EXAMPLE_H
18 #define CEPH_ERASURE_CODE_EXAMPLE_H
25 #include "crush/CrushWrapper.h"
26 #include "osd/osd_types.h"
27 #include "erasure-code/ErasureCode.h"
29 #define FIRST_DATA_CHUNK 0
30 #define SECOND_DATA_CHUNK 1
31 #define DATA_CHUNKS 2u
33 #define CODING_CHUNK 2
34 #define CODING_CHUNKS 1u
36 #define MINIMUM_TO_RECOVER 2u
38 class ErasureCodeExample final
: public ErasureCode
{
40 ~ErasureCodeExample() override
{}
42 int create_rule(const string
&name
,
44 ostream
*ss
) const override
{
45 return crush
.add_simple_rule(name
, "default", "host", "",
46 "indep", pg_pool_t::TYPE_ERASURE
, ss
);
49 int minimum_to_decode_with_cost(const set
<int> &want_to_read
,
50 const map
<int, int> &available
,
51 set
<int> *minimum
) override
{
53 // If one chunk is more expensive to fetch than the others,
54 // recover it instead. For instance, if the cost reflects the
55 // time it takes for a chunk to be retrieved from a remote
56 // OSD and if CPU is cheap, it could make sense to recover
57 // instead of fetching the chunk.
59 map
<int, int> c2c(available
);
60 if (c2c
.size() > DATA_CHUNKS
) {
61 if (c2c
[FIRST_DATA_CHUNK
] > c2c
[SECOND_DATA_CHUNK
] &&
62 c2c
[FIRST_DATA_CHUNK
] > c2c
[CODING_CHUNK
])
63 c2c
.erase(FIRST_DATA_CHUNK
);
64 else if(c2c
[SECOND_DATA_CHUNK
] > c2c
[FIRST_DATA_CHUNK
] &&
65 c2c
[SECOND_DATA_CHUNK
] > c2c
[CODING_CHUNK
])
66 c2c
.erase(SECOND_DATA_CHUNK
);
67 else if(c2c
[CODING_CHUNK
] > c2c
[FIRST_DATA_CHUNK
] &&
68 c2c
[CODING_CHUNK
] > c2c
[SECOND_DATA_CHUNK
])
69 c2c
.erase(CODING_CHUNK
);
71 set
<int> available_chunks
;
72 for (map
<int, int>::const_iterator i
= c2c
.begin();
75 available_chunks
.insert(i
->first
);
76 return _minimum_to_decode(want_to_read
, available_chunks
, minimum
);
79 unsigned int get_chunk_count() const override
{
80 return DATA_CHUNKS
+ CODING_CHUNKS
;
83 unsigned int get_data_chunk_count() const override
{
87 unsigned int get_chunk_size(unsigned int object_size
) const override
{
88 return ( object_size
/ DATA_CHUNKS
) + 1;
91 int encode(const set
<int> &want_to_encode
,
93 map
<int, bufferlist
> *encoded
) override
{
95 // make sure all data chunks have the same length, allocating
96 // padding if necessary.
98 unsigned int chunk_length
= get_chunk_size(in
.length());
100 unsigned int width
= get_chunk_count() * get_chunk_size(in
.length());
101 bufferptr
pad(width
- in
.length());
102 pad
.zero(0, get_data_chunk_count());
105 // compute the coding chunk with first chunk ^ second chunk
107 char *p
= out
.c_str();
108 for (unsigned i
= 0; i
< chunk_length
; i
++)
109 p
[i
+ CODING_CHUNK
* chunk_length
] =
110 p
[i
+ FIRST_DATA_CHUNK
* chunk_length
] ^
111 p
[i
+ SECOND_DATA_CHUNK
* chunk_length
];
113 // populate the bufferlist with bufferptr pointing
114 // to chunk boundaries
116 const bufferptr
&ptr
= out
.front();
117 for (set
<int>::iterator j
= want_to_encode
.begin();
118 j
!= want_to_encode
.end();
121 bufferptr
chunk(ptr
, (*j
) * chunk_length
, chunk_length
);
122 tmp
.push_back(chunk
);
123 tmp
.claim_append((*encoded
)[*j
]);
124 (*encoded
)[*j
].swap(tmp
);
129 int encode_chunks(const set
<int> &want_to_encode
,
130 map
<int, bufferlist
> *encoded
) override
{
135 int _decode(const set
<int> &want_to_read
,
136 const map
<int, bufferlist
> &chunks
,
137 map
<int, bufferlist
> *decoded
) {
139 // All chunks have the same size
141 unsigned chunk_length
= (*chunks
.begin()).second
.length();
142 for (set
<int>::iterator i
= want_to_read
.begin();
143 i
!= want_to_read
.end();
145 if (chunks
.find(*i
) != chunks
.end()) {
147 // If the chunk is available, just copy the bufferptr pointer
148 // to the decoded argument.
150 (*decoded
)[*i
] = chunks
.find(*i
)->second
;
151 } else if(chunks
.size() != 2) {
153 // If a chunk is missing and there are not enough chunks
154 // to recover, abort.
159 // No matter what the missing chunk is, XOR of the other
162 map
<int, bufferlist
>::const_iterator k
= chunks
.begin();
163 const char *a
= k
->second
.front().c_str();
165 const char *b
= k
->second
.front().c_str();
166 bufferptr
chunk(chunk_length
);
167 char *c
= chunk
.c_str();
168 for (unsigned j
= 0; j
< chunk_length
; j
++) {
174 tmp
.claim_append((*decoded
)[*i
]);
175 (*decoded
)[*i
].swap(tmp
);
181 int decode_chunks(const set
<int> &want_to_read
,
182 const map
<int, bufferlist
> &chunks
,
183 map
<int, bufferlist
> *decoded
) override
{
188 const vector
<int> &get_chunk_mapping() const override
{
189 static vector
<int> mapping
;