Exemplo n.º 1
0
    def test_mlocking(self):
        self.thisHostMust(hasmemlocking=True)
        with self.getTestDir() as dirn:
            fsize = 8 * 1024
            fn = pathlib.Path(dirn) / 'mapfile'
            with open(fn, 'wb') as f:
                f.write(b'x' * fsize)
                f.flush()
            with open(fn, 'r+b') as f:
                with s_thisplat.mmap(0, fsize, 0x1, 0x8001, f.fileno(), 0):
                    addr, size = s_thisplat.getFileMappedRegion(fn)
                    self.ne(addr, 0)
                    self.eq(size, fsize)
                    beforelock = s_thisplat.getCurrentLockedMemory()
                    maxlocked = s_thisplat.getMaxLockedMemory()
                    self.ge(maxlocked, beforelock)
                    self.ge(s_thisplat.getTotalMemory(), beforelock)
                    self.ge(s_thisplat.getAvailableMemory(), beforelock)
                    s_thisplat.mlock(addr, size)
                    locktotal = s_thisplat.getCurrentLockedMemory()
                    self.ge(locktotal, size)
                    self.ge(locktotal, beforelock)
                    maxlocked = s_thisplat.getMaxLockedMemory()
                    self.ge(maxlocked, locktotal)
                    s_thisplat.munlock(addr, size)
                    locktotal = s_thisplat.getCurrentLockedMemory()
                    self.eq(locktotal, beforelock)

                    # Make sure we get the largest mapped region
                    with s_thisplat.mmap(0, int(fsize / 2), 0x1, 0x8001, f.fileno(), 0):
                        addr, size = s_thisplat.getFileMappedRegion(fn)
                        self.eq(size, fsize)

            # Sad tests
            bfn = pathlib.Path(dirn) / 'mapfile.newp'
            self.raises(s_exc.NoSuchFile, s_thisplat.getFileMappedRegion, bfn)

        # Sad tests
        with self.raises(OSError) as cm:
            s_thisplat.mlock(0x01, 16)
        # Cannot allocate memory to lock
        self.eq(cm.exception.errno, 12)

        with self.raises(OSError) as cm:
            s_thisplat.munlock(0xFF, 16)
        # Cannot allocate memory to unlock
        self.eq(cm.exception.errno, 12)
Exemplo n.º 2
0
    def _memorylockloop(self):
        '''
        Separate thread loop that manages the prefaulting and locking of the memory backing the data file
        '''
        if not s_thishost.get('hasmemlocking'):
            return
        MAX_TOTAL_PERCENT = .90  # how much of all the RAM to take
        MAX_LOCK_AT_ONCE = s_const.gibibyte

        # Calculate a reasonable maximum amount of memory to lock

        s_thisplat.maximizeMaxLockedMemory()
        locked_ulimit = s_thisplat.getMaxLockedMemory()
        if locked_ulimit < s_const.gibibyte // 2:
            logger.warning(
                'Operating system limit of maximum amount of locked memory (currently %d) is \n'
                'too low for optimal performance.', locked_ulimit)

        logger.debug('memory locking thread started')

        # Note:  available might be larger than max_total in a container
        max_total = s_thisplat.getTotalMemory()
        available = s_thisplat.getAvailableMemory()

        PAGESIZE = 4096
        max_to_lock = (min(locked_ulimit, int(max_total * MAX_TOTAL_PERCENT),
                           int(available * MAX_TOTAL_PERCENT)) //
                       PAGESIZE) * PAGESIZE

        self.max_could_lock = max_to_lock

        path = self.path.absolute(
        ) / 'data.mdb'  # Path to the file that gets mapped
        fh = open(path, 'r+b')
        fileno = fh.fileno()

        prev_memend = 0  # The last end of the file mapping, so we can start from there

        # Avoid spamming messages
        first_end = True
        limit_warned = False
        self.locking_memory = True

        self.resizeevent.set()

        while not self.isfini:

            self.resizeevent.wait()
            if self.isfini:
                break

            self.schedCallSafe(self.lockdoneevent.clear)
            self.resizeevent.clear()

            try:
                memstart, memlen = s_thisplat.getFileMappedRegion(path)
            except s_exc.NoSuchFile:
                logger.warning('map not found for %s', path)

                if not self.resizeevent.is_set():
                    self.schedCallSafe(self.lockdoneevent.set)
                continue

            if memlen > max_to_lock:
                memlen = max_to_lock
                if not limit_warned:
                    logger.warning('memory locking limit reached')
                    limit_warned = True
                # Even in the event that we've hit our limit we still have to loop because further mmaps may cause
                # the base address to change, necessitating relocking what we can

            # The file might be a little bit smaller than the map because rounding (and mmap fails if you give it a
            # too-long length)
            filesize = os.fstat(fileno).st_size
            goal_end = memstart + min(memlen, filesize)
            self.lock_goal = goal_end - memstart

            self.lock_progress = 0
            prev_memend = memstart

            # Actually do the prefaulting and locking.  Only do it a chunk at a time to maintain responsiveness.
            while prev_memend < goal_end:
                new_memend = min(prev_memend + MAX_LOCK_AT_ONCE, goal_end)
                memlen = new_memend - prev_memend
                PROT = 1  # PROT_READ
                FLAGS = 0x8001  # MAP_POPULATE | MAP_SHARED (Linux only)  (for fast prefaulting)
                try:
                    self.prefaulting = True
                    with s_thisplat.mmap(0,
                                         length=new_memend - prev_memend,
                                         prot=PROT,
                                         flags=FLAGS,
                                         fd=fileno,
                                         offset=prev_memend - memstart):
                        s_thisplat.mlock(prev_memend, memlen)
                except OSError as e:
                    logger.warning(
                        'error while attempting to lock memory of %s: %s',
                        path, e)
                    break
                finally:
                    self.prefaulting = False

                prev_memend = new_memend
                self.lock_progress = prev_memend - memstart

            if first_end:
                first_end = False
                logger.info('completed prefaulting and locking slab')

            if not self.resizeevent.is_set():
                self.schedCallSafe(self.lockdoneevent.set)

        self.locking_memory = False
        logger.debug('memory locking thread ended')