在谈MIT6.830 lab1 细节剖析 (已完结)

该项目使用Java来实现,充分体现面向对象特性。

part1 是对关系型数据库表结构的抽象,实现以下几个类

src / java / simpledb / storage / TupleDesc.java
src / java / simpledb / storage / Tuple.java

这个项目写起来有些特别,通常我们自己来实现,是设计数据,然后用IDEA实现get和set方法。这里项目设计是反过来的,已经有get和set。让我们去补全数据,目的是通过练习,理解整个架构。

在实现过程中,注意equals, hashcode, tostring方法实现均可以用idea自动生成,这也是Java的特色所在。

其中Java ArrayList, string.join方法有些地方要注意,这里就不再提了。

 

part2 是实现catalog,也就是管理所有表结构的类。是一个单例

src / java / simpledb / common / Catalog.java

这里找不到table的定义,因此我们需要自己实现一个table类

    class Table{
        public Table(DbFile file, String name, String pkeyField){
            this.file = file;
            this.name = name;
            this.pkeyField = pkeyField;
            this.tupleDesc = file.getTupleDesc();
        }
        public DbFile file;
        public String name;
        public String pkeyField;
        public TupleDesc tupleDesc;
    }

    HashMap<Integer, Table> tables = new HashMap<>();

part3是实现一个BufferPool

src/java/simpledb/storage/BufferPool.java

只需要实现构造函数和getPage

这里也是写数据成员,很容易想到一个是HashMap,但是为了考虑并发,这里用线程安全的HashMap,加读写锁,后面会修改。

getPage发生缺页时,要去往硬盘上读,这里处理可以先实现

    private ConcurrentHashMap<PageId, Page> pageTable;

    private ReadWriteLock rwLock;
    public  Page getPage(TransactionId tid, PageId pid, Permissions perm)
        throws TransactionAbortedException, DbException {
        // some code goes here
        rwLock.readLock().lock();
        Page page = pageTable.get(pid);
        if(page == null){
            DbFile file = Database.getCatalog().getDatabaseFile(pid.getTableId());
            page = file.readPage(pid);
        }
        rwLock.readLock().unlock();
        return page;
    }

Part4 

实现这三个,HeapPage 是Page接口的实现

src/java/simpledb/storage/HeapPageId.java
src/java/simpledb/storage/RecordId.java
src/java/simpledb/storage/HeapPage.java

主要是实现HeapPage

其中HeapPage是一个可以序列话为二进制存储的结构,比较关键的数据有

_tuples per page_ = floor((_page size_ * 8) / (_tuple size_ * 8 + 1))

