Пример #1
0
class XidLruCache:
    PAGES_PER_SEGMENT = 32
    def __init__(self, datadir, pageclass, buffsz):
        self.datadir = datadir
        ctrlfile = ControlFile(datadir)
        self.blcksz = ctrlfile.blcksz
        self.buffer = LruCache(pageclass, self.blcksz, buffsz)
    
    def getfilename(self, segno):
        pass
        
    def readfromdisk(self, pageno):
        blocksz = self.blcksz
        segno = pageno / self.PAGES_PER_SEGMENT
        filename = self.getfilename(segno)
        try:
            with open(filename) as file:
                file.seek(blocksz * pageno)
                block = file.read(blocksz)
        except:
            raise UPgException('error in reading xid')
        if len(block) != blocksz:
            raise UPgException('error in reading xid')
        return block

    def getlrupage(self, pageno):
        lrupage = self.buffer.get_and_visit(pageno)
        if not lrupage:
            block = self.readfromdisk(pageno)
            lrupage = self.buffer.put(pageno, block)
        return lrupage    
Пример #2
0
class HeapBuffer:
    def __init__(self, pgdatadir, catalog_class):
        self.pgdatadir = pgdatadir
        self.catalog_class = catalog_class

        ctrlfile = ControlFile(pgdatadir)
        self.blocksz = ctrlfile.blcksz
        self.segfilesz = ctrlfile.relseg_size
        self.catalog_version_no = ctrlfile.catalog_version_no

        self.pg_majorversion = catalog_class.loadpgversion(pgdatadir)
        self.heapbuffer = LruCache(HeapBufferPage, self.blocksz,
                                   HEAP_BUFFER_COUNT)

    '''
        计算buffer tag。
    '''

    def __getbuftag(self, relfilenode, forknum, blocknum):
        return struct.pack('5I', relfilenode.space_node, relfilenode.db_node,
                           relfilenode.rel_node, forknum, blocknum)

    '''
        根据relfilenode得到文件名。根据global tablespace,default table space,还有指定了table space,文件名
        规则不一样。
    '''

    def getrelationpath(self, relfilenode, forknum):
        assert forknum == MAIN_FORKNUM or forknum == FSM_FORKNUM \
                        or forknum == VISIBILITYMAP_FORKNUM or forknum == INIT_FORKNUM
        pgdatadir = self.pgdatadir

        forkNames = ('', 'fsm', 'vm', 'init')
        if forknum == MAIN_FORKNUM:
            filename = relfilenode.rel_node
        else:
            filename = '%u_%s' % (relfilenode.rel_node, forkNames[forknum])

        if relfilenode.space_node == self.catalog_class.GLOBALTABLESPACE_OID:
            return '%s/global/%s' % (pgdatadir, filename)
        elif relfilenode.space_node == self.catalog_class.DEFAULTTABLESPACE_OID:
            return '%s/base/%u/%s' % (pgdatadir, relfilenode.db_node, filename)
        else:
            tablespacedir = "PG_%s_%u" % (self.pg_majorversion,
                                          self.catalog_version_no)
            return '%s/pg_tblspc/%u/%s/%u/%s' % (
                pgdatadir, relfilenode.space_node, tablespacedir,
                relfilenode.db_node, filename)

    def __loadbuffer(self, relfilenode, forknum, blocknum):
        try:
            blocksz = self.blocksz
            segsz = self.segfilesz

            filepath = self.getrelationpath(relfilenode, forknum)
            segno = blocknum / segsz
            if segno > 0:
                filepath = '%s.%u' % (filepath, segno)

            blockoff = blocksz * (blocknum % segsz)
            with open(filepath) as file:
                file.seek(blockoff)
                block = file.read(blocksz)
                if len(block) != blocksz:
                    logger.error('could not read block %u in file \"%s\": %m' %
                                 (blocknum, filepath))
                    raise UPgException('could not read block in file')
            return block
        except IOError:
            logger.error('could not read block %u in file \"%s\": %m' %
                         (blocknum, filepath))
            raise UPgException('could not read block in file')

    def readpage(self, relfilenode, forknum, blocknum):
        tag = self.__getbuftag(relfilenode, forknum, blocknum)
        buffpage = self.heapbuffer.get_and_visit(tag)
        if not buffpage:
            buffdata = self.__loadbuffer(relfilenode, forknum, blocknum)
            buffpage = self.heapbuffer.put(tag, buffdata)
        return buffpage

    def getblocknums(self, relfilenode, forknum):
        blocksz = self.blocksz
        segsz = self.segfilesz

        filepath = self.getrelationpath(relfilenode, forknum)
        segno = 0
        while True:
            if segno > 0:
                filepath = '%s.%u' % (filepath, segno)
            if not os.path.exists(filepath):
                return segno * segsz
            filesize = os.path.getsize(filepath) / blocksz
            if filesize > segsz:
                raise UPgException('could not read block in file')
            elif filesize < segsz:
                return segno * segsz + filesize
            else:
                segno += 1
