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 <fcntl.h>
21 #include <unistd.h>
22 #include <cassert>
23 #include <cerrno>
24 #include <cstddef>
25 #include <cstdint>
26 #include <ios>
27 #include <stdexcept>
28 
29 #include "chunkserver/output_buffer.h"
30 #include "common/crc.h"
31 #include "common/massert.h"
32 #include "devtools/request_log.h"
33 
OutputBuffer(size_t internalBufferCapacity)34 OutputBuffer::OutputBuffer(size_t internalBufferCapacity)
35 	: internalBufferCapacity_(internalBufferCapacity),
36 	  buffer_(internalBufferCapacity, 0),
37 	  bufferUnflushedDataFirstIndex_(0),
38 	  bufferUnflushedDataOneAfterLastIndex_(0)
39 {
40 	eassert(internalBufferCapacity > 0);
41 	buffer_.reserve(internalBufferCapacity_);
42 }
43 
writeOutToAFileDescriptor(int outputFileDescriptor)44 OutputBuffer::WriteStatus OutputBuffer::writeOutToAFileDescriptor(int outputFileDescriptor) {
45 	while (bytesInABuffer() > 0) {
46 		ssize_t ret = ::write(outputFileDescriptor, &buffer_[bufferUnflushedDataFirstIndex_],
47 				bytesInABuffer());
48 		if (ret <= 0) {
49 			if (ret == 0 || errno == EAGAIN) {
50 				return WRITE_AGAIN;
51 			}
52 			return WRITE_ERROR;
53 		}
54 		bufferUnflushedDataFirstIndex_ += ret;
55 	}
56 	return WRITE_DONE;
57 }
58 
bytesInABuffer() const59 size_t OutputBuffer::bytesInABuffer() const {
60 	return bufferUnflushedDataOneAfterLastIndex_ - bufferUnflushedDataFirstIndex_;
61 }
62 
clear()63 void OutputBuffer::clear() {
64 	bufferUnflushedDataFirstIndex_ = 0;
65 	bufferUnflushedDataOneAfterLastIndex_ = 0;
66 }
67 
copyIntoBuffer(int inputFileDescriptor,size_t len,off_t * offset)68 ssize_t OutputBuffer::copyIntoBuffer(int inputFileDescriptor, size_t len, off_t* offset) {
69 	eassert(len + bufferUnflushedDataOneAfterLastIndex_ <= internalBufferCapacity_);
70 	off_t bytes_written = 0;
71 	while (len > 0) {
72 		ssize_t ret = pread(inputFileDescriptor, (void*)&buffer_[bufferUnflushedDataOneAfterLastIndex_], len,
73 				(offset ? *offset : 0));
74 		if (ret <= 0) {
75 			return bytes_written;
76 		}
77 		len -= ret;
78 		bufferUnflushedDataOneAfterLastIndex_ += ret;
79 		bytes_written += ret;
80 	}
81 	return bytes_written;
82 }
83 
checkCRC(size_t bytes,uint32_t crc) const84 bool OutputBuffer::checkCRC(size_t bytes, uint32_t crc) const {
85 	assert(bufferUnflushedDataOneAfterLastIndex_ - bytes > 0
86 			&& bufferUnflushedDataOneAfterLastIndex_ - bytes < buffer_.size());
87 	return mycrc32(0, &buffer_[bufferUnflushedDataOneAfterLastIndex_ - bytes], bytes) == crc;
88 }
89 
copyIntoBuffer(const void * mem,size_t len)90 ssize_t OutputBuffer::copyIntoBuffer(const void *mem, size_t len) {
91 	eassert(bufferUnflushedDataOneAfterLastIndex_ + len <= internalBufferCapacity_);
92 	memcpy((void*)&buffer_[bufferUnflushedDataOneAfterLastIndex_], mem, len);
93 	bufferUnflushedDataOneAfterLastIndex_ += len;
94 
95 	return len;
96 }
97 
~OutputBuffer()98 OutputBuffer::~OutputBuffer() {
99 }
100