1 /*
2    Copyright 2013-2017 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 "mount/chunk_locator.h"
21 
22 #include <unistd.h>
23 
24 #include "protocol/MFSCommunication.h"
25 #include "common/exceptions.h"
26 #include "common/mfserr.h"
27 #include "devtools/request_log.h"
28 #include "mount/mastercomm.h"
29 
invalidateCache(uint32_t inode,uint32_t index)30 void ReadChunkLocator::invalidateCache(uint32_t inode, uint32_t index) {
31 	std::unique_lock<std::mutex> lock(mutex_);
32 	if (cache_ && inode == inode_ && index == index_) {
33 		cache_ = nullptr;
34 	}
35 }
36 
locateChunk(uint32_t inode,uint32_t index)37 std::shared_ptr<const ChunkLocationInfo> ReadChunkLocator::locateChunk(uint32_t inode, uint32_t index) {
38 	{
39 		std::unique_lock<std::mutex> lock(mutex_);
40 		if (cache_ && inode == inode_ && index == index_) {
41 			return cache_;
42 		}
43 	}
44 	LOG_AVG_TILL_END_OF_SCOPE0("ReadChunkLocator::locateChunk");
45 	uint64_t chunkId;
46 	uint32_t version;
47 	uint64_t fileLength;
48 	ChunkLocationInfo::ChunkLocations locations;
49 #ifdef USE_LEGACY_READ_MESSAGES
50 	const uint8_t *chunkserversData;
51 	uint32_t chunkserversDataSize;
52 	uint8_t status = fs_readchunk(inode, index, &fileLength, &chunkId, &version,
53 			&chunkserversData, &chunkserversDataSize);
54 #else
55 	uint8_t status = fs_lizreadchunk(locations, chunkId, version, fileLength, inode, index);
56 #endif
57 
58 	if (status != 0) {
59 		if (status == LIZARDFS_ERROR_ENOENT) {
60 			throw UnrecoverableReadException("Chunk locator: error sent by master server", status);
61 		} else {
62 			throw RecoverableReadException("Chunk locator: error sent by master server", status);
63 		}
64 	}
65 
66 #ifdef USE_LEGACY_READ_MESSAGES
67 	if (chunkserversData != NULL) {
68 		uint32_t ip;
69 		uint16_t port;
70 		uint32_t entrySize = serializedSize(ip, port);
71 		for (const uint8_t *rptr = chunkserversData;
72 				rptr < chunkserversData + chunkserversDataSize;
73 				rptr += entrySize) {
74 			deserialize(rptr, entrySize, ip, port);
75 			locations.push_back(
76 					ChunkTypeWithAddress(NetworkAddress(ip, port),
77 						ChunkType::getStandardChunkType()));
78 		}
79 	}
80 #endif
81 	{
82 		std::unique_lock<std::mutex> lock(mutex_);
83 		inode_ = inode;
84 		index_ = index;
85 		cache_ = std::make_shared<ChunkLocationInfo>(chunkId, version, fileLength, locations);
86 		return cache_;
87 	}
88 }
89 
locateAndLockChunk(uint32_t inode,uint32_t index)90 void WriteChunkLocator::locateAndLockChunk(uint32_t inode, uint32_t index) {
91 	LOG_AVG_TILL_END_OF_SCOPE0("WriteChunkLocator::locateAndLockChunk");
92 	sassert(inode_ == 0 || (inode_ == inode && index_ == index));
93 	inode_ = inode;
94 	index_ = index;
95 	locationInfo_.locations.clear();
96 	uint32_t oldLockId = lockId_;
97 	uint64_t oldFileLength = locationInfo_.fileLength;
98 
99 	uint8_t status = fs_lizwritechunk(inode, index, lockId_, locationInfo_.fileLength,
100 			locationInfo_.chunkId, locationInfo_.version, locationInfo_.locations);
101 	if (status != LIZARDFS_STATUS_OK) {
102 		if (status == LIZARDFS_ERROR_IO
103 				|| status == LIZARDFS_ERROR_NOCHUNKSERVERS
104 				|| status == LIZARDFS_ERROR_LOCKED
105 				|| status == LIZARDFS_ERROR_CHUNKBUSY
106 				|| status == LIZARDFS_ERROR_CHUNKLOST) {
107 			throw RecoverableWriteException("error sent by master server", status);
108 		} else {
109 			lockId_ = 0;
110 			throw UnrecoverableWriteException("error sent by master server", status);
111 		}
112 	}
113 
114 	if (oldLockId != 0) {
115 		locationInfo_.fileLength = oldFileLength;
116 	}
117 }
118 
unlockChunk()119 void WriteChunkLocator::unlockChunk() {
120 	LOG_AVG_TILL_END_OF_SCOPE0("WriteChunkLocator::unlockChunk");
121 	sassert(lockId_ != 0);
122 	uint8_t status = fs_lizwriteend(locationInfo_.chunkId, lockId_,
123 			inode_, locationInfo_.fileLength);
124 	if (status == LIZARDFS_ERROR_IO) {
125 		// Communication with the master server failed
126 		throw RecoverableWriteException("Sending WRITE_END to the master failed", status);
127 	}
128 	// Master unlocked the chunk and returned some status
129 	lockId_ = 0;
130 	if (status != LIZARDFS_STATUS_OK) {
131 		throw UnrecoverableWriteException("Sending WRITE_END to the master failed", status);
132 	}
133 }
134