def _unlinkold(self): if self._is_dir: # Marker, or object, directory. # # Delete from the filesystem only if it contains no objects. # If it does contain objects, then just remove the object # metadata tag which will make this directory a # fake-filesystem-only directory and will be deleted when the # container or parent directory is deleted. # # FIXME: Ideally we should use an atomic metadata update operation metadata = read_metadata(self._data_file) if dir_is_object(metadata): metadata[X_OBJECT_TYPE] = DIR_NON_OBJECT write_metadata(self._data_file, metadata) rmobjdir(self._data_file) else: # Delete file object do_unlink(self._data_file) # Garbage collection of non-object directories. Now that we # deleted the file, determine if the current directory and any # parent directory may be deleted. dirname = os.path.dirname(self._data_file) while dirname and dirname != self._container_path: # Try to remove any directories that are not objects. if not rmobjdir(dirname): # If a directory with objects has been found, we can stop # garabe collection break else: dirname = os.path.dirname(dirname)
def test_do_unlink(self): fd, tmpfile = mkstemp() try: assert fs.do_unlink(tmpfile) is None assert not os.path.exists(tmpfile) res = fs.do_unlink(os.path.join('/tmp', str(random.random()))) assert res is None finally: os.close(fd)
def test_do_unlink_err(self): tmpdir = mkdtemp() try: fs.do_unlink(tmpdir) except SwiftOnFileSystemOSError: pass else: self.fail('SwiftOnFileSystemOSError expected') finally: os.rmdir(tmpdir)
def create(self, hpss_hints): """ Context manager to create a file. We create a temporary file first, and then return a DiskFileWriter object to encapsulate the state. For Gluster, we first optimistically create the temporary file using the "rsync-friendly" .NAME.random naming. If we find that some path to the file does not exist, we then create that path and then create the temporary file again. If we get file name conflict, we'll retry using different random suffixes 1,000 times before giving up. .. note:: An implementation is not required to perform on-disk preallocations even if the parameter is specified. But if it does and it fails, it must raise a `DiskFileNoSpace` exception. :param hpss_hints: dict containing HPSS class of service hints :raises DiskFileNoSpace: if a size is specified and allocation fails :raises AlreadyExistsAsFile: if path or part of a path is not a \ directory """ # Create /account/container directory structure on mount point root try: self._logger.debug("DiskFile: Creating directories for %s" % self._container_path) hpss_utils.makedirs(self._container_path) except OSError as err: if err.errno != errno.EEXIST: raise # Create directories to object name, if they don't exist. self._logger.debug("DiskFile: creating directories in obj name %s" % self._obj) object_dirs = os.path.split(self._obj)[0] self._logger.debug("object_dirs: %s" % repr(object_dirs)) self._logger.debug("data_dir: %s" % self._put_datadir) hpss_utils.makedirs(os.path.join(self._put_datadir, object_dirs)) data_file = os.path.join(self._put_datadir, self._obj) # Create the temporary file attempts = 1 while True: tmpfile = '.%s.%s.temporary' % (self._obj, random.randint(0, 65536)) tmppath = os.path.join(self._put_datadir, tmpfile) self._logger.debug("DiskFile: Creating temporary file %s" % tmppath) try: # TODO: figure out how to create hints struct self._logger.debug("DiskFile: creating file") fd = do_open(tmppath, hpss.O_WRONLY | hpss.O_CREAT | hpss.O_EXCL) self._logger.debug("DiskFile: setting COS") if hpss_hints['cos']: hpss_utils.set_cos(tmppath, int(hpss_hints['cos'])) except SwiftOnFileSystemOSError as gerr: if gerr.errno in (errno.ENOSPC, errno.EDQUOT): # Raise DiskFileNoSpace to be handled by upper layers when # there is no space on disk OR when quota is exceeded self._logger.error("DiskFile: no space") raise DiskFileNoSpace() if gerr.errno == errno.EACCES: self._logger.error("DiskFile: permission denied") raise DiskFileNoSpace() if gerr.errno == errno.ENOTDIR: self._logger.error("DiskFile: not a directory") raise AlreadyExistsAsFile('do_open(): failed on %s,' ' path or part of a' ' path is not a directory' % data_file) if gerr.errno not in (errno.ENOENT, errno.EEXIST, errno.EIO): # FIXME: Other cases we should handle? self._logger.error("DiskFile: unknown error %s" % gerr.errno) raise if attempts >= MAX_OPEN_ATTEMPTS: # We failed after N attempts to create the temporary # file. raise DiskFileError('DiskFile.mkstemp(): failed to' ' successfully create a temporary file' ' without running into a name conflict' ' after %d of %d attempts for: %s' % ( attempts, MAX_OPEN_ATTEMPTS, data_file)) if gerr.errno == errno.EEXIST: self._logger.debug("DiskFile: file exists already") # Retry with a different random number. attempts += 1 else: break dw = None self._logger.debug("DiskFile: created file") try: # Ensure it is properly owned before we make it available. do_chown(tmppath, self._uid, self._gid) dw = DiskFileWriter(fd, tmppath, self) yield dw finally: if dw: dw.close() if dw._tmppath: do_unlink(dw._tmppath)