Пример #3
0
class HeapBuffer:
    def __init__(self, pgdatadir, catalog_class):
        self.pgdatadir = pgdatadir
        self.catalog_class = catalog_class
        
        ctrlfile = ControlFile(pgdatadir)
        self.blocksz = ctrlfile.blcksz
        self.segfilesz = ctrlfile.relseg_size
        self.catalog_version_no = ctrlfile.catalog_version_no
        
        self.pg_majorversion = catalog_class.loadpgversion(pgdatadir)
        self.heapbuffer = LruCache(HeapBufferPage, self.blocksz, HEAP_BUFFER_COUNT)
    
    '''
        计算buffer tag。
    '''    
    def __getbuftag(self, relfilenode, forknum, blocknum):
        return struct.pack('5I', relfilenode.space_node, relfilenode.db_node, relfilenode.rel_node, forknum, blocknum)

    '''
        根据relfilenode得到文件名。根据global tablespace,default table space,还有指定了table space,文件名
        规则不一样。
    '''
    def getrelationpath(self, relfilenode, forknum):
        assert forknum == MAIN_FORKNUM or forknum == FSM_FORKNUM \
                        or forknum == VISIBILITYMAP_FORKNUM or forknum == INIT_FORKNUM
        pgdatadir = self.pgdatadir
        
        forkNames = ('', 'fsm', 'vm', 'init')
        if forknum == MAIN_FORKNUM:
            filename = relfilenode.rel_node
        else: 
            filename = '%u_%s'%(relfilenode.rel_node, forkNames[forknum])
        
        if relfilenode.space_node == self.catalog_class.GLOBALTABLESPACE_OID:
            return '%s/global/%s'%(pgdatadir, filename)
        elif relfilenode.space_node == self.catalog_class.DEFAULTTABLESPACE_OID:
            return '%s/base/%u/%s'%(pgdatadir, relfilenode.db_node, filename)
        else:
            tablespacedir =  "PG_%s_%u"%(self.pg_majorversion, self.catalog_version_no) 
            return '%s/pg_tblspc/%u/%s/%u/%s'%(pgdatadir, relfilenode.space_node, tablespacedir, relfilenode.db_node, filename)
        

    def __loadbuffer(self, relfilenode, forknum, blocknum):
        try:
            blocksz = self.blocksz
            segsz = self.segfilesz
        
            filepath = self.getrelationpath(relfilenode, forknum)
            segno = blocknum/segsz
            if segno > 0:
                filepath = '%s.%u'%(filepath, segno)
        
            blockoff = blocksz * (blocknum%segsz)
            with open(filepath) as file:
                file.seek(blockoff)
                block = file.read(blocksz)
                if len(block) != blocksz:
                    logger.error('could not read block %u in file \"%s\": %m'%(blocknum, filepath))
                    raise UPgException('could not read block in file')
            return block
        except IOError:
            logger.error('could not read block %u in file \"%s\": %m'%(blocknum, filepath))
            raise UPgException('could not read block in file')
            

    def readpage(self, relfilenode, forknum, blocknum):
        tag = self.__getbuftag(relfilenode, forknum, blocknum)
        buffpage = self.heapbuffer.get_and_visit(tag)
        if not buffpage:
            buffdata = self.__loadbuffer(relfilenode, forknum, blocknum)
            buffpage = self.heapbuffer.put(tag, buffdata)
        return buffpage

    def getblocknums(self, relfilenode, forknum):
        blocksz = self.blocksz
        segsz = self.segfilesz
            
        filepath = self.getrelationpath(relfilenode, forknum)
        segno = 0
        while True:
            if segno > 0:
                filepath = '%s.%u' % (filepath, segno)
            if not os.path.exists(filepath):
                return segno * segsz
            filesize = os.path.getsize(filepath)/blocksz
            if filesize > segsz:
                raise UPgException('could not read block in file')
            elif filesize < segsz:
                return segno * segsz + filesize
            else:
                segno += 1