fuse_impls_read.c
上传用户:quxuerui
上传日期:2018-01-08
资源大小:41811k
文件大小:5k
- /**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "fuse_dfs.h"
- #include "fuse_impls.h"
- #include "fuse_file_handle.h"
- static size_t min(const size_t x, const size_t y) {
- return x < y ? x : y;
- }
- /**
- * dfs_read
- *
- * Reads from dfs or the open file's buffer. Note that fuse requires that
- * either the entire read be satisfied or the EOF is hit or direct_io is enabled
- *
- */
- int dfs_read(const char *path, char *buf, size_t size, off_t offset,
- struct fuse_file_info *fi)
- {
- TRACE1("read",path)
-
- // retrieve dfs specific data
- dfs_context *dfs = (dfs_context*)fuse_get_context()->private_data;
- // check params and the context var
- assert(dfs);
- assert(path);
- assert(buf);
- assert(offset >= 0);
- assert(size >= 0);
- assert(fi);
- dfs_fh *fh = (dfs_fh*)fi->fh;
- assert(fh != NULL);
- assert(fh->fs != NULL);
- assert(fh->hdfsFH != NULL);
- // special case this as simplifies the rest of the logic to know the caller wanted > 0 bytes
- if (size == 0)
- return 0;
- // If size is bigger than the read buffer, then just read right into the user supplied buffer
- if ( size >= dfs->rdbuffer_size) {
- int num_read;
- size_t total_read = 0;
- while (size - total_read > 0 && (num_read = hdfsPread(fh->fs, fh->hdfsFH, offset + total_read, buf + total_read, size - total_read)) > 0) {
- total_read += num_read;
- }
- // if there was an error before satisfying the current read, this logic declares it an error
- // and does not try to return any of the bytes read. Don't think it matters, so the code
- // is just being conservative.
- if (total_read < size && num_read < 0) {
- total_read = -EIO;
- }
- return total_read;
- }
- //
- // Critical section - protect from multiple reads in different threads accessing the read buffer
- // (no returns until end)
- //
- pthread_mutex_lock(&fh->mutex);
- // used only to check the postcondition of this function - namely that we satisfy
- // the entire read or EOF is hit.
- int isEOF = 0;
- int ret = 0;
- // check if the buffer is empty or
- // the read starts before the buffer starts or
- // the read ends after the buffer ends
- if (fh->bufferSize == 0 ||
- offset < fh->buffersStartOffset ||
- offset + size > fh->buffersStartOffset + fh->bufferSize)
- {
- // Read into the buffer from DFS
- int num_read = 0;
- size_t total_read = 0;
- while (dfs->rdbuffer_size - total_read > 0 &&
- (num_read = hdfsPread(fh->fs, fh->hdfsFH, offset + total_read, fh->buf + total_read, dfs->rdbuffer_size - total_read)) > 0) {
- total_read += num_read;
- }
- // if there was an error before satisfying the current read, this logic declares it an error
- // and does not try to return any of the bytes read. Don't think it matters, so the code
- // is just being conservative.
- if (total_read < size && num_read < 0) {
- // invalidate the buffer
- fh->bufferSize = 0;
- syslog(LOG_ERR, "Read error - pread failed for %s with return code %d %s:%d", path, (int)num_read, __FILE__, __LINE__);
- ret = -EIO;
- } else {
- // Either EOF, all read or read beyond size, but then there was an error
- fh->bufferSize = total_read;
- fh->buffersStartOffset = offset;
- if (dfs->rdbuffer_size - total_read > 0) {
- // assert(num_read == 0); this should be true since if num_read < 0 handled above.
- isEOF = 1;
- }
- }
- }
- //
- // NOTE on EOF, fh->bufferSize == 0 and ret = 0 ,so the logic for copying data into the caller's buffer is bypassed, and
- // the code returns 0 as required
- //
- if (ret == 0 && fh->bufferSize > 0) {
- assert(offset >= fh->buffersStartOffset);
- assert(fh->buf);
- const size_t bufferReadIndex = offset - fh->buffersStartOffset;
- assert(bufferReadIndex >= 0 && bufferReadIndex < fh->bufferSize);
- const size_t amount = min(fh->buffersStartOffset + fh->bufferSize - offset, size);
- assert(amount >= 0 && amount <= fh->bufferSize);
- const char *offsetPtr = fh->buf + bufferReadIndex;
- assert(offsetPtr >= fh->buf);
- assert(offsetPtr + amount <= fh->buf + fh->bufferSize);
-
- memcpy(buf, offsetPtr, amount);
- ret = amount;
- }
- //
- // Critical section end
- //
- pthread_mutex_unlock(&fh->mutex);
-
- // fuse requires the below and the code should guarantee this assertion
- // 3 cases on return:
- // 1. entire read satisfied
- // 2. partial read and isEOF - including 0 size read
- // 3. error
- assert(ret == size || isEOF || ret < 0);
- return ret;
- }