1 /*
2 Copyright 2013-2015 Skytechnology sp. z o.o.
3
4 This file is part of LizardFS.
5
6 LizardFS is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, version 3.
9
10 LizardFS is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with LizardFS. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "common/platform.h"
20 #include "chunkserver/chunk.h"
21
22 #include <fcntl.h>
23 #include <inttypes.h>
24 #include <unistd.h>
25 #include <sstream>
26
27 #include "common/massert.h"
28 #include "common/slice_traits.h"
29
Chunk(uint64_t chunkId,ChunkPartType type,ChunkState state)30 Chunk::Chunk(uint64_t chunkId, ChunkPartType type, ChunkState state)
31 : testnext(NULL),
32 testprev(NULL),
33 next(NULL),
34 ccond(NULL),
35 owner(NULL),
36 chunkid(chunkId),
37 version(0),
38 fd(-1),
39 blocks(0),
40 refcount(0),
41 blockExpectedToBeReadNext(0),
42 type_(type),
43 filename_layout_(-1),
44 validattr(0),
45 todel(0),
46 state(state),
47 wasChanged(0) {
48 }
49
generateFilenameForVersion(uint32_t version,int layout_version) const50 std::string Chunk::generateFilenameForVersion(uint32_t version, int layout_version) const {
51 std::stringstream ss;
52 char buffer[30];
53 ss << owner->path << Chunk::getSubfolderNameGivenChunkId(chunkid, layout_version) << "/chunk_";
54 if (slice_traits::isXor(type_)) {
55 if (slice_traits::xors::isXorParity(type_)) {
56 ss << "xor_parity_of_";
57 } else {
58 ss << "xor_" << (unsigned)slice_traits::xors::getXorPart(type_) << "_of_";
59 }
60 ss << (unsigned)slice_traits::xors::getXorLevel(type_) << "_";
61 }
62 if (slice_traits::isEC(type_)) {
63 ss << "ec_" << (type_.getSlicePart() + 1) << "_of_"
64 << slice_traits::ec::getNumberOfDataParts(type_) << "_"
65 << slice_traits::ec::getNumberOfParityParts(type_) << "_";
66 }
67 sprintf(buffer, "%016" PRIX64 "_%08" PRIX32 ".mfs", chunkid, version);
68 if (chunkFormat() == ChunkFormat::INTERLEAVED) {
69 memcpy(buffer + 26, "liz", 3);
70 }
71 ss << buffer;
72 return ss.str();
73 }
74
maxBlocksInFile() const75 uint32_t Chunk::maxBlocksInFile() const {
76 int data_part_count = slice_traits::getNumberOfDataParts(type_);
77 return (MFSBLOCKSINCHUNK + data_part_count - 1) / data_part_count;
78 }
79
renameChunkFile(uint32_t new_version,int new_layout_version)80 int Chunk::renameChunkFile(uint32_t new_version, int new_layout_version) {
81 std::string old_file_name = filename();
82 std::string new_file_name = generateFilenameForVersion(new_version, new_layout_version);
83
84 int status = rename(old_file_name.c_str(), new_file_name.c_str());
85 if (status < 0) {
86 return status;
87 }
88
89 filename_layout_ = new_layout_version;
90 version = new_version;
91
92 return 0;
93 }
94
setBlockCountFromFizeSize(off_t fileSize)95 void Chunk::setBlockCountFromFizeSize(off_t fileSize) {
96 sassert(isFileSizeValid(fileSize));
97 blocks = fileSize / kHddBlockSize;
98 }
99
getSubfolderNumber(uint64_t chunkId,int layout_version)100 uint32_t Chunk::getSubfolderNumber(uint64_t chunkId, int layout_version) {
101 // layout version 0 corresponds to current directory/chunk naming convention
102 // values greater than 0 describe older versions (order is not important)
103 return (layout_version == kCurrentDirectoryLayout ? chunkId >> 16 : chunkId) & 0xFF;
104 }
105
getSubfolderNameGivenNumber(uint32_t subfolderNumber,int layout_version)106 std::string Chunk::getSubfolderNameGivenNumber(uint32_t subfolderNumber, int layout_version) {
107 sassert(subfolderNumber < Chunk::kNumberOfSubfolders);
108 char buffer[16];
109 // layout version 0 corresponds to current directory/chunk naming convention
110 // values greater than 0 describe older versions (order is not important)
111 if (layout_version == kCurrentDirectoryLayout) {
112 sprintf(buffer, "chunks%02X", unsigned(subfolderNumber));
113 } else {
114 sprintf(buffer, "%02X", unsigned(subfolderNumber));
115 }
116 return std::string(buffer);
117 }
118
getSubfolderNameGivenChunkId(uint64_t chunkId,int layout_version)119 std::string Chunk::getSubfolderNameGivenChunkId(uint64_t chunkId, int layout_version) {
120 return Chunk::getSubfolderNameGivenNumber(Chunk::getSubfolderNumber(chunkId, layout_version), layout_version);
121 }
122
MooseFSChunk(uint64_t chunkId,ChunkPartType type,ChunkState state)123 MooseFSChunk::MooseFSChunk(uint64_t chunkId, ChunkPartType type, ChunkState state) :
124 Chunk(chunkId, type, state) {
125 }
126
getBlockOffset(uint16_t blockNumber) const127 off_t MooseFSChunk::getBlockOffset(uint16_t blockNumber) const {
128 return getHeaderSize() + MFSBLOCKSIZE * blockNumber;
129 }
130
getFileSizeFromBlockCount(uint32_t blockCount) const131 off_t MooseFSChunk::getFileSizeFromBlockCount(uint32_t blockCount) const {
132 return getHeaderSize() + blockCount * MFSBLOCKSIZE;
133 }
134
setBlockCountFromFizeSize(off_t fileSize)135 void MooseFSChunk::setBlockCountFromFizeSize(off_t fileSize) {
136 sassert(isFileSizeValid(fileSize));
137 fileSize -= getHeaderSize();
138 blocks = fileSize / MFSBLOCKSIZE;
139 }
140
isFileSizeValid(off_t fileSize) const141 bool MooseFSChunk::isFileSizeValid(off_t fileSize) const {
142 if (fileSize < static_cast<off_t>(getHeaderSize())) {
143 return false;
144 }
145 fileSize -= getHeaderSize();
146 if (fileSize % MFSBLOCKSIZE != 0) {
147 return false;
148 }
149 if (fileSize / MFSBLOCKSIZE > maxBlocksInFile()) {
150 return false;
151 }
152 return true;
153 }
154
getSignatureOffset() const155 off_t MooseFSChunk::getSignatureOffset() const {
156 return 0;
157 }
158
readaheadHeader() const159 void MooseFSChunk::readaheadHeader() const {
160 #ifdef LIZARDFS_HAVE_POSIX_FADVISE
161 posix_fadvise(fd, 0, getHeaderSize(), POSIX_FADV_WILLNEED);
162 #elif defined(__APPLE__)
163 struct radvisory ra;
164 ra.ra_offset = 0;
165 ra.ra_count = getHeaderSize();
166 fcntl(fd, F_RDADVISE, &ra);
167 #endif
168 }
169
getHeaderSize() const170 size_t MooseFSChunk::getHeaderSize() const {
171 if (slice_traits::isStandard(type_)) {
172 return kMaxSignatureBlockSize + serializedSize(uint32_t()) * maxBlocksInFile();
173 } else {
174 assert(slice_traits::isXor(type_) || slice_traits::isEC(type_));
175
176 uint32_t requiredHeaderSize = kMaxSignatureBlockSize + serializedSize(uint32_t()) * maxBlocksInFile();
177 // header size is equal to the requiredHeaderSize rounded up to typical disk block size
178 uint32_t diskBlockSize = kDiskBlockSize;
179 off_t dataOffset = (requiredHeaderSize + diskBlockSize - 1) / diskBlockSize * diskBlockSize;
180 return dataOffset;
181 }
182 }
183
getCrcOffset() const184 off_t MooseFSChunk::getCrcOffset() const {
185 return kMaxSignatureBlockSize;
186 }
187
getCrcBlockSize() const188 size_t MooseFSChunk::getCrcBlockSize() const {
189 return serializedSize(uint32_t()) * maxBlocksInFile();
190 }
191
InterleavedChunk(uint64_t chunkId,ChunkPartType type,ChunkState state)192 InterleavedChunk::InterleavedChunk(uint64_t chunkId, ChunkPartType type, ChunkState state) :
193 Chunk(chunkId, type, state) {
194 }
195
getBlockOffset(uint16_t blockNumber) const196 off_t InterleavedChunk::getBlockOffset(uint16_t blockNumber) const {
197 return static_cast<uint32_t>(blockNumber) * kHddBlockSize;
198 }
199
getFileSizeFromBlockCount(uint32_t blockCount) const200 off_t InterleavedChunk::getFileSizeFromBlockCount(uint32_t blockCount) const {
201 return blockCount * kHddBlockSize;
202 }
203
setBlockCountFromFizeSize(off_t fileSize)204 void InterleavedChunk::setBlockCountFromFizeSize(off_t fileSize) {
205 sassert(isFileSizeValid(fileSize));
206 blocks = fileSize / kHddBlockSize;
207 }
208
isFileSizeValid(off_t fileSize) const209 bool InterleavedChunk::isFileSizeValid(off_t fileSize) const {
210 return fileSize % kHddBlockSize == 0;
211 }
212