项目结构
相关类和方法
TupleDesc.java:
- class TDItem :用于组织每一列的辅助类,包含fieldType和fieldName两个属性。
- TupleDesc构造函数:创建一个TDItem数组,描述一个tuple包括哪些field。
- numFields():返回TDItem数组的大小。
- getFieldName(int i):返回TDItem数组中下标i的fieldName。
- getFieldType(int i):返回TDItem数组中下标i的fieldType。
- fieldNameToIndex(String name):遍历TDItem数组找到对应fieldName的下标。getSize():遍历TDItem数组,求每一列fieldType大小总和。
- merge(TupleDesc td1, TupleDesc td2):把两个TupleDesc合二为一。
- equals(Object o):判断两个TupleDesc的列属性是否相同。
Tuple.java:
- Tuple构造函数:创建fields数组。
- getTupleDesc():返回当前tuple的TupleDesc结构。
- getRecordId()、setRecordId:获得/设置当前tuple的RecordId,RecordId代表了当前tuple在disk上的位置。
- setField(int i, Field f):为fields数组下标i处的field赋新值。
- getField(int i):获得fields数组下标i处的field值。
- fields():返回一个迭代器,迭代此tuple内fields数组的所有元素。
Catalog.java:
- class Table:为Catalog存储的一个个表建立的辅助类,Table类的构造函数需要三个参数,第一个参数是DbFile类型,是table的内容;第二个参数是String类型,是table 的name;第三个参数是pkeyField,代表表中主键的fieldName。
- Catalog构造函数:创建一个<Interger,Table>的哈希表,用于存储已经实例化的表。
- addTable(DbFile file, String name, String pkeyField):在哈希表中添加一个Table。
- getTableId(String name):遍历哈希表中的Tables,找到对应名字返回table的Id。
- getTupleDesc(int tableid):返回tableid表对应的TupleDesc表结构。
- getDatabaseFile(int tableid):返回tableid表对应的表数据DbFile。
- getPrimaryKey(int tableid):返回tableid表对应的主键名。
- getTableName(int id):返回tableid表对应的TableName。
- clear():从Catalog中删除所有的tables。
- loadSchema(String catalogFile):利用正则化从file中读取表的结构,并在数据库中创建所有合适的表。
BufferPool.java:
- class Lock:为Transaction设置锁的辅助类,Lock类的构造函数需要两个参数,第一个参数是加锁Transaction的TransactionId;第二个参数是锁的类型(0 for shared lock and 1 for exclusive lock)。
- class PageLockManager:管理基于页的加锁解锁所需的辅助类,创建一个<PageId,Vector<Lock>>的哈希表,保存每页上拥有的锁集合。有三个内置方法,第一个是acquireLock(PageId pid,TransactionId tid,int lockType)用来加锁;第二个是releaseLock(PageId pid,TransactionId tid)用来解锁;第三个是holdsLock(PageId pid,TransactionId tid)用来判断是否有锁。
- BufferPool(int numPages):BufferPool的构造函数,创建一个BufferPool实例缓存最大numPages数量的Pages,通过<PageId,Page>类型的pageStore哈希表管理缓存pages。
- getPageSize():获得每个Page大小,默认是4096。
- getPage(TransactionId tid, PageId pid, Permissions perm):根据pid获取Page,如果在pageStore中,返回对应Page,如果不在就添加进哈希表,如果缓存的page数量超过缓存最大numPages数量,调用evictPage()淘汰一个页。获得page时在tid代表的Transaction上加锁,perm代表锁的类型,保证使用返回Page时的安全性。
- releasePage(TransactionId tid, PageId pid):调用 lockManager.releaseLock(pid,tid) 解锁。
- holdsLock(TransactionId tid, PageId p):判断特定Transaction是否在特定Page上加了锁。
- transactionComplete(TransactionId tid, boolean commit):如果commit,则调用flushPages(tid)将缓存中的页数据写入disk。如果没有commit,则调用 restorePages(tid) 回滚commit,重置pageStore中dirty的Page。
- insertTuple(TransactionId tid, int tableId, Tuple t):在BufferPool中添加特定的tuple到tableId对应的表中,调用DbFile的insertTuple(tid, t)方法(其中有一个读写锁),并将添加了tuple的page mark dirty。
- deleteTuple(TransactionId tid, Tuple t):从BufferPool中删除特定的tuple,调用DbFile的deleteTuple(tid, t)方法(其中有一个读写锁),并将删除了tuple的page mark dirty。
- discardPage(PageId pid):从BufferPool的缓存中删除pid对应的page。
- flushPage(PageId pid):将pid对应的Page从BuffePool的缓存中写入disk。
- flushPages(TransactionId tid):将tid下所有BufferPool缓存中的Page都写入disk。
- evictPage():当缓存的page数量超过缓存最大numPages数量,调用evictPage()淘汰一个页。先维护一个<PageId,Integer>类型的哈希表pageAge,根据Page载入cache的时间排序,淘汰缓存中最老的Page,当然这是最简单的一种实现,还有其他实现方式。
HeapPageId.java :
- HeapPageId的构造函数:对于特定table中的一页特定Page,设置一个page id 结构,参数为int类型的tableId和int类型的pgNo。
- getTableId():返回PageId对应的tableId。
- getPageNumber():返回tableId对应的表包含的page数量。
- equals(Object o):判断两个pageId对象是否相等。
RecordID.java:
- RecordId的构造函数:RecordId是对一个特定Table中特定一个Page的一个特定tuple的引用,构造时用到的参数是PageId类型的 pid 和 int类型的 tupleno,其中pid是该tuple所在的Page对应的Id,tupleno是该tuple是该Page中第几个。
- getTupleNumber():返回RecordId引用tuple的tupleno。
- getPageId():返回RecordId引用tuple的pid。
- equals(Object o):判断两个RecordId对象是否相等。
HeapPage.java:
- class HeapPageIterator:用于迭代HeapPage,有hasNext()、next()、remove()等方法。
- HeapPage的构造函数:有两个参数,第一个是HeapPageId,第二个是byte[] 类型的data。在构造函数中为data分配空间,并将空间中开始部分用于header,header中保存了此页slots的bitmap信息。
- getNumTuples():返回此页中能够存储的tuple数量,用于构造函数中分配slot。
- getHeaderSize():返回此页需要多少bytes作为header。
- getBeforeImage():在修改前返回此页的view,用于recovery。
- getId():返回此页的pid。
- readNextTuple(DataInputStream dis, int slotId):寻找到下一个被占用的slot,返回读取的tuple。
- getPageData():返回byte[] 类型的此页数据。
- deleteTuple(Tuple t):从此页中删除特定的tuple数据,同时修改header中对应的bit,指示此slot处的数据已经被删除了。(这里其实没有删除数据,只是在header处显示此处数据为空,可用其他数据替换)。
- insertTuple(Tuple t):利用getFirstNotUsedSlot()函数找到第一个空闲的slot,加入数据,同时修改header中对应的bit,指示此slot处有数据。
- getFirstNotUsedSlot():找到第一个为空的slot下标。
- markDirty(boolean dirty, TransactionId tid):标识此页的dirty/not dirty状态,同时利用tid说明是哪一个Transaction做了该标识。
- TransactionId isDirty():返回最后一个dirtied了此页的Transaction的tid,如果不dirty返回null。
- getNumEmptySlots():返回此页中为空的slot数量。
- isSlotUsed(int i):判断下标为i的slot是否被占用。
- markSlotUsed(int i, boolean value):在header中标识下标为i的slot是否被占用,true在header的bit位上标1,false则标0。
HeapFile.java:
- HeapFile的构造函数:通过特定的file文件构建一个heap file,有两个参数,第一个是File类型的f,第二个是TupleDesc类型的td。
- getFile():返回磁盘中支持此HeapFile 的File类型文件。
- getId():返回唯一标识此HeapFile的ID。
- getTupleDesc():返回存储在这个DbFile中的table 的TupleDesc。
- readPage(PageId pid):读取pid对应的Page。先找到File内要读取的Page Number,读取整个Page返回。
- writePage(Page page):写pid对应的Page。先找到File内要写的Page Number,写入整个Page。
- numPages():返回这个HeapFile中包含的page数量。
- insertTuple(TransactionId tid, Tuple t):找到一个未满的page,如果不存在空闲的slot,创建新的一页存储tuple,之后添加,返回添加过的Page。
- deleteTuple(TransactionId tid, Tuple t):找到对应的page,删除tuple,标识此page为dirty。
SeqScan.java:
- SeqScan的构造函数:创建一次特定的transaction对特定table内的数据进行遍历,有三个参数,第一个参数是transaction对应的tid;第二个参数是tableId;第三个参数是表的别名,用于解析。
- getTableName():返回对应tid。
- getAlias():返回对应别名。
- open():使用DbFileIterator打开table。
- getTupleDesc():返回table 的TupleDesc类型。
- close():使用DbFileIterator关闭table。
Predicate.java:
- enum Op:枚举定义了EQUALS, GREATER_THAN, LESS_THAN, LESS_THAN_OR_EQ, GREATER_THAN_OR_EQ, LIKE,NOT_EQUALS这六种Predicate Op。
- Predicate构造函数:这里有三个参数,第一个参数是field,是进行谓词比较的filed 数量;第二个参数是Op,是用于比较的谓词Operation;第三个参数是operand,时传入要比较的field value。
- filter(Tuple t):在特定的field、Operation、operand下与tuple t进行比较。
JoinPredicate.java:
- JoinPredicate的构造函数:JoinPredicate利用一个Predicate对两个tuples的fields进行比较,JoinPredicate最常被Join operator使用。构造函数创建在两个tuples的两个fields上创建一个新的Predicate。有三个参数,第一个参数和第二个参数是field1和field2,是Predicate中第一个tuple和第二个tuple的下标;第三个参数是op,是应用的operation。
- filter(Tuple t1, Tuple t2):将Predicate用用两个特定tuples。
Aggregate.java:
- Aggregate的构造函数:Aggregation operator用于计算一个Aggregate(e.g. sum,avg,max,min),我们需要对一列数据支持聚合。构造函数有四个参数,第一个参数是OpIterator类型的 child,用于不断提供tuples;第二个参数是 int 类型的 afield,标识着我们需要聚合的列;第三个参数是 int 类型的gfield,标识着结果中我们需要group by 的列;第四个参数是 Aggregator.Op类型的aop,是我们需要使用的Aggregation operator。
- groupField():如果这个Aggregate伴随有 groupby,返回groupby的field 的索引。
- groupFieldName():如果这个Aggregate伴随有 groupby,返回groupby的field 的Name。
- fetchNext():返回下一个tuple。如果有groupby field,那么第一个field是我们group的field,第二个field是计算的aggregate结果;如果没有groupby field,只需要返回结果。
- getTupleDesc():返回这个aggregate计算结果tuple的TupleDesc。
Insert.java:
- class Insert的构造函数:把从child operator中读取到的tuples添加到tableId对应的表中。有三个参数,第一个参数是代表transaction的tid,第二个参数是OpIterator类型的迭代器child,第三个参数是tableId。
- fetchNext():利用OpIterator类型的迭代器child找到一组要添加的记录,insert需要经过BufferPool,所以使用Database.getBufferPool().insertTuple(this.tid, this.tableId, t)方法进行添加。
Delete.java:
- class Insert的构造函数:把从child operator中读取到的tuples从tableId对应的表中删除。有两个参数,第一个参数是代表transaction的tid,第二个参数是OpIterator类型的迭代器child。
- fetchNext():利用OpIterator类型的迭代器child找到一组要删除的记录,insert需要经过BufferPool,所以使用Database.getBufferPool().deleteTuple(this.tid, t)方法进行删除。