diff options
Diffstat (limited to 'swift/1.4.8/plugins/DiskFile.py')
| -rw-r--r-- | swift/1.4.8/plugins/DiskFile.py | 296 | 
1 files changed, 296 insertions, 0 deletions
diff --git a/swift/1.4.8/plugins/DiskFile.py b/swift/1.4.8/plugins/DiskFile.py new file mode 100644 index 00000000000..815e1c3ab54 --- /dev/null +++ b/swift/1.4.8/plugins/DiskFile.py @@ -0,0 +1,296 @@ +# Copyright (c) 2011 Red Hat, Inc. +# +# Licensed 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. + +import os +from eventlet import tpool +from swift.common.utils import normalize_timestamp, renamer +from swift.plugins.utils import mkdirs, rmdirs, validate_object, \ +    check_valid_account, create_object_metadata,  do_open, \ +    do_close, do_unlink, do_chown, do_stat, do_listdir, read_metadata,\ +    write_metadata +from swift.common.constraints import  check_mount +from swift.plugins.utils import X_CONTENT_TYPE, X_CONTENT_LENGTH, X_TIMESTAMP,\ +     X_PUT_TIMESTAMP, X_TYPE, X_ETAG, X_OBJECTS_COUNT, X_BYTES_USED, \ +     X_OBJECT_TYPE, FILE, DIR, MARKER_DIR, OBJECT, \ +     DIR_TYPE, FILE_TYPE, DEFAULT_UID, DEFAULT_GID + +import logging +from swift.obj.server import DiskFile + + +DATADIR = 'objects' +ASYNCDIR = 'async_pending' +KEEP_CACHE_SIZE = (5 * 1024 * 1024) +# keep these lower-case +DISALLOWED_HEADERS = set('content-length content-type deleted etag'.split()) + + +class Gluster_DiskFile(DiskFile): +    """ +    Manage object files on disk. + +    :param path: path to devices on the node/mount path for UFO. +    :param device: device name/account_name for UFO. +    :param partition: partition on the device the object lives in +    :param account: account name for the object +    :param container: container name for the object +    :param obj: object name for the object +    :param keep_data_fp: if True, don't close the fp, otherwise close it +    :param disk_chunk_Size: size of chunks on file reads +    """ + +    def __init__(self, path, device, partition, account, container, obj, +                 logger, keep_data_fp=False, disk_chunk_size=65536, +                 uid=DEFAULT_UID, gid=DEFAULT_GID, fs_object = None): +        self.disk_chunk_size = disk_chunk_size +        device = account +        #Don't support obj_name ending/begining with '/', like /a, a/, /a/b/ etc +        obj = obj.strip('/') +        if '/' in obj: +            self.obj_path, self.obj = obj.rsplit('/', 1) +        else: +            self.obj_path = '' +            self.obj = obj + +        if self.obj_path: +            self.name = '/'.join((container, self.obj_path)) +        else: +            self.name = container +        #Absolute path for obj directory. +        self.datadir = os.path.join(path, device, self.name) + +        self.device_path = os.path.join(path, device) +        if not check_mount(path, device): +            check_valid_account(account, fs_object) + +        self.container_path = os.path.join(path, device, container) +        self.tmpdir = os.path.join(path, device, 'tmp') +        self.logger = logger +        self.metadata = {} +        self.meta_file = None +        self.data_file = None +        self.fp = None +        self.iter_etag = None +        self.started_at_0 = False +        self.read_to_eof = False +        self.quarantined_dir = None +        self.keep_cache = False +        self.is_dir = False +        self.is_valid = True +        self.uid = int(uid) +        self.gid = int(gid) +        if not os.path.exists(self.datadir + '/' + self.obj): +            return + +        self.data_file = os.path.join(self.datadir, self.obj) +        self.metadata = read_metadata(self.datadir + '/' + self.obj) +        if not self.metadata: +            create_object_metadata(self.datadir + '/' + self.obj) +            self.metadata = read_metadata(self.datadir + '/' + self.obj) + +        if not validate_object(self.metadata): +            create_object_metadata(self.datadir + '/' + self.obj) +            self.metadata = read_metadata(self.datadir + '/' + +                                        self.obj) + +        self.filter_metadata() + +        if os.path.isdir(self.datadir + '/' + self.obj): +            self.is_dir = True +        else: +            self.fp = do_open(self.data_file, 'rb') +            if not keep_data_fp: +                self.close(verify_file=False) + +    def close(self, verify_file=True): +        """ +        Close the file. Will handle quarantining file if necessary. + +        :param verify_file: Defaults to True. If false, will not check +                            file to see if it needs quarantining. +        """ +        #Marker directory +        if self.is_dir: +            return +        if self.fp: +            do_close(self.fp) +            self.fp = None + +    def is_deleted(self): +        """ +        Check if the file is deleted. + +        :returns: True if the file doesn't exist or has been flagged as +                  deleted. +        """ +        return not self.data_file + +    def create_dir_object(self, dir_path): +        #TODO: if object already exists??? +        if os.path.exists(dir_path) and not os.path.isdir(dir_path): +            self.logger.error("Deleting file %s", dir_path) +            do_unlink(dir_path) +        #If dir aleady exist just override metadata. +        mkdirs(dir_path) +        do_chown(dir_path, self.uid, self.gid) +        create_object_metadata(dir_path) +        return True + + + +    def put_metadata(self, metadata): +        obj_path = self.datadir + '/' + self.obj +        write_metadata(obj_path, metadata) +        self.metadata = metadata + + +    def put(self, fd, tmppath, metadata, extension=''): +        """ +        Finalize writing the file on disk, and renames it from the temp file to +        the real location.  This should be called after the data has been +        written to the temp file. + +        :params fd: file descriptor of the temp file +        :param tmppath: path to the temporary file being used +        :param metadata: dictionary of metadata to be written +        :param extention: extension to be used when making the file +        """ +        #Marker dir. +        if extension == '.ts': +            return True +        if extension == '.meta': +            self.put_metadata(metadata) +            return True +        else: +            extension = '' +        if metadata[X_OBJECT_TYPE] == MARKER_DIR: +            self.create_dir_object(os.path.join(self.datadir, self.obj)) +            self.put_metadata(metadata) +            self.data_file = self.datadir + '/' + self.obj +            return True +        #Check if directory already exists. +        if self.is_dir: +            self.logger.error('Directory already exists %s/%s' % \ +                          (self.datadir , self.obj)) +            return False +        #metadata['name'] = self.name +        timestamp = normalize_timestamp(metadata[X_TIMESTAMP]) +        write_metadata(tmppath, metadata) +        if X_CONTENT_LENGTH in metadata: +            self.drop_cache(fd, 0, int(metadata[X_CONTENT_LENGTH])) +        tpool.execute(os.fsync, fd) +        if self.obj_path: +            dir_objs = self.obj_path.split('/') +            tmp_path = '' +            if len(dir_objs): +                for dir_name in dir_objs: +                    if tmp_path: +                        tmp_path = tmp_path + '/' + dir_name +                    else: +                        tmp_path = dir_name +                    if not self.create_dir_object(os.path.join(self.container_path, +                            tmp_path)): +                        self.logger.error("Failed in subdir %s",\ +                                        os.path.join(self.container_path,tmp_path)) +                        return False + +        renamer(tmppath, os.path.join(self.datadir, +                                      self.obj + extension)) +        do_chown(os.path.join(self.datadir, self.obj + extension), \ +              self.uid, self.gid) +        self.metadata = metadata +        #self.logger.error("Meta %s", self.metadata) +        self.data_file = self.datadir + '/' + self.obj + extension +        return True + + +    def unlinkold(self, timestamp): +        """ +        Remove any older versions of the object file.  Any file that has an +        older timestamp than timestamp will be deleted. + +        :param timestamp: timestamp to compare with each file +        """ +        if self.metadata and self.metadata['X-Timestamp'] != timestamp: +            self.unlink() + +    def unlink(self): +        """ +        Remove the file. +        """ +        #Marker dir. +        if self.is_dir: +            rmdirs(os.path.join(self.datadir, self.obj)) +            if not os.path.isdir(os.path.join(self.datadir, self.obj)): +                self.metadata = {} +                self.data_file = None +            else: +                logging.error('Unable to delete dir %s' % os.path.join(self.datadir, self.obj)) +            return + +        for fname in do_listdir(self.datadir): +            if fname == self.obj: +                try: +                    do_unlink(os.path.join(self.datadir, fname)) +                except OSError, err: +                    if err.errno != errno.ENOENT: +                        raise + +        #Remove entire path for object. +        #remove_dir_path(self.obj_path, self.container_path) + +        self.metadata = {} +        self.data_file = None + +    def get_data_file_size(self): +        """ +        Returns the os.path.getsize for the file.  Raises an exception if this +        file does not match the Content-Length stored in the metadata. Or if +        self.data_file does not exist. + +        :returns: file size as an int +        :raises DiskFileError: on file size mismatch. +        :raises DiskFileNotExist: on file not existing (including deleted) +        """ +        #Marker directory. +        if self.is_dir: +            return 0 +        try: +            file_size = 0 +            if self.data_file: +                file_size = os.path.getsize(self.data_file) +                if  X_CONTENT_LENGTH in self.metadata: +                    metadata_size = int(self.metadata[X_CONTENT_LENGTH]) +                    if file_size != metadata_size: +                        self.metadata[X_CONTENT_LENGTH] = file_size +                        self.update_object(self.metadata) + +                return file_size +        except OSError, err: +            if err.errno != errno.ENOENT: +                raise +        raise DiskFileNotExist('Data File does not exist.') + +    def update_object(self, metadata): +        obj_path = self.datadir + '/' + self.obj +        write_metadata(obj_path, metadata) +        self.metadata = metadata + +    def filter_metadata(self): +        if X_TYPE in self.metadata: +            self.metadata.pop(X_TYPE) +        if X_OBJECT_TYPE in self.metadata: +            self.metadata.pop(X_OBJECT_TYPE) +  | 
