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