diff options
Diffstat (limited to 'gluster/swift/obj/diskfile.py')
-rw-r--r-- | gluster/swift/obj/diskfile.py | 94 |
1 files changed, 53 insertions, 41 deletions
diff --git a/gluster/swift/obj/diskfile.py b/gluster/swift/obj/diskfile.py index 47cde89..eb180a2 100644 --- a/gluster/swift/obj/diskfile.py +++ b/gluster/swift/obj/diskfile.py @@ -447,9 +447,9 @@ class DiskFileWriter(object): df._threadpool.force_run_in_thread(self._finalize_put, metadata) - # Avoid the unlink() system call as part of the mkstemp context - # cleanup - self.tmppath = None + # Avoid the unlink() system call as part of the DiskFile.create() + # context cleanup + self._tmppath = None class DiskFileReader(object): @@ -509,7 +509,7 @@ class DiskFileReader(object): bytes_read += len(chunk) diff = bytes_read - dropped_cache if diff > (1024 * 1024): - self._drop_cache(self._fd, dropped_cache, diff) + self._drop_cache(dropped_cache, diff) dropped_cache = bytes_read yield chunk if self._iter_hook: @@ -604,6 +604,7 @@ class DiskFile(object): self._logger = mgr.logger self._metadata = None self._fd = None + self._stat = None # Don't store a value for data_file until we know it exists. self._data_file = None @@ -644,37 +645,49 @@ class DiskFile(object): """ # Writes are always performed to a temporary file try: - fd = do_open(self._data_file, os.O_RDONLY | O_CLOEXEC) + self._fd = do_open(self._data_file, os.O_RDONLY | O_CLOEXEC) except GlusterFileSystemOSError as err: if err.errno in (errno.ENOENT, errno.ENOTDIR): # If the file does exist, or some part of the path does not # exist, raise the expected DiskFileNotExist raise DiskFileNotExist raise - else: - stats = do_fstat(fd) - if not stats: - return - self._is_dir = stat.S_ISDIR(stats.st_mode) - obj_size = stats.st_size - - self._metadata = read_metadata(fd) - if not validate_object(self._metadata): - create_object_metadata(fd) - self._metadata = read_metadata(fd) - assert self._metadata is not None - self._filter_metadata() - - if self._is_dir: - do_close(fd) - obj_size = 0 - self._fd = -1 - else: - if self._is_object_expired(self._metadata): - raise DiskFileExpired(metadata=self._metadata) - self._fd = fd - - self._obj_size = obj_size + try: + self._stat = do_fstat(self._fd) + self._is_dir = stat.S_ISDIR(self._stat.st_mode) + obj_size = self._stat.st_size + + self._metadata = read_metadata(self._fd) + if not validate_object(self._metadata, self._stat): + create_object_metadata(self._fd) + self._metadata = read_metadata(self._fd) + assert self._metadata is not None + self._filter_metadata() + + if self._is_dir: + do_close(self._fd) + obj_size = 0 + self._fd = -1 + else: + if self._is_object_expired(self._metadata): + raise DiskFileExpired(metadata=self._metadata) + self._obj_size = obj_size + except (OSError, IOError, DiskFileExpired) as err: + # Something went wrong. Context manager will not call + # __exit__. So we close the fd manually here. + self._close_fd() + if hasattr(err, 'errno') and \ + err.errno in (errno.ENOENT, errno.ESTALE): + # Handle races: ENOENT/ESTALE can be raised by read_metadata() + # call in GlusterFS if file gets deleted by another + # client after do_open() succeeds + logging.warn("open(%s) succeeded but one of the subsequent " + "syscalls failed with ENOENT/ESTALE. Raising " + "DiskFileNotExist." % (self._data_file)) + raise DiskFileNotExist + else: + # Re-raise the original exception after fd has been closed + raise err return self def _is_object_expired(self, metadata): @@ -712,6 +725,12 @@ class DiskFile(object): raise DiskFileNotOpen() return self + def _close_fd(self): + if self._fd is not None: + fd, self._fd = self._fd, None + if fd > -1: + do_close(fd) + def __exit__(self, t, v, tb): """ Context exit. @@ -723,10 +742,7 @@ class DiskFile(object): responsibility of the implementation to properly handle that. """ self._metadata = None - if self._fd is not None: - fd, self._fd = self._fd, None - if fd > -1: - do_close(fd) + self._close_fd() def get_metadata(self): """ @@ -833,10 +849,6 @@ class DiskFile(object): " on subpath: %s" % (full_path, cur_path)) child = stack.pop() if stack else None return True, newmd - # Exists, but as a file - #raise DiskFileError('DiskFile.put(): directory creation failed' - # ' since the target, %s, already exists as' - # ' a file' % df._data_file) @contextmanager def create(self, size=None): @@ -893,7 +905,7 @@ class DiskFile(object): if attempts >= MAX_OPEN_ATTEMPTS: # We failed after N attempts to create the temporary # file. - raise DiskFileError('DiskFile.mkstemp(): failed to' + raise DiskFileError('DiskFile.create(): failed to' ' successfully create a temporary file' ' without running into a name conflict' ' after %d of %d attempts for: %s' % ( @@ -906,7 +918,7 @@ class DiskFile(object): # FIXME: Possible FUSE issue or race condition, let's # sleep on it and retry the operation. _random_sleep() - logging.warn("DiskFile.mkstemp(): %s ... retrying in" + logging.warn("DiskFile.create(): %s ... retrying in" " 0.1 secs", gerr) attempts += 1 elif not self._obj_path: @@ -915,7 +927,7 @@ class DiskFile(object): # could be a FUSE issue or some race condition, so let's # sleep a bit and retry. _random_sleep() - logging.warn("DiskFile.mkstemp(): %s ... retrying in" + logging.warn("DiskFile.create(): %s ... retrying in" " 0.1 secs", gerr) attempts += 1 elif attempts > 1: @@ -923,7 +935,7 @@ class DiskFile(object): # also be a FUSE issue or some race condition, nap and # retry. _random_sleep() - logging.warn("DiskFile.mkstemp(): %s ... retrying in" + logging.warn("DiskFile.create(): %s ... retrying in" " 0.1 secs" % gerr) attempts += 1 else: |