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 #pragma once
20 
21 #include "common/platform.h"
22 
23 #include <cstdint>
24 #include <cstdlib>
25 #include <string>
26 #include <sys/types.h>
27 
28 #include <condition_variable>
29 #include <thread>
30 
31 #include "chunkserver/chunk_format.h"
32 #include "common/chunk_part_type.h"
33 #include "common/disk_info.h"
34 #include "protocol/MFSCommunication.h"
35 
36 #define STATSHISTORY (24*60)
37 #define LASTERRSIZE 30
38 
39 // Block data and crc summaric size.
40 constexpr uint32_t kHddBlockSize = MFSBLOCKSIZE + 4;
41 
42 enum ChunkState {
43 	CH_AVAIL,
44 	CH_LOCKED,
45 	CH_DELETED,
46 	CH_TOBEDELETED
47 };
48 
49 class Chunk;
50 
51 struct cntcond {
52 	std::condition_variable cond;
53 	uint32_t wcnt;
54 	Chunk *owner;
55 	struct cntcond *next;
56 };
57 
58 struct ioerror {
59 	uint64_t chunkid;
60 	uint32_t timestamp;
61 	int errornumber;
62 };
63 
64 struct folder {
65 	char *path;
66 #define SCST_SCANNEEDED 0u
67 #define SCST_SCANINPROGRESS 1u
68 #define SCST_SCANTERMINATE 2u
69 #define SCST_SCANFINISHED 3u
70 #define SCST_SENDNEEDED 4u
71 #define SCST_WORKING 5u
72 	unsigned int scanstate:3;
73 	unsigned int needrefresh:1;
74 	unsigned int todel:2;
75 	unsigned int damaged:1;
76 	unsigned int toremove:2;
77 	uint8_t scanprogress;
78 #define MGST_MIGRATEDONE 0u
79 #define MGST_MIGRATEINPROGRESS 1u
80 #define MGST_MIGRATETERMINATE 2u
81 #define MGST_MIGRATEFINISHED 3u
82 	uint8_t migratestate;
83 	uint64_t leavefree;
84 	uint64_t avail;
85 	uint64_t total;
86 	HddAtomicStatistics cstat;
87 	HddStatistics stats[STATSHISTORY];
88 	uint32_t statspos;
89 	ioerror lasterrtab[LASTERRSIZE];
90 	uint32_t chunkcount;
91 	uint32_t lasterrindx;
92 	uint32_t lastrefresh;
93 	dev_t devid;
94 	ino_t lockinode;
95 	int lfd;
96 	double carry;
97 	std::thread scanthread;
98 	std::thread migratethread;
99 	Chunk *testhead,**testtail;
100 	struct folder *next;
101 };
102 
103 class Chunk {
104 public:
105 	static const uint32_t kNumberOfSubfolders = 256;
106 	enum { kCurrentDirectoryLayout = 0, kMooseFSDirectoryLayout };
107 
108 	Chunk(uint64_t chunkId, ChunkPartType type, ChunkState state);
~Chunk()109 	virtual ~Chunk() {};
110 
filename()111 	std::string filename() const {
112 		return filename_layout_ >= kCurrentDirectoryLayout
113 		               ? generateFilenameForVersion(version, filename_layout_)
114 		               : std::string();
115 	};
116 
117 	std::string generateFilenameForVersion(uint32_t version, int layout_version = kCurrentDirectoryLayout) const;
118 	int renameChunkFile(uint32_t new_version, int new_layout_version = kCurrentDirectoryLayout);
setFilenameLayout(int layout_version)119 	void setFilenameLayout(int layout_version) { filename_layout_ = layout_version; }
120 
121 	virtual off_t getBlockOffset(uint16_t blockNumber) const = 0;
122 	virtual off_t getFileSizeFromBlockCount(uint32_t blockCount) const = 0;
123 	virtual bool isFileSizeValid(off_t fileSize) const = 0;
chunkFormat()124 	virtual ChunkFormat chunkFormat() const { return ChunkFormat::IMPROPER; };
125 	uint32_t maxBlocksInFile() const;
126 	virtual void setBlockCountFromFizeSize(off_t fileSize) = 0;
type()127 	ChunkPartType type() const { return type_; }
128 	static uint32_t getSubfolderNumber(uint64_t chunkId, int layout_version = 0);
129 	static std::string getSubfolderNameGivenNumber(uint32_t subfolderNumber, int layout_version = 0);
130 	static std::string getSubfolderNameGivenChunkId(uint64_t chunkId, int layout_version = 0);
131 
132 	Chunk *testnext, **testprev;
133 	Chunk *next;
134 	cntcond *ccond;
135 	struct folder *owner;
136 	uint64_t chunkid;
137 	uint32_t version;
138 	int32_t  fd;
139 	uint16_t blocks;
140 	uint16_t refcount;
141 	uint16_t blockExpectedToBeReadNext;
142 
143 protected:
144 	ChunkPartType type_;
145 	int8_t filename_layout_; /*!< <0 - no valid name (empty string)
146 	                               0 - current directory layout
147 	                              >0 - older directory layouts */
148 public:
149 	uint8_t validattr;
150 	uint8_t todel;
151 	uint8_t state;
152 	uint8_t wasChanged;
153 };
154 
155 class MooseFSChunk : public Chunk {
156 public:
157 	static const size_t kMaxSignatureBlockSize = 1024;
158 	static const size_t kMaxCrcBlockSize = MFSBLOCKSINCHUNK * sizeof(uint32_t);
159 	static const size_t kMaxPaddingBlockSize = 4096;
160 	static const size_t kMaxHeaderSize =
161 			kMaxSignatureBlockSize + kMaxCrcBlockSize + kMaxPaddingBlockSize;
162 	static const size_t kDiskBlockSize = 4096; // 4kB
163 
164 	typedef std::array<uint8_t, kMaxCrcBlockSize> CrcDataContainer;
165 
166 	MooseFSChunk(uint64_t chunkId, ChunkPartType type, ChunkState state);
167 	off_t getBlockOffset(uint16_t blockNumber) const override;
168 	off_t getFileSizeFromBlockCount(uint32_t blockCount) const override;
169 	bool isFileSizeValid(off_t fileSize) const override;
170 	void setBlockCountFromFizeSize(off_t fileSize) override;
chunkFormat()171 	ChunkFormat chunkFormat() const override { return ChunkFormat::MOOSEFS; };
172 	off_t getSignatureOffset() const;
173 	void readaheadHeader() const;
174 	size_t getHeaderSize() const;
175 	off_t getCrcOffset() const;
176 	size_t getCrcBlockSize() const;
177 };
178 
179 class InterleavedChunk : public Chunk {
180 public:
181 	InterleavedChunk(uint64_t chunkId, ChunkPartType type, ChunkState state);
182 	off_t getBlockOffset(uint16_t blockNumber) const override;
183 	off_t getFileSizeFromBlockCount(uint32_t blockCount) const override;
184 	bool isFileSizeValid(off_t fileSize) const override;
185 	void setBlockCountFromFizeSize(off_t fileSize) override;
chunkFormat()186 	ChunkFormat chunkFormat() const override { return ChunkFormat::INTERLEAVED; };
187 };
188 
189 #define IF_MOOSEFS_CHUNK(mc, chunk) \
190 	if (MooseFSChunk *mc = dynamic_cast<MooseFSChunk *>(chunk))
191 
192 #define IF_INTERLEAVED_CHUNK(lc, chunk) \
193 	if (InterleavedChunk *lc = dynamic_cast<InterleavedChunk *>(chunk))
194