Example #1
0
    def commit(self, mergeFn=None):

        if self._status & RepositoryView.COMMITTING == 0:
            try:
                self._exclusive.acquire()
                self._status |= RepositoryView.COMMITTING
                
                store = self.repository.store
                before = time()

                size = 0L
                txnStatus = 0
                lock = None

                def finish(lock, txnStatus, commit):
                    if commit:
                        self._commitTransaction(txnStatus)
                    else:
                        self._abortTransaction(txnStatus)
                    if lock is not None:
                        lock = store.releaseLock(lock)
                    return lock, 0
        
                notifications = RepositoryNotifications()

                while True:
                    try:
                        while True:
                            self.refresh(mergeFn)
                            lock = store.acquireLock()
                            newVersion = store.getVersion()
                            if newVersion > self._version:
                                lock = store.releaseLock(lock)
                            else:
                                break

                        count = len(self._log) + len(self._deletedRegistry)
                        if count > 1000:
                            self.logger.info('%s committing %d items...',
                                             self, count)

                        txnStatus = self._startTransaction()

                        if count > 0:
                            newVersion += 1
                            store._values.setVersion(newVersion)
                            itemWriter = DBItemWriter(store)
                            for item in self._log:
                                size += self._saveItem(item, newVersion,
                                                       itemWriter,
                                                       notifications)
                            for item in self._deletedRegistry.itervalues():
                                size += self._saveItem(item, newVersion,
                                                       itemWriter,
                                                       notifications)
                            if self.isDirty():
                                size += self._roots._saveValues(newVersion)

                        lock, txnStatus = finish(lock, txnStatus, True)
                        break

                    except DBLockDeadlockError:
                        self.logger.info('retrying commit aborted by deadlock')
                        lock, txnStatus = finish(lock, txnStatus, False)
                        continue

                    except:
                        if txnStatus:
                            self.logger.exception('aborting transaction (%d kb)', size >> 10)
                        lock, txnStatus = finish(lock, txnStatus, False)
                        raise

                self._version = newVersion
                
                if self._log:
                    for item in self._log:
                        item._version = newVersion
                        item.setDirty(0, None)
                        item._status &= ~(Item.NEW | Item.MERGED)
                    self._log.clear()

                    if self.isDirty():
                        self._roots._clearDirties()
                        self.setDirty(0)

                if self._deletedRegistry:
                    self._deletedRegistry.clear()

                after = time()

                if count > 0:
                    duration = after - before
                    try:
                        iSpeed = "%d items/s" % round(count / duration)
                        dSpeed = "%d kbytes/s" % round((size >> 10) / duration)
                    except ZeroDivisionError:
                        iSpeed = dSpeed = 'speed could not be measured'

                    self.logger.info('%s committed %d items (%d kbytes) in %s, %s (%s)', self, count, size >> 10, timedelta(seconds=duration), iSpeed, dSpeed)

                if len(notifications) > 0:
                    notifications.dispatchHistory(self)

            finally:
                self._status &= ~RepositoryView.COMMITTING
                self._exclusive.release()
Example #2
0
    def refresh(self, mergeFn=None, version=None):

        store = self.repository.store
        newVersion = version or store.getVersion()
        
        if newVersion > self._version:
            histNotifications = RepositoryNotifications()

            unloads = {}
            also = set()
            _log = self._log

            try:
                self._log = set()
                try:
                    self._mergeItems(self._version, newVersion,
                                     histNotifications, unloads, also, mergeFn)
                except:
                    for item in self._log:
                        item.setDirty(0)
                        item._unloadItem(True, self)
                    raise
                else:
                    # unload items unchanged until changed by merging
                    for item in self._log:
                        item.setDirty(0)
                        unloads[item._uuid] = item
            finally:
                self._log = _log

            # unload items changed only in the other view whose older version
            # got loaded as a side-effect of merging
            for uuid in also:
                item = self.find(uuid, False)
                if item is not None:
                    unloads[uuid] = item
                    
            self.logger.debug('refreshing view from version %d to %d',
                              self._version, newVersion)
            self._version = newVersion

            refCounted = self.isRefCounted()
            for item in unloads.itervalues():
                self.logger.debug('unloading version %d of %s',
                                  item._version, item)
                item._unloadItem(refCounted or item.isPinned(), self)
            for item in unloads.itervalues():
                if refCounted or item.isPinned():
                    self.logger.debug('reloading version %d of %s',
                                      newVersion, item)
                    self.find(item._uuid)

            before = time()
            count = len(histNotifications)
            histNotifications.dispatchHistory(self)
            duration = time() - before
            if duration > 1.0:
                self.logger.warning('%s %d notifications ran in %s',
                                    self, count, timedelta(seconds=duration))

            self.prune(10000)

        elif newVersion < self._version:
            self.cancel()
            for item in [item for item in self._registry.itervalues()
                         if item._version > newVersion]:
                item._unloadItem(True, self)
            self._version = newVersion