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