Exemple #1
0
def non_leaf_coalesce(node, parent, uri, callbacks):
    """
    Perform non-leaf (mid tree) volume coalesce
    """
    node_volume = node.volume
    parent_volume = parent.volume

    log.debug("non_leaf_coalesce key={}, parent={}".format(
        node_volume.id, parent_volume.id))

    with VolumeContext(callbacks, uri, 'w') as opq:
        node_path = callbacks.volumeGetPath(opq, str(node_volume.id))
        parent_path = callbacks.volumeGetPath(opq, str(parent_volume.id))
        log.debug("Running cow-coalesce on {}".format(node_volume.id))
        image_utils = ImageFormat.get_format(
            node_volume.image_type).image_utils
        image_utils.coalesce(GC, node_path, parent_path)

        with PollLock(opq, 'gl', callbacks, PRIO_GC):
            with callbacks.db_context(opq) as db:
                # reparent all of the children to this node's parent
                children = db.get_children(node_volume.id)
                journal_entries = db.add_journal_entries(
                    node_volume.id, parent_volume.id, children)

            __reparent_children(opq, callbacks, journal_entries)

            callbacks.volumeUnlock(opq, node.lock)
            callbacks.volumeUnlock(opq, parent.lock)
Exemple #2
0
 def stop():
     with VolumeContext(callbacks, uri, 'w') as opq:
         path = os.path.join(util.var_run_prefix(), 'sr',
                             callbacks.getUniqueIdentifier(opq),
                             name + '_task.pickle')
         with open(path) as f:
             process = pickle.load(f)
         process.kill()
         process.wait()
         os.unlink(path)
Exemple #3
0
    def create(self, dbg, sr, name, description, size, sharable):
        devices = util.get_sr_metadata(dbg, 'file://' + sr)['devices']
        devices = map(lambda x: os.path.normpath(x), devices)

        with VolumeContext(self.callbacks, sr, 'w') as opq:
            image_type = ImageFormat.IMAGE_RAW
            image_format = ImageFormat.get_format(image_type)
            vdi_uuid = str(uuid.uuid4())

            with PollLock(opq, 'gl', self.callbacks, 0.5):
                with self.callbacks.db_context(opq) as db:
                    # List all used devices.
                    used_devices = map(
                        lambda x: os.path.realpath(
                            self.callbacks.volumeGetPath(opq, str(x.id))),
                        db.get_all_volumes())

                    # Find first free device with the best size.
                    free_device = None
                    psize = sys.maxint
                    for device in devices:
                        if os.path.realpath(device) not in used_devices:
                            device_size = util.get_physical_file_size(device)
                            if device_size >= size and device_size < psize:
                                free_device = device
                                psize = device_size

                    if not free_device:
                        # TODO: Maybe find a better exception.
                        raise ValueError('No free device found in config')

                    volume = db.insert_new_volume(psize, image_type)
                    db.insert_vdi(name, description, vdi_uuid, volume.id,
                                  sharable)
                    volume_path = self.callbacks.volumeGetPath(
                        opq, str(volume.id))
            os.symlink(free_device, volume_path)

            vdi_uri = self.callbacks.getVolumeUriPrefix(opq) + vdi_uuid

        return {
            'key': vdi_uuid,
            'uuid': vdi_uuid,
            'name': name,
            'description': description,
            'read_write': True,
            'virtual_size': psize,
            'physical_utilisation': psize,
            'uri': [image_format.uri_prefix + vdi_uri],
            'sharable': sharable,
            'keys': {}
        }
Exemple #4
0
def start_task(dbg_msg, uri, callbacks, name, args):
    with VolumeContext(callbacks, uri, 'w') as opq:
        task = subprocess.Popen(args)
        log.debug(dbg_msg)
        path = os.path.join(util.var_run_prefix(), 'sr',
                            callbacks.getUniqueIdentifier(opq))
        try:
            os.makedirs(path)
        except OSError:
            pass
        path = os.path.join(path, name + '_task.pickle')
        with open(path, 'w+') as f:
            pickle.dump(task, f)
