summaryrefslogtreecommitdiff
path: root/src/test/osd/ErasureCodeExample.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/osd/ErasureCodeExample.h')
-rw-r--r--src/test/osd/ErasureCodeExample.h96
1 files changed, 71 insertions, 25 deletions
diff --git a/src/test/osd/ErasureCodeExample.h b/src/test/osd/ErasureCodeExample.h
index 896e614c6b5..0fd55187559 100644
--- a/src/test/osd/ErasureCodeExample.h
+++ b/src/test/osd/ErasureCodeExample.h
@@ -19,45 +19,63 @@
#include <unistd.h>
#include <errno.h>
+#include <algorithm>
#include <sstream>
#include "osd/ErasureCodeInterface.h"
+#define FIRST_DATA_CHUNK 0
+#define SECOND_DATA_CHUNK 1
#define DATA_CHUNKS 2u
+
+#define CODING_CHUNK 2
#define CODING_CHUNKS 1u
+#define MINIMUM_TO_RECOVER 2u
+
class ErasureCodeExample : public ErasureCodeInterface {
public:
- useconds_t delay;
- ErasureCodeExample(const map<std::string,std::string> &parameters) :
- delay(0)
- {
- if (parameters.find("usleep") != parameters.end()) {
- std::istringstream ss(parameters.find("usleep")->second);
- ss >> delay;
- usleep(delay);
- }
- }
-
virtual ~ErasureCodeExample() {}
virtual int minimum_to_decode(const set<int> &want_to_read,
const set<int> &available_chunks,
set<int> *minimum) {
- if (available_chunks.size() < DATA_CHUNKS)
+ if (includes(available_chunks.begin(), available_chunks.end(),
+ want_to_read.begin(), want_to_read.end())) {
+ *minimum = want_to_read;
+ return 0;
+ } else if (available_chunks.size() >= MINIMUM_TO_RECOVER) {
+ *minimum = available_chunks;
+ return 0;
+ } else {
return -EIO;
- set<int>::iterator i;
- unsigned j;
- for (i = available_chunks.begin(), j = 0; j < DATA_CHUNKS; i++, j++)
- minimum->insert(*i);
- return 0;
+ }
}
virtual int minimum_to_decode_with_cost(const set<int> &want_to_read,
const map<int, int> &available,
set<int> *minimum) {
+ //
+ // If one chunk is more expensive to fetch than the others,
+ // recover it instead. For instance, if the cost reflects the
+ // time it takes for a chunk to be retrieved from a remote
+ // OSD and if CPU is cheap, it could make sense to recover
+ // instead of fetching the chunk.
+ //
+ map<int, int> c2c(available);
+ if (c2c.size() > DATA_CHUNKS) {
+ if (c2c[FIRST_DATA_CHUNK] > c2c[SECOND_DATA_CHUNK] &&
+ c2c[FIRST_DATA_CHUNK] > c2c[CODING_CHUNK])
+ c2c.erase(FIRST_DATA_CHUNK);
+ else if(c2c[SECOND_DATA_CHUNK] > c2c[FIRST_DATA_CHUNK] &&
+ c2c[SECOND_DATA_CHUNK] > c2c[CODING_CHUNK])
+ c2c.erase(SECOND_DATA_CHUNK);
+ else if(c2c[CODING_CHUNK] > c2c[FIRST_DATA_CHUNK] &&
+ c2c[CODING_CHUNK] > c2c[SECOND_DATA_CHUNK])
+ c2c.erase(CODING_CHUNK);
+ }
set <int> available_chunks;
- for (map<int, int>::const_iterator i = available.begin();
- i != available.end();
+ for (map<int, int>::const_iterator i = c2c.begin();
+ i != c2c.end();
i++)
available_chunks.insert(i->first);
return minimum_to_decode(want_to_read, available_chunks, minimum);
@@ -66,16 +84,28 @@ public:
virtual int encode(const set<int> &want_to_encode,
const bufferlist &in,
map<int, bufferlist> *encoded) {
+ //
+ // make sure all data chunks have the same length, allocating
+ // padding if necessary.
+ //
unsigned chunk_length = ( in.length() / DATA_CHUNKS ) + 1;
unsigned length = chunk_length * ( DATA_CHUNKS + CODING_CHUNKS );
bufferlist out(in);
bufferptr pad(length - in.length());
pad.zero(0, DATA_CHUNKS);
out.push_back(pad);
+ //
+ // compute the coding chunk with first chunk ^ second chunk
+ //
char *p = out.c_str();
- for (unsigned i = 0; i < chunk_length * DATA_CHUNKS; i++)
- p[i + 2 * chunk_length] =
- p[i + 0 * chunk_length] ^ p[i + 1 * chunk_length];
+ for (unsigned i = 0; i < chunk_length; i++)
+ p[i + CODING_CHUNK * chunk_length] =
+ p[i + FIRST_DATA_CHUNK * chunk_length] ^
+ p[i + SECOND_DATA_CHUNK * chunk_length];
+ //
+ // populate the bufferlist with bufferptr pointing
+ // to chunk boundaries
+ //
const bufferptr ptr = out.buffers().front();
for (set<int>::iterator j = want_to_encode.begin();
j != want_to_encode.end();
@@ -89,14 +119,30 @@ public:
virtual int decode(const set<int> &want_to_read,
const map<int, bufferlist> &chunks,
map<int, bufferlist> *decoded) {
-
+ //
+ // All chunks have the same size
+ //
unsigned chunk_length = (*chunks.begin()).second.length();
for (set<int>::iterator i = want_to_read.begin();
i != want_to_read.end();
i++) {
- if (chunks.find(*i) != chunks.end())
+ if (chunks.find(*i) != chunks.end()) {
+ //
+ // If the chunk is available, just copy the bufferptr pointer
+ // to the decoded argument.
+ //
(*decoded)[*i] = chunks.find(*i)->second;
- else {
+ } else if(chunks.size() != 2) {
+ //
+ // If a chunk is missing and there are not enough chunks
+ // to recover, abort.
+ //
+ return -ERANGE;
+ } else {
+ //
+ // No matter what the missing chunk is, XOR of the other
+ // two recovers it.
+ //
bufferptr chunk(chunk_length);
map<int, bufferlist>::const_iterator k = chunks.begin();
const char *a = k->second.buffers().front().c_str();