以及headerBytes = ceiling(tupsPerPage/8

因为headerBytes是Bit数组标记tupsPerPage是否在使用

与之相关的两个方法就很好实现。

另外就是BitMap的操作

判断BitMap中有多少个0

我们转换成判断BitMap中有多少个1

然后用lowBit技巧。

    /**
     * Returns the number of empty slots on this page.
     */
    public int getNumEmptySlots() {
        // some code goes here
        int num = 0;
        for(byte b : header){
            while(b != 0){
                num++;
                b &= (b-1);
            }
        }
        return getNumTuples() - num;
    }

然后是BitMap判断是否使用

    /**
     * Returns true if associated slot on this page is filled.
     */
    public boolean isSlotUsed(int i) {
        // some code goes here
        byte b = header[i / 8];
        return (b & (1 << (i % 8))) != 0;
    }

 

然后就是结合BitMap实现一个迭代器,这里也是常规操作:

    /**
     * @return an iterator over all tuples on this page (calling remove on this iterator throws an UnsupportedOperationException)
     * (note that this iterator shouldn't return tuples in empty slots!)
     */
    public Iterator<Tuple> iterator() {
        // some code goes here
        return new Iterator<Tuple>(){

            int i = 0;

            @Override
            public boolean hasNext() {
                return i < getNumTuples() - getNumEmptySlots();
            }

            @Override
            public Tuple next() {
                if(!hasNext()){
                    throw new NoSuchElementException();
                }
                while(!isSlotUsed(i)){
                    i++;
                }
                return tuples[i++];
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }

}

Part4 是实现一个HeapFile, HeapFile是File接口的实现,其中一个DbFile有多少Page的实现如下:

    /**
     * Returns the number of pages in this HeapFile.
     */
    public int numPages() {
        // some code goes here
        return (int) f.length() / BufferPool.getPageSize();
    }

然后读取DbFile指定的Page使用标准的文件偏移量做法即可。

    // see DbFile.java for javadocs
    public Page readPage(PageId pid) {
        // some code goes here
        // 读取File指定的一页
        try {
            RandomAccessFile rfile = new RandomAccessFile(f, "r");
            int pageSize = BufferPool.getPageSize();
            byte[] buffer = new byte[pageSize];
            rfile.seek((long) pid.getPageNumber() * pageSize);
            if(rfile.read(buffer) == -1){
                return null;
            }
            return new HeapPage(new HeapPageId(pid.getTableId(), pid.getPageNumber()), buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

Part7是实现一个命令行测试, 然后用一段数据测试

1,1,1
2,2,2 
3,4,4
public class test {

    public static void main(String[] argv) {

        // construct a 3-column table schema
        Type types[] = new Type[]{ Type.INT_TYPE, Type.INT_TYPE, Type.INT_TYPE };
        String names[] = new String[]{ "field0", "field1", "field2" };
        TupleDesc descriptor = new TupleDesc(types, names);

        // create the table, associate it with some_data_file.dat
        // and tell the catalog about the schema of this table.
        HeapFile table1 = new HeapFile(new File("some_data_file.dat"), descriptor);
        Database.getCatalog().addTable(table1, "test");

        // construct the query: we use a simple SeqScan, which spoonfeeds
        // tuples via its iterator.
        TransactionId tid = new TransactionId();
        SeqScan f = new SeqScan(tid, table1.getId());
        try {
            // and run it
            f.open();
            //System.out.println(1);
            while (f.hasNext()) {
                Tuple tup = f.next();
                System.out.println(tup);
            }
            f.close();
            Database.getBufferPool().transactionComplete(tid);
        } catch (Exception e) {
            System.out.println ("Exception : " + e);
        }
    }

}

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验目标: 本实验的目标是完成一个可以在QEMU仿真器上运行的x86操作系统。具体地说,我们将编写引导扇区代码和内核代码,并将它们组合成一个可引导的磁盘映像。最后,我们将使用QEMU仿真器启动我们的操作系统。 实验步骤: 1. 准备工作 准备工作包括安装必要的软件和工具、下载实验代码和文档等。 2. 编写引导扇区代码 引导扇区是操作系统的第一个扇区,它需要被放置在磁盘的第一个扇区。引导扇区必须包含一个512字节的主引导记录(MBR),其中包括一个引导程序和分区表。我们需要编写一个能够在引导扇区中运行的汇编代码,它将加载内核并将控制权转交给内核。 3. 编写内核代码 内核是操作系统的核心部分,它负责管理计算机的硬件资源、提供系统调用接口等。我们需要编写一个简单的内核,该内核将输出“Hello, world!”并进入无限循环。我们可以使用C语言编写内核代码,并使用GCC编译器将其编译成汇编代码。 4. 构建磁盘映像 我们需要将引导扇区和内核代码组合成一个可引导的磁盘映像。为此,我们可以使用dd命令将引导扇区和内核代码写入一个空白磁盘映像中。 5. 启动操作系统 最后,我们需要使用QEMU仿真器启动我们的操作系统。我们可以使用以下命令启动QEMU并加载磁盘映像: ``` qemu-system-i386 -hda os.img ``` 实验结果: 经过以上步骤,我们成功地编写了一个简单的操作系统,并使用QEMU仿真器进行了测试。当我们启动操作系统时,它将输出“Hello, world!”并进入无限循环。 实验总结: 本实验让我了解了操作系统的基本概念和架构,并学会了如何编写一个简单的操作系统。通过实验,我更深入地理解了计算机系统的底层原理,对操作系统的工作原理有了更深入的了解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值