1 /*
2    Copyright 2013-2014 EditShare, 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 <array>
24 
25 #include "common/goal.h"
26 #include "common/serialization.h"
27 #include "common/serialization_macros.h"
28 
29 namespace detail {
30 
31 template <class T>
32 class SerializableGoalIdArray : public std::array<T, GoalId::kMax + 1> {
33 	typedef std::array<T, GoalId::kMax + 1> base;
34 
35 public:
serializedSize()36 	uint32_t serializedSize() const {
37 		return ::serializedSize(goalsAsMap());
38 	}
39 
serialize(uint8_t ** destination)40 	void serialize(uint8_t **destination) const {
41 		::serialize(destination, goalsAsMap());
42 	}
43 
deserialize(const uint8_t ** source,uint32_t & bytes_left_in_buffer)44 	void deserialize(const uint8_t **source, uint32_t &bytes_left_in_buffer) {
45 		// verify if the map is empty
46 		for (uint8_t goal = 0; goal <= GoalId::kMax; ++goal) {
47 			assert(operator[](goal) == T());
48 		}
49 
50 		// deserialize the map
51 		std::map<uint8_t, T> map;
52 		::deserialize(source, bytes_left_in_buffer, map);
53 		for (const auto &goal_and_value : map) {
54 			operator[](goal_and_value.first) = goal_and_value.second;
55 		}
56 	}
57 
58 	using base::operator[];
59 
60 private:
goalsAsMap()61 	std::map<uint8_t, T> goalsAsMap() const {
62 		std::map<uint8_t, T> result;
63 		T default_value = T();
64 
65 		for (uint8_t goal = 0; goal <= GoalId::kMax; ++goal) {
66 			if (operator[](goal) != default_value) {  // Packet size optimization!
67 				result[goal] = operator[](goal);
68 			}
69 		}
70 
71 		return result;
72 	}
73 };
74 
75 }  // detail
76 
77 class ChunksAvailabilityState {
78 public:
79 	enum State { kSafe = 0, kEndangered, kLost, kStateCount };
80 
ChunksAvailabilityState()81 	ChunksAvailabilityState() : data_() {
82 	}
83 
safeChunks(uint8_t goal)84 	uint64_t safeChunks(uint8_t goal) const {
85 		return data_[kSafe][goal];
86 	}
endangeredChunks(uint8_t goal)87 	uint64_t endangeredChunks(uint8_t goal) const {
88 		return data_[kEndangered][goal];
89 	}
lostChunks(uint8_t goal)90 	uint64_t lostChunks(uint8_t goal) const {
91 		return data_[kLost][goal];
92 	}
addChunk(uint8_t goal,State state)93 	void addChunk(uint8_t goal, State state) {
94 		getMapForState(state)[goal]++;
95 	}
removeChunk(uint8_t goal,State state)96 	void removeChunk(uint8_t goal, State state) {
97 		getMapForState(state)[goal]--;
98 	}
99 
100 	LIZARDFS_DEFINE_SERIALIZE_METHODS(data_);
101 
102 private:
getMapForState(State state)103 	detail::SerializableGoalIdArray<uint64_t> &getMapForState(State state) {
104 		assert(state >= kSafe && state <= kLost);
105 		return data_[state];
106 	}
107 
108 	// count of safe/endangered/lost chunks for each goal
109 	std::array<detail::SerializableGoalIdArray<uint64_t>, 3> data_;
110 };
111 
112 /*! \brief Class for keeping statistics for chunk parts.
113  *
114  * Basically this is 2x two dimensional matrix for keeping integer values
115  * describing number of chunk part copies.
116  *
117  * Names of the class methods start to make sens after looking
118  * at the cgi table "All chunks state matrix".
119  */
120 class ChunksReplicationState {
121 public:
122 	constexpr static uint32_t kMaxPartsCount = 11; /*!< Maximum number of parts that we keep
123 	                                                    in statistics. */
124 
ChunksReplicationState()125 	ChunksReplicationState() : chunksToReplicate_(), chunksToDelete_() {
126 	}
127 
chunksToReplicate(uint8_t goal,uint32_t missingParts)128 	uint64_t chunksToReplicate(uint8_t goal, uint32_t missingParts) const {
129 		assert(missingParts < kMaxPartsCount);
130 		return chunksToReplicate_[goal][missingParts];
131 	}
chunksToDelete(uint8_t goal,uint32_t redundantParts)132 	uint64_t chunksToDelete(uint8_t goal, uint32_t redundantParts) const {
133 		assert(redundantParts < kMaxPartsCount);
134 		return chunksToDelete_[goal][redundantParts];
135 	}
addChunk(uint8_t goal,uint32_t missingParts,uint32_t redundantParts)136 	void addChunk(uint8_t goal, uint32_t missingParts, uint32_t redundantParts) {
137 		missingParts = std::min(missingParts, kMaxPartsCount - 1);
138 		redundantParts = std::min(redundantParts, kMaxPartsCount - 1);
139 		chunksToReplicate_[goal][missingParts]++;
140 		chunksToDelete_[goal][redundantParts]++;
141 	}
removeChunk(uint8_t goal,uint32_t missingParts,uint32_t redundantParts)142 	void removeChunk(uint8_t goal, uint32_t missingParts, uint32_t redundantParts) {
143 		missingParts = std::min(missingParts, kMaxPartsCount - 1);
144 		redundantParts = std::min(redundantParts, kMaxPartsCount - 1);
145 		chunksToReplicate_[goal][missingParts]--;
146 		chunksToDelete_[goal][redundantParts]--;
147 	}
148 
149 	LIZARDFS_DEFINE_SERIALIZE_METHODS(chunksToReplicate_, chunksToDelete_);
150 
151 private:
152 	// count of chunks that need replication/deletion for each goal and number of missing parts
153 	detail::SerializableGoalIdArray<std::array<uint64_t, kMaxPartsCount>> chunksToReplicate_;
154 	detail::SerializableGoalIdArray<std::array<uint64_t, kMaxPartsCount>> chunksToDelete_;
155 };
156