aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/on_disk/chunks/chunked_helpers.cpp
blob: e0bd21bf7c5a197876eeb896e0401b0b933e7488 (plain) (blame)
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
#include <util/ysaveload.h>

#include "chunked_helpers.h"

TBlob GetBlock(const TBlob& blob, size_t index) {
    TChunkedDataReader reader(blob);
    if (index >= reader.GetBlocksCount())
        ythrow yexception() << "index " << index << " is >= than block count " << reader.GetBlocksCount();
    size_t begin = (const char*)reader.GetBlock(index) - (const char*)blob.Data();
    return blob.SubBlob(begin, begin + reader.GetBlockLen(index));
}

/*************************** TNamedChunkedDataReader ***************************/

static const char* NamedChunkedDataMagic = "NamedChunkedData";

TNamedChunkedDataReader::TNamedChunkedDataReader(const TBlob& blob)
    : TChunkedDataReader(blob)
{
    if (TChunkedDataReader::GetBlocksCount() < 1)
        throw yexception() << "Too few blocks";

    size_t block = TChunkedDataReader::GetBlocksCount() - 1;
    size_t magicLen = strlen(NamedChunkedDataMagic);
    if (GetBlockLen(block) < magicLen || memcmp(GetBlock(block), NamedChunkedDataMagic, magicLen) != 0)
        throw yexception() << "Not a valid named chunked data file";

    TMemoryInput input(static_cast<const char*>(GetBlock(block)) + magicLen, GetBlockLen(block) - magicLen);
    Load(&input, Names);

    size_t index = 0;
    for (TVector<TString>::const_iterator it = Names.begin(); it != Names.end(); ++it, ++index) {
        if (!it->empty())
            NameToIndex[*it] = index;
    }
}

/*************************** TNamedChunkedDataWriter ***************************/

TNamedChunkedDataWriter::TNamedChunkedDataWriter(IOutputStream& slave) 
    : TChunkedDataWriter(slave)
{
}

TNamedChunkedDataWriter::~TNamedChunkedDataWriter() {
}

void TNamedChunkedDataWriter::NewBlock() {
    NewBlock("");
}

void TNamedChunkedDataWriter::NewBlock(const TString& name) {
    if (!name.empty()) {
        if (NameToIndex.count(name) != 0)
            throw yexception() << "Block name is not unique";
        NameToIndex[name] = Names.size();
    }
    Names.push_back(name);
    TChunkedDataWriter::NewBlock();
}

void TNamedChunkedDataWriter::WriteFooter() {
    NewBlock("");
    Write(NamedChunkedDataMagic);
    Save(this, Names);
    TChunkedDataWriter::WriteFooter();
}