Example #1
0
    def _getOpenHdf5Blockfile(self, blockFilePath):
        """
        Return a handle to the open hdf5File at the given path.
        If we haven't opened the file yet, open it first.
        """
        # Try once without locking
        if blockFilePath in list(self._openBlockFiles.keys()):
            return self._openBlockFiles[blockFilePath]

        # Obtain the lock and try again
        with self._lock:
            if blockFilePath not in list(self._openBlockFiles.keys()):
                try:
                    writeLock = FileLock(blockFilePath, timeout=10)
                    if self.mode == "a":
                        acquired = writeLock.acquire(blocking=False)
                        assert acquired, "Couldn't obtain an exclusive lock for writing to file: {}".format(
                            blockFilePath
                        )
                        self._fileLocks[blockFilePath] = writeLock
                    elif self.mode == "r":
                        assert writeLock.available(), "Can't read from a file that is being written to elsewhere."
                    else:
                        assert False, "Unsupported mode"
                    self._openBlockFiles[blockFilePath] = h5py.File(blockFilePath, self.mode)
                except:
                    log_exception(logger, "Couldn't open {}".format(blockFilePath))
                    raise
            return self._openBlockFiles[blockFilePath]
 def _downloadFromQueue(self, num_blocks, blockQueue, failedBlockQueue):
     """
     Helper function for downloadAllBlocks(), above.
     """
     try:
         while not blockQueue.empty():
             block_start = blockQueue.get(block=False)
             entire_block_roi = self.getEntireBlockRoi(block_start) # Roi of this whole block within the whole dataset
             blockFilePathComponents = self.getDatasetPathComponents( block_start )
             
             # Obtain lock
             fileLock = FileLock( blockFilePathComponents.externalPath )
             if not fileLock.acquire(False):
                 failedBlockQueue.put( block_start )
             else:
                 try:
                     # Download the block
                     # (This function releases the lock for us.)
                     self._downloadBlock(fileLock, entire_block_roi, blockFilePathComponents)
                     logger.debug( "Finished downloading {}/{}".format( num_blocks-blockQueue.qsize(), num_blocks ) )
                 except:
                     if fileLock.locked():
                         fileLock.release()
                         self.setBlockStatus(entire_block_roi[0], BlockwiseFileset.BLOCK_NOT_AVAILABLE)
                     failedBlockQueue.put( block_start )
                     raise
     except Queue.Empty:
         return
Example #3
0
    def _waitForBlocks(self, block_starts):
        """
        Initiate downloads for those blocks that need it.
        (Some blocks in the list may already be downloading.)
        Then wait for all necessary downloads to complete (including the ones that we didn't initiate).
        """
        # Only wait for those that are missing.
        missing_blocks = []
        for block_start in block_starts:
            if self.getBlockStatus(
                    block_start) == BlockwiseFileset.BLOCK_NOT_AVAILABLE:
                missing_blocks.append(block_start)

        # Start by creating all necessary directories.
        self._ensureDirectoriesExist(missing_blocks)

        # Attempt to lock each path we need to create.
        # Locks we fail to obtain are already being fetched by other processes, which is okay.
        acquired_locks = []
        unobtained_locks = []
        for block_start in missing_blocks:
            entire_block_roi = self.getEntireBlockRoi(
                block_start
            )  # Roi of this whole block within the whole dataset
            blockFilePathComponents = self.getDatasetPathComponents(
                block_start)

            fileLock = FileLock(blockFilePathComponents.externalPath)
            if fileLock.acquire(False):
                acquired_locks.append((entire_block_roi, fileLock))
            else:
                unobtained_locks.append((entire_block_roi, fileLock))

        # We are now responsible for downloading the data for the file paths we were able to lock.
        # Start a separate thread for each.
        downloadThreads = []
        for block_roi, fileLock in acquired_locks:
            blockFilePathComponents = self.getDatasetPathComponents(
                block_roi[0])
            th = threading.Thread(
                target=functools.partial(self._downloadBlock, fileLock,
                                         block_roi, blockFilePathComponents))
            downloadThreads.append(th)

        # Start all the threads
        for th in downloadThreads:
            th.start()

        # Wait for them all to complete
        for th in downloadThreads:
            th.join()

        # Finally, wait for the blocks that we COULDN'T lock (they must be downloading in other processes somewhere...)
        for block_roi, fileLock in unobtained_locks:
            while self.getBlockStatus(
                    block_roi[0]) == BlockwiseFileset.BLOCK_NOT_AVAILABLE:
                time.sleep(5)