Exemple #5
0
def remove_garbage_volumes(uri, callbacks):
    """
    Find any unreferenced, garbage COW nodes and remove
    """
    with VolumeContext(callbacks, uri, 'w') as opq:
        with PollLock(opq, 'gl', callbacks, PRIO_GC):
            with callbacks.db_context(opq) as db:
                garbage = db.get_garbage_volumes()

            if len(garbage) > 0:
                for volume in garbage:
                    callbacks.volumeDestroy(opq, str(volume.id))
                    with callbacks.db_context(opq) as db:
                        db.delete_volume(volume.id)
Exemple #6
0
def _find_best_non_leaf_coalesceable(uri, callbacks):
    """
    Find the next pair of COW nodes to be coalesced
    """
    with VolumeContext(callbacks, uri, 'w') as opq:
        ret = (None, None)
        with PollLock(opq, 'gl', callbacks, PRIO_GC):
            with callbacks.db_context(opq) as db:
                nodes = __find_non_leaf_coalesceable(db)
                for node in nodes:
                    ret = __lock_node_pair(node, opq, db, callbacks)
                    if ret != (None, None):
                        break
    return ret
Exemple #7
0
def _find_best_leaf_coalesceable(this_host, uri, callbacks):
    """
    Find the next pair of COW nodes to be leaf coalesced
    """
    with VolumeContext(callbacks, uri, 'w') as opq:
        with PollLock(opq, 'gl', callbacks, PRIO_GC):
            with callbacks.db_context(opq) as db:
                nodes = __find_leaf_coalesceable(this_host, db)
            for node in nodes:
                # Temp: no leaf on qcow2 for now
                if node.image_type == ImageFormat.IMAGE_QCOW2:
                    continue
                with callbacks.db_context(opq) as db:
                    leaf, parent = __lock_node_pair(node, opq, db, callbacks)
                if (leaf, parent) != (None, None):
                    __leaf_coalesce(leaf, parent, opq, callbacks)
                    return True
    return False
Exemple #8
0
    def start_gc(dbg, sr_type, uri):
        # Ensure trash directory exists before starting GC.
        callbacks = util.get_sr_callbacks(sr_type)
        with VolumeContext(callbacks, uri, 'w') as opq:
            callbacks.create_trash_dir(opq)

        if gc_is_enabled(uri, callbacks):
            # Get the command to run, need to replace pyc with py as __file__
            # will be the byte compiled file.
            dbg_msg = "{}: Starting GC sr_type={} uri={}".format(
                dbg, sr_type, uri)
            args = [
                os.path.abspath(re.sub("pyc$", "py", __file__)), sr_type, uri
            ]
            start_task(dbg_msg, uri, callbacks, "gc", args)
        else:
            log.debug('GC is disabled, cannot start it')
        start_background_tasks(dbg, sr_type, uri, callbacks)
Exemple #9
0
def recover_journal(uri, this_host, callbacks):
    """
    Complete recover operations started in a different instance
    """
    with VolumeContext(callbacks, uri, 'w') as opq:
        # Take the global SR lock, the coaleasce reparenting happens within
        # this lock, so if we can get it and if there are any pending
        # operations then a different process crashed or was aborted and we
        # need to complete the outstanding operations
        with PollLock(opq, 'gl', callbacks, PRIO_GC):
            with callbacks.db_context(opq) as db:
                # Get the journalled reparent operations
                journal_entries = db.get_journal_entries()
            __reparent_children(opq, callbacks, journal_entries)

            # Now refresh any leaves
            with callbacks.db_context(opq) as db:
                refresh_entries = db.get_refresh_entries(this_host)
            __refresh_leaf_vdis(opq, callbacks, refresh_entries)
Exemple #10
0
def gc_is_enabled(uri, callbacks):
    with VolumeContext(callbacks, uri, 'w') as opq:
        return not os.path.exists(
            os.path.join('/var/lib/sr', callbacks.getUniqueIdentifier(opq),
                         'gc_disabled'))