Example #4
0
 def isBlockLocked(self, blockstart):
     """
     Return True if the block is locked for writing.
     Note that both 'available' and 'not available' blocks might be locked.
     """
     datasetPathComponents = self.getDatasetPathComponents(blockstart)
     hdf5FilePath = datasetPathComponents.externalPath
     testLock = FileLock(hdf5FilePath)
     return not testLock.available()
    def _waitForBlocks(self, block_starts):
        """
        Initiate downloads for those blocks that need it.
        (Some blocks in the list may already be downloading.)
        Then wait for all necessary downloads to complete (including the ones that we didn't initiate).
        """
        # Only wait for those that are missing.
        missing_blocks = []
        for block_start in block_starts:
            if self.getBlockStatus(block_start) == BlockwiseFileset.BLOCK_NOT_AVAILABLE:
                missing_blocks.append(block_start)

        # Start by creating all necessary directories.
        self._ensureDirectoriesExist(missing_blocks)

        # Attempt to lock each path we need to create.
        # Locks we fail to obtain are already being fetched by other processes, which is okay.
        acquired_locks = []
        unobtained_locks = []
        for block_start in missing_blocks:
            entire_block_roi = self.getEntireBlockRoi(block_start)  # Roi of this whole block within the whole dataset
            blockFilePathComponents = self.getDatasetPathComponents(block_start)

            fileLock = FileLock(blockFilePathComponents.externalPath)
            if fileLock.acquire(False):
                acquired_locks.append((entire_block_roi, fileLock))
            else:
                unobtained_locks.append((entire_block_roi, fileLock))

        # We are now responsible for downloading the data for the file paths we were able to lock.
        # Start a separate thread for each.
        downloadThreads = []
        for block_roi, fileLock in acquired_locks:
            blockFilePathComponents = self.getDatasetPathComponents(block_roi[0])
            th = threading.Thread(
                target=functools.partial(self._downloadBlock, fileLock, block_roi, blockFilePathComponents)
            )
            downloadThreads.append(th)

        # Start all the threads
        for th in downloadThreads:
            th.start()

        # Wait for them all to complete
        for th in downloadThreads:
            th.join()

        # Finally, wait for the blocks that we COULDN'T lock (they must be downloading in other processes somewhere...)
        for block_roi, fileLock in unobtained_locks:
            while self.getBlockStatus(block_roi[0]) == BlockwiseFileset.BLOCK_NOT_AVAILABLE:
                time.sleep(5)
Example #6
0
    def purgeAllLocks(self):
        """
        Clears all .lock files from the local blockwise fileset.
        This may be necessary if previous processes crashed or were killed while some blocks were downloading.
        You must ensure that this is NOT called while more than one process (or thread) has access to the fileset.
        For example, in a master/worker situation, call this only from the master, before the workers have been started.
        """
        found_lock = False

        view_shape = self.description.view_shape
        view_roi = ([0] * len(view_shape), view_shape)
        block_starts = list(getIntersectingBlocks(self.description.block_shape, view_roi))
        for block_start in block_starts:
            blockFilePathComponents = self.getDatasetPathComponents(block_start)
            fileLock = FileLock(blockFilePathComponents.externalPath)
            found_lock |= fileLock.purge()
            if found_lock:
                logger.warning("Purged lock for block: {}".format(tuple(block_start)))

        return found_lock
Example #7
0
    def _downloadFromQueue(self, num_blocks, blockQueue, failedBlockQueue):
        """
        Helper function for downloadAllBlocks(), above.
        """
        try:
            while not blockQueue.empty():
                block_start = blockQueue.get(block=False)
                entire_block_roi = self.getEntireBlockRoi(
                    block_start
                )  # Roi of this whole block within the whole dataset
                blockFilePathComponents = self.getDatasetPathComponents(
                    block_start)

                # Obtain lock
                fileLock = FileLock(blockFilePathComponents.externalPath)
                if not fileLock.acquire(False):
                    failedBlockQueue.put(block_start)
                else:
                    try:
                        # Download the block
                        # (This function releases the lock for us.)
                        self._downloadBlock(fileLock, entire_block_roi,
                                            blockFilePathComponents)
                        logger.debug("Finished downloading {}/{}".format(
                            num_blocks - blockQueue.qsize(), num_blocks))
                    except:
                        if fileLock.locked():
                            fileLock.release()
                            self.setBlockStatus(
                                entire_block_roi[0],
                                BlockwiseFileset.BLOCK_NOT_AVAILABLE)
                        failedBlockQueue.put(block_start)
                        raise
        except Queue.Empty:
            return
Example #8
0
class OpColorizeLabels(Operator):
    name = "OpColorizeLabels"
    category = "display adaptor"
    
    Input = InputSlot()
    OverrideColors = InputSlot(stype='object', value={0 : (0,0,0,0)} )  # dict of { label : (R,G,B,A) }
                                                                        # By default, label 0 is black and transparent
    Output = OutputSlot() # 4 channels: RGBA

    colortable = None
    _lock = threading.Lock()
        
    def __init__(self, *args, **kwargs):
        super(OpColorizeLabels, self).__init__(*args, **kwargs)

        self.overrideColors = {}

        with OpColorizeLabels._lock:
            if OpColorizeLabels.colortable is None:
                OpColorizeLabels.colortable = OpColorizeLabels.generateColortable(2**22)

        # Pre-generate the table of data
        self.colortable = copy.copy(OpColorizeLabels.colortable)
        
    def setupOutputs(self):
        inputTags = self.Input.meta.axistags
        inputShape = self.Input.meta.shape
        self.channelIndex = inputTags.index('c')
        assert inputShape[self.channelIndex] == 1, "Input must be a single-channel label image"
                
        self.Output.meta.assignFrom(self.Input.meta)

        applyToChannel = partial(applyToElement, inputTags, 'c')
        self.Output.meta.shape = applyToChannel(inputShape, 4) # RGBA
        self.Output.meta.dtype = numpy.uint8
        self.Output.meta.drange = (0, 255)
        self.Output.meta.axistags["c"].description = "rgba"

        newOverrideColors = self.OverrideColors.value
        if newOverrideColors != self.overrideColors:
            # Add new overrides
            for label, color in newOverrideColors.items():
                if label not in self.overrideColors:
                    self.colortable[label] = color
            # Replace removed overrides with their original random values
            for label, color in self.overrideColors.items():
                if label not in newOverrideColors:
                    self.colortable[label] = OpColorizeLabels.colortable[label]

        self.overrideColors = newOverrideColors
    
    def setStartToZero(self,start,stop):
        start = [0]*len(start)
        stop = [end-begin for begin,end in zip(start,stop)]
        start = TinyVector(start)
        stop = TinyVector(stop)
        return start,stop
    
    def execute(self, slot, subindex, roi, result):
        fullKey = roi.toSlice()
        roiCopy = copy.copy(roi)
        roiCopy.start, roiCopy.stop = self.setStartToZero(roi.start, roi.stop)
        resultKey = roiCopy.toSlice()
        
        # Input has only one channel
        thinKey = applyToElement(self.Input.meta.axistags, 'c', fullKey, slice(0,1))
        inputData = self.Input[thinKey].wait()
        dropChannelKey = applyToElement(self.Input.meta.axistags, 'c', resultKey, 0)
        channellessInput = inputData[dropChannelKey]

        # Advanced indexing with colortable applies the relabeling from labels to colors.
        # If we get an error here, we may need to expand the colortable (currently supports only 2**22 labels.)
        channelSlice = getElement(self.Input.meta.axistags, 'c', fullKey)
        # channellessInput % self.colortable.shape[0]
        channellessInput &= self.colortable.shape[0]-1 # Cheaper than mod for 2**X
        result[...] = self.colortable[:, channelSlice][channellessInput]
        return result

    @staticmethod
    def generateColortable(size):
        lg = math.log(size, 2)
        # The execute function makes this assumption, so check it.
        assert lg == math.floor(lg), "Colortable size must be a power of 2."
        
        lazyflowSettingsDir = os.path.expanduser('~/.lazyflow')
        try:
            if not os.path.exists( lazyflowSettingsDir ):
                os.makedirs( lazyflowSettingsDir )
        except Exception, ex:
            import warnings
            warnings.warn("Not able to create dir: ~/.lazyflow.  Writing random_color_table.npy to /tmp instead.")
            # Write to a temporary directory.
            lazyflowSettingsDir = tempfile.mkdtemp()

        cachedColortablePath = os.path.join(lazyflowSettingsDir, 'random_color_table.npy')

        with FileLock(cachedColortablePath):
            # If possible, load the table from disk
            loadedTable = False
            if os.path.exists( cachedColortablePath ):
                try:
                    table = numpy.load(cachedColortablePath)
                    if table.shape[0] == size:
                        loadedTable = True
                    else:
                        table = None
                except: 
                    table = None
            
            if not loadedTable:
                randState = numpy.random.mtrand.RandomState(0)
                table = numpy.zeros((size,4), dtype=numpy.uint8)
                table[...] = randState.random_integers( 0, 255, table.shape )
                table[...,3] = 255 # Alpha is 255 by default.
    
                # Save it for next session
                saved = False
                ex = None
                try:
                    if not os.path.exists( lazyflowSettingsDir ):
                        os.makedirs( lazyflowSettingsDir )
                except Exception, ex:
                    pass
                else:
                    try:
                        numpy.save(cachedColortablePath, table)
                        saved = True
                    except Exception, ex:
                        pass
    
                if not saved:
                    # It's not worth crashing if the table can't be cached.
                    logger.warn( "Wasn't able to create cache file: " + cachedColortablePath )
                    logger.warn( "Caught exception: " + str(ex) )