├── .dockerignore ├── .clang-format ├── third_party ├── .clang-tidy ├── versions.txt └── murmur3 │ └── MurmurHash3.h ├── src ├── include │ ├── type │ │ ├── type_id.h │ │ ├── abstract_pool.h │ │ ├── numeric_type.h │ │ ├── boolean_type.h │ │ ├── timestamp_type.h │ │ ├── bigint_type.h │ │ ├── tinyint_type.h │ │ ├── smallint_type.h │ │ ├── integer_type.h │ │ ├── varlen_type.h │ │ ├── limits.h │ │ └── decimal_type.h │ ├── storage │ │ ├── table │ │ │ ├── tmp_tuple.h │ │ │ ├── table_iterator.h │ │ │ ├── tuple.h │ │ │ └── table_heap.h │ │ ├── page │ │ │ ├── hash_table_page_defs.h │ │ │ ├── tmp_tuple_page.h │ │ │ ├── hash_table_header_page.h │ │ │ ├── page.h │ │ │ └── hash_table_block_page.h │ │ ├── index │ │ │ ├── int_comparator.h │ │ │ ├── hash_comparator.h │ │ │ ├── linear_probe_hash_table_index.h │ │ │ └── generic_key.h │ │ └── disk │ │ │ └── disk_manager.h │ ├── container │ │ └── hash │ │ │ ├── hash_function.h │ │ │ ├── hash_table.h │ │ │ └── linear_probe_hash_table.h │ ├── execution │ │ ├── executor_factory.h │ │ ├── expressions │ │ │ ├── constant_value_expression.h │ │ │ ├── aggregate_value_expression.h │ │ │ ├── column_value_expression.h │ │ │ ├── abstract_expression.h │ │ │ └── comparison_expression.h │ │ ├── executors │ │ │ ├── abstract_executor.h │ │ │ ├── seq_scan_executor.h │ │ │ └── insert_executor.h │ │ ├── plans │ │ │ ├── seq_scan_plan.h │ │ │ ├── abstract_plan.h │ │ │ ├── hash_join_plan.h │ │ │ └── insert_plan.h │ │ └── executor_context.h │ ├── common │ │ ├── macros.h │ │ ├── bustub_instance.h │ │ ├── config.h │ │ ├── rid.h │ │ ├── rwlatch.h │ │ ├── util │ │ │ ├── hash_util.h │ │ │ └── string_util.h │ │ └── exception.h │ ├── recovery │ │ ├── checkpoint_manager.h │ │ ├── log_recovery.h │ │ └── log_manager.h │ ├── buffer │ │ ├── replacer.h │ │ └── clock_replacer.h │ ├── catalog │ │ ├── table_generator.h │ │ ├── simple_catalog.h │ │ ├── schema.h │ │ └── column.h │ └── concurrency │ │ └── transaction_manager.h ├── common │ └── config.cpp ├── CMakeLists.txt ├── catalog │ ├── column.cpp │ └── schema.cpp ├── recovery │ ├── checkpoint_manager.cpp │ ├── log_recovery.cpp │ └── log_manager.cpp ├── storage │ ├── page │ │ ├── hash_table_header_page.cpp │ │ └── hash_table_block_page.cpp │ ├── index │ │ └── linear_probe_hash_table_index.cpp │ └── table │ │ └── table_iterator.cpp ├── type │ ├── integer_parent_type.cpp │ └── boolean_type.cpp ├── buffer │ └── clock_replacer.cpp ├── concurrency │ ├── lock_manager.cpp │ └── transaction_manager.cpp └── execution │ └── executor_factory.cpp ├── README.md ├── Dockerfile ├── LICENSE ├── .circleci └── config.yml ├── test ├── common │ └── rwlatch_test.cpp ├── catalog │ └── catalog_test.cpp ├── storage │ └── tmp_tuple_page_test.cpp ├── buffer │ ├── clock_replacer_test.cpp │ └── buffer_pool_manager_test.cpp ├── include │ └── logging │ │ └── common.h ├── table │ └── tuple_test.cpp ├── type │ └── type_test.cpp ├── CMakeLists.txt └── container │ ├── hash_table_test.cpp │ └── hash_table_page_test.cpp ├── .travis.yml └── .clang-tidy /.dockerignore: -------------------------------------------------------------------------------- 1 | # Don't send any build context to Docker. 2 | ** -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | DerivePointerAlignment: false 3 | PointerAlignment: Right 4 | ColumnLimit: 120 -------------------------------------------------------------------------------- /third_party/.clang-tidy: -------------------------------------------------------------------------------- 1 | # Disable all checks for third-party sources. 2 | 3 | Checks: ' 4 | -*, 5 | ' -------------------------------------------------------------------------------- /src/include/type/type_id.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // type_id.h 6 | // 7 | // Identification: src/include/type/type_id.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | namespace bustub { 16 | // Every possible SQL type ID 17 | enum TypeId { INVALID = 0, BOOLEAN, TINYINT, SMALLINT, INTEGER, BIGINT, DECIMAL, VARCHAR, TIMESTAMP }; 18 | } // namespace bustub 19 | -------------------------------------------------------------------------------- /src/include/storage/table/tmp_tuple.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/config.h" 4 | 5 | namespace bustub { 6 | 7 | // Document this class! What does it represent? 8 | 9 | class TmpTuple { 10 | public: 11 | TmpTuple(page_id_t page_id, size_t offset) : page_id_(page_id), offset_(offset) {} 12 | 13 | inline bool operator==(const TmpTuple &rhs) const { return page_id_ == rhs.page_id_ && offset_ == rhs.offset_; } 14 | 15 | page_id_t GetPageId() const { return page_id_; } 16 | size_t GetOffset() const { return offset_; } 17 | 18 | private: 19 | page_id_t page_id_; 20 | size_t offset_; 21 | }; 22 | 23 | } // namespace bustub 24 | -------------------------------------------------------------------------------- /src/common/config.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // config.cpp 6 | // 7 | // Identification: src/common/config.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "common/config.h" 14 | 15 | namespace bustub { 16 | 17 | std::atomic enable_logging(false); 18 | 19 | std::chrono::duration log_timeout = std::chrono::seconds(1); 20 | 21 | std::chrono::milliseconds cycle_detection_interval = std::chrono::milliseconds(50); 22 | 23 | } // namespace bustub 24 | -------------------------------------------------------------------------------- /src/include/storage/page/hash_table_page_defs.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // hash_table_page_defs.h 6 | // 7 | // Identification: src/include/storage/page/hash_table_page_defs.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #define MappingType std::pair 16 | 17 | #define BLOCK_ARRAY_SIZE (4 * PAGE_SIZE / (4 * sizeof(MappingType) + 1)) 18 | 19 | #define HASH_TABLE_BLOCK_TYPE HashTableBlockPage 20 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This is hacky :( 2 | file(GLOB_RECURSE bustub_sources ${PROJECT_SOURCE_DIR}/src/*/*.cpp ${PROJECT_SOURCE_DIR}/src/*/*/*.cpp) 3 | add_library(bustub_shared SHARED ${bustub_sources}) 4 | 5 | ###################################################################################################################### 6 | # THIRD-PARTY SOURCES 7 | ###################################################################################################################### 8 | 9 | # murmur3 10 | file(GLOB_RECURSE murmur3_sources 11 | ${PROJECT_SOURCE_DIR}/third_party/murmur3/*.cpp ${PROJECT_SOURCE_DIR}/third_party/murmur3/*.h) 12 | add_library(thirdparty_murmur3 SHARED ${murmur3_sources}) 13 | target_link_libraries(bustub_shared thirdparty_murmur3) 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BusTub Logo 2 | 3 | ----------------- 4 | 5 | # CMU 15-445 (Fall 2019) 6 | 7 | ## 课程传送门 8 | 9 | [Introduction to Database Systems](https://15445.courses.cs.cmu.edu) 10 | 11 | ## 课程简介 12 | 13 | 该课程是CMU的数据库系统的基础课程(Andy Pavlo的课),共有四个Project,完善BusTub RDBMS的相应功能,具体说明见课程的assignment 14 | 15 | 建议在写项目之前,先好好看Andy的课程,有条件的去听一听YouTube上的课程视频,至少要把PPT仔细过一遍,不过瘾的还可以看看课程的textbook[《Database System Concepts》](https://book.douban.com/subject/30345517/)(第七版已经出来了) 16 | 17 | ## Projects 18 | 19 | - [x] Project 1 - Clock Replacer & Buffer Pool Manager 20 | 21 | - [x] Project 2 - Hash Index 22 | 23 | - [x] Project 3 - Query Execution 24 | 25 | - [ ] Project 4 - Logging & Recovery 26 | 27 | ps: master分支是原始的BusTub,完成的Project都打了tag 28 | -------------------------------------------------------------------------------- /src/include/storage/index/int_comparator.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // int_comparator.h 6 | // 7 | // Identification: src/include/storage/index/int_comparator.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | namespace bustub { 16 | 17 | /** 18 | * Function object return is > 0 if lhs > rhs, < 0 if lhs < rhs, 19 | * = 0 if lhs = rhs . 20 | */ 21 | class IntComparator { 22 | public: 23 | inline int operator()(const int lhs, const int rhs) { return lhs - rhs; } 24 | }; 25 | } // namespace bustub 26 | -------------------------------------------------------------------------------- /src/include/storage/index/hash_comparator.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // hash_comparator.h 6 | // 7 | // Identification: src/include/storage/index/hash_comparator.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | namespace bustub { 16 | 17 | /** 18 | * HashComparator is for comparing hash_t, it returns: 19 | * < 0 if lhs < rhs 20 | * > 0 if lhs > rhs 21 | * = 0 if lhs = rhs 22 | */ 23 | class HashComparator { 24 | public: 25 | inline int operator()(const hash_t lhs, const hash_t rhs) { return lhs < rhs ? -1 : (lhs > rhs ? 1 : 0); } 26 | }; 27 | 28 | } // namespace bustub 29 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | CMD bash 3 | 4 | # Install Ubuntu packages. 5 | # Please add packages in alphabetical order. 6 | ARG DEBIAN_FRONTEND=non-interactive 7 | 8 | RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list && \ 9 | apt-get clean && \ 10 | apt-get -y update && \ 11 | apt-get -y install \ 12 | build-essential \ 13 | apt-utils \ 14 | clang-8 \ 15 | clang-format-8 \ 16 | clang-tidy-8 \ 17 | cmake \ 18 | doxygen \ 19 | git \ 20 | g++-7 \ 21 | pkg-config \ 22 | valgrind \ 23 | zlib1g-dev \ 24 | openssh-server \ 25 | rsync \ 26 | sudo \ 27 | vim && \ 28 | useradd -d "/home/jyh" -m -s "/bin/bash" jyh && \ 29 | chmod u+w /etc/sudoers && \ 30 | echo "jyh ALL=(ALL:ALL) NOPASSWD:ALL" >> /etc/sudoers && \ 31 | chmod u-w /etc/sudoers && \ 32 | echo "PermitRootLogin yes" >> /etc/ssh/sshd_config -------------------------------------------------------------------------------- /src/catalog/column.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // column.cpp 6 | // 7 | // Identification: src/catalog/column.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "catalog/column.h" 14 | 15 | #include 16 | #include 17 | 18 | namespace bustub { 19 | 20 | std::string Column::ToString() const { 21 | std::ostringstream os; 22 | 23 | os << "Column[" << column_name_ << ", " << Type::TypeIdToString(column_type_) << ", " 24 | << "Offset:" << column_offset_ << ", "; 25 | 26 | if (IsInlined()) { 27 | os << "FixedLength:" << fixed_length_; 28 | } else { 29 | os << "VarLength:" << variable_length_; 30 | } 31 | os << "]"; 32 | return (os.str()); 33 | } 34 | 35 | } // namespace bustub 36 | -------------------------------------------------------------------------------- /src/recovery/checkpoint_manager.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // checkpoint_manager.cpp 6 | // 7 | // Identification: src/recovery/checkpoint_manager.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "recovery/checkpoint_manager.h" 14 | 15 | namespace bustub { 16 | 17 | void CheckpointManager::BeginCheckpoint() { 18 | // Block all the transactions and ensure that both the WAL and all dirty buffer pool pages are persisted to disk, 19 | // creating a consistent checkpoint. Do NOT allow transactions to resume at the end of this method, resume them 20 | // in CheckpointManager::EndCheckpoint() instead. This is for grading purposes. 21 | } 22 | 23 | void CheckpointManager::EndCheckpoint() { 24 | // Allow transactions to resume, completing the checkpoint. 25 | } 26 | 27 | } // namespace bustub 28 | -------------------------------------------------------------------------------- /src/include/container/hash/hash_function.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // hash_function.h 6 | // 7 | // Identification: src/include/container/hash/hash_function.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | #include "murmur3/MurmurHash3.h" 18 | 19 | namespace bustub { 20 | 21 | template 22 | class HashFunction { 23 | public: 24 | /** 25 | * @param key the key to be hashed 26 | * @return the hashed value 27 | */ 28 | virtual uint64_t GetHash(KeyType key) { 29 | uint64_t hash[2]; 30 | murmur3::MurmurHash3_x64_128(reinterpret_cast(&key), static_cast(sizeof(KeyType)), 0, 31 | reinterpret_cast(&hash)); 32 | return hash[0]; 33 | } 34 | }; 35 | 36 | } // namespace bustub 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 CMU Database Group 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build_test: 4 | docker: 5 | - image: ubuntu:18.04 6 | steps: 7 | # install dependencies 8 | # TODO (Chenyao): I'm not sure which packages are useful. Trim unused packages to speed up. 9 | - run: apt-get -y update && 10 | apt-get -y install 11 | build-essential 12 | clang-8 13 | clang-format-8 14 | clang-tidy-8 15 | cmake 16 | doxygen 17 | git 18 | g++-7 19 | libjemalloc-dev 20 | libevent-dev 21 | libpq-dev 22 | libsqlite3-dev 23 | libtbb-dev 24 | llvm-8 25 | pkg-config 26 | postgresql-client 27 | sqlite3 28 | valgrind 29 | zlib1g-dev 30 | - checkout 31 | - run: mkdir build 32 | - run: cd build && cmake -DCMAKE_BUILD_TYPE=Debug .. 33 | - run: cd build && make -j 34 | - run: cd build && make check-tests 35 | 36 | workflows: 37 | version: 2 38 | workflow: 39 | jobs: 40 | - build_test -------------------------------------------------------------------------------- /src/include/storage/page/tmp_tuple_page.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "storage/page/page.h" 4 | #include "storage/table/tmp_tuple.h" 5 | #include "storage/table/tuple.h" 6 | 7 | namespace bustub { 8 | 9 | // To pass the test cases for this class, you must follow the existing TmpTuplePage format and implement the 10 | // existing functions exactly as they are! It may be helpful to look at TablePage. 11 | // Remember that this task is optional, you get full credit if you finish the next task. 12 | 13 | /** 14 | * TmpTuplePage format: 15 | * 16 | * Sizes are in bytes. 17 | * | PageId (4) | LSN (4) | FreeSpace (4) | (free space) | TupleSize2 | TupleData2 | TupleSize1 | TupleData1 | 18 | * 19 | * We choose this format because DeserializeExpression expects to read Size followed by Data. 20 | */ 21 | class TmpTuplePage : public Page { 22 | public: 23 | void Init(page_id_t page_id, uint32_t page_size) {} 24 | 25 | page_id_t GetTablePageId() { return INVALID_PAGE_ID; } 26 | 27 | bool Insert(const Tuple &tuple, TmpTuple *out) { return false; } 28 | 29 | private: 30 | static_assert(sizeof(page_id_t) == 4); 31 | }; 32 | 33 | } // namespace bustub 34 | -------------------------------------------------------------------------------- /src/include/execution/executor_factory.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // executor_factory.h 6 | // 7 | // Identification: src/include/execution/executor_factory.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | #include "execution/executors/abstract_executor.h" 18 | #include "execution/plans/abstract_plan.h" 19 | 20 | namespace bustub { 21 | /** 22 | * ExecutorFactory creates executors for arbitrary plan nodes. 23 | */ 24 | class ExecutorFactory { 25 | public: 26 | /** 27 | * Creates a new executor given the executor context and plan node. 28 | * @param exec_ctx the executor context for the created executor 29 | * @param plan the plan node that needs to be executed 30 | * @return an executor for the given plan and context 31 | */ 32 | static std::unique_ptr CreateExecutor(ExecutorContext *exec_ctx, const AbstractPlanNode *plan); 33 | }; 34 | } // namespace bustub 35 | -------------------------------------------------------------------------------- /third_party/versions.txt: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | # Toolchain library versions 19 | 20 | GTEST_VERSION=1.8.0 21 | GFLAGS_VERSION=2.2.0 22 | GBENCHMARK_VERSION=1.4.1 23 | 24 | # Library, Version, Commit Hash 25 | 26 | # murmur3 27 | # url: https://github.com/aappleby/smhasher.git 28 | # branch: master 29 | # commit hash: 61a0530f28277f2e850bfc39600ce61d02b518de 30 | # commit hash date: 9 Jan 2018 31 | -------------------------------------------------------------------------------- /src/include/common/macros.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // macros.h 6 | // 7 | // Identification: src/include/common/macros.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | namespace bustub { 19 | 20 | #define BUSTUB_ASSERT(expr, message) assert((expr) && (message)) 21 | 22 | #define UNREACHABLE(message) throw std::logic_error(message) 23 | 24 | // Macros to disable copying and moving 25 | #define DISALLOW_COPY(cname) \ 26 | cname(const cname &) = delete; /* NOLINT */ \ 27 | cname &operator=(const cname &) = delete; /* NOLINT */ 28 | 29 | #define DISALLOW_MOVE(cname) \ 30 | cname(cname &&) = delete; /* NOLINT */ \ 31 | cname &operator=(cname &&) = delete; /* NOLINT */ 32 | 33 | #define DISALLOW_COPY_AND_MOVE(cname) \ 34 | DISALLOW_COPY(cname); \ 35 | DISALLOW_MOVE(cname); 36 | 37 | } // namespace bustub 38 | -------------------------------------------------------------------------------- /src/include/type/abstract_pool.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // abstract_pool.h 6 | // 7 | // Identification: src/include/type/abstract_pool.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | namespace bustub { 18 | 19 | // Interface of a memory pool that can quickly allocate chunks of memory 20 | class AbstractPool { 21 | public: 22 | // Virtual destructor 23 | virtual ~AbstractPool() = default; 24 | 25 | /** 26 | * @brief Allocate a contiguous block of memory of the given size 27 | * @param size The size (in bytes) of memory to allocate 28 | * @return A non-null pointer if allocation is successful. A null pointer if 29 | * allocation fails. 30 | * 31 | * TODO: Provide good error codes for failure cases 32 | */ 33 | virtual void *Allocate(size_t size) = 0; 34 | 35 | /** 36 | * @brief Returns the provided chunk of memory back into the pool 37 | */ 38 | virtual void Free(void *ptr) = 0; 39 | }; 40 | 41 | } // namespace bustub 42 | -------------------------------------------------------------------------------- /src/recovery/log_recovery.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // log_recovery.cpp 6 | // 7 | // Identification: src/recovery/log_recovery.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "recovery/log_recovery.h" 14 | 15 | #include "storage/page/table_page.h" 16 | 17 | namespace bustub { 18 | /* 19 | * deserialize a log record from log buffer 20 | * @return: true means deserialize succeed, otherwise can't deserialize cause 21 | * incomplete log record 22 | */ 23 | bool LogRecovery::DeserializeLogRecord(const char *data, LogRecord *log_record) { return false; } 24 | 25 | /* 26 | *redo phase on TABLE PAGE level(table/table_page.h) 27 | *read log file from the beginning to end (you must prefetch log records into 28 | *log buffer to reduce unnecessary I/O operations), remember to compare page's 29 | *LSN with log_record's sequence number, and also build active_txn_ table & 30 | *lsn_mapping_ table 31 | */ 32 | void LogRecovery::Redo() {} 33 | 34 | /* 35 | *undo phase on TABLE PAGE level(table/table_page.h) 36 | *iterate through active txn map and undo each operation 37 | */ 38 | void LogRecovery::Undo() {} 39 | 40 | } // namespace bustub 41 | -------------------------------------------------------------------------------- /src/storage/page/hash_table_header_page.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // hash_table_header_page.cpp 6 | // 7 | // Identification: src/storage/page/hash_table_header_page.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "storage/page/hash_table_header_page.h" 14 | 15 | namespace bustub { 16 | page_id_t HashTableHeaderPage::GetBlockPageId(size_t index) { 17 | if (index >= next_ind_) 18 | return INVALID_PAGE_ID; 19 | return block_page_ids_[index]; 20 | } 21 | 22 | page_id_t HashTableHeaderPage::GetPageId() const { return page_id_; } 23 | 24 | void HashTableHeaderPage::SetPageId(bustub::page_id_t page_id) { page_id_ = page_id; } 25 | 26 | lsn_t HashTableHeaderPage::GetLSN() const { return lsn_; } 27 | 28 | void HashTableHeaderPage::SetLSN(lsn_t lsn) { lsn_ = lsn;} 29 | 30 | void HashTableHeaderPage::AddBlockPageId(page_id_t page_id) { 31 | block_page_ids_[next_ind_++] = page_id; 32 | } 33 | 34 | size_t HashTableHeaderPage::NumBlocks() { return next_ind_; } 35 | 36 | void HashTableHeaderPage::SetSize(size_t size) { size_ = size ;} 37 | 38 | size_t HashTableHeaderPage::GetSize() const { return size_; } 39 | 40 | } // namespace bustub 41 | -------------------------------------------------------------------------------- /src/include/storage/table/table_iterator.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // table_iterator.h 6 | // 7 | // Identification: src/include/storage/table/table_iterator.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | #include "common/rid.h" 18 | #include "concurrency/transaction.h" 19 | #include "storage/table/tuple.h" 20 | 21 | namespace bustub { 22 | 23 | class TableHeap; 24 | 25 | /** 26 | * TableIterator enables the sequential scan of a TableHeap. 27 | */ 28 | class TableIterator { 29 | friend class Cursor; 30 | 31 | public: 32 | TableIterator(TableHeap *table_heap, RID rid, Transaction *txn); 33 | 34 | ~TableIterator() { delete tuple_; } 35 | 36 | inline bool operator==(const TableIterator &itr) const { return tuple_->rid_.Get() == itr.tuple_->rid_.Get(); } 37 | 38 | inline bool operator!=(const TableIterator &itr) const { return !(*this == itr); } 39 | 40 | const Tuple &operator*(); 41 | 42 | Tuple *operator->(); 43 | 44 | TableIterator &operator++(); 45 | 46 | TableIterator operator++(int); 47 | 48 | private: 49 | TableHeap *table_heap_; 50 | Tuple *tuple_; 51 | Transaction *txn_; 52 | }; 53 | 54 | } // namespace bustub 55 | -------------------------------------------------------------------------------- /src/type/integer_parent_type.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // integer_parent_type.cpp 6 | // 7 | // Identification: src/type/integer_parent_type.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include 14 | #include 15 | 16 | #include "type/integer_parent_type.h" 17 | 18 | namespace bustub { 19 | IntegerParentType::IntegerParentType(TypeId type) : NumericType(type) {} 20 | 21 | Value IntegerParentType::Min(const Value &left, const Value &right) const { 22 | assert(left.CheckInteger()); 23 | assert(left.CheckComparable(right)); 24 | if (left.IsNull() || right.IsNull()) { 25 | return left.OperateNull(right); 26 | } 27 | 28 | if (left.CompareLessThan(right) == CmpBool::CmpTrue) { 29 | return left.Copy(); 30 | } 31 | return right.Copy(); 32 | } 33 | 34 | Value IntegerParentType::Max(const Value &left, const Value &right) const { 35 | assert(left.CheckInteger()); 36 | assert(left.CheckComparable(right)); 37 | if (left.IsNull() || right.IsNull()) { 38 | return left.OperateNull(right); 39 | } 40 | 41 | if (left.CompareGreaterThanEquals(right) == CmpBool::CmpTrue) { 42 | return left.Copy(); 43 | } 44 | return right.Copy(); 45 | } 46 | } // namespace bustub 47 | -------------------------------------------------------------------------------- /src/include/recovery/checkpoint_manager.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // checkpoint_manager.h 6 | // 7 | // Identification: src/include/recovery/checkpoint_manager.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include "buffer/buffer_pool_manager.h" 16 | #include "concurrency/transaction_manager.h" 17 | #include "recovery/log_manager.h" 18 | 19 | namespace bustub { 20 | 21 | /** 22 | * CheckpointManager creates consistent checkpoints by blocking all other transactions temporarily. 23 | */ 24 | class CheckpointManager { 25 | public: 26 | CheckpointManager(TransactionManager *transaction_manager, LogManager *log_manager, 27 | BufferPoolManager *buffer_pool_manager) 28 | : transaction_manager_(transaction_manager), 29 | log_manager_(log_manager), 30 | buffer_pool_manager_(buffer_pool_manager) {} 31 | 32 | ~CheckpointManager() = default; 33 | 34 | void BeginCheckpoint(); 35 | void EndCheckpoint(); 36 | 37 | private: 38 | TransactionManager *transaction_manager_ __attribute__((__unused__)); 39 | LogManager *log_manager_ __attribute__((__unused__)); 40 | BufferPoolManager *buffer_pool_manager_ __attribute__((__unused__)); 41 | }; 42 | 43 | } // namespace bustub 44 | -------------------------------------------------------------------------------- /src/include/execution/expressions/constant_value_expression.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // constant_value_expression.h 6 | // 7 | // Identification: src/include/expression/constant_value_expression.h 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | #include "execution/expressions/abstract_expression.h" 18 | 19 | namespace bustub { 20 | /** 21 | * ConstantValueExpression represents constants. 22 | */ 23 | class ConstantValueExpression : public AbstractExpression { 24 | public: 25 | /** Creates a new constant value expression wrapping the given value. */ 26 | explicit ConstantValueExpression(const Value &val) : AbstractExpression({}, val.GetTypeId()), val_(val) {} 27 | 28 | Value Evaluate(const Tuple *tuple, const Schema *schema) const override { return val_; } 29 | 30 | Value EvaluateJoin(const Tuple *left_tuple, const Schema *left_schema, const Tuple *right_tuple, 31 | const Schema *right_schema) const override { 32 | return val_; 33 | } 34 | 35 | Value EvaluateAggregate(const std::vector &group_bys, const std::vector &aggregates) const override { 36 | return val_; 37 | } 38 | 39 | private: 40 | Value val_; 41 | }; 42 | } // namespace bustub 43 | -------------------------------------------------------------------------------- /test/common/rwlatch_test.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // rwlatch_test.cpp 6 | // 7 | // Identification: test/common/rwlatch_test.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include // NOLINT 14 | #include 15 | 16 | #include "common/rwlatch.h" 17 | #include "gtest/gtest.h" 18 | 19 | namespace bustub { 20 | 21 | class Counter { 22 | public: 23 | Counter() = default; 24 | void Add(int num) { 25 | mutex.WLock(); 26 | count_ += num; 27 | mutex.WUnlock(); 28 | } 29 | int Read() { 30 | int res; 31 | mutex.RLock(); 32 | res = count_; 33 | mutex.RUnlock(); 34 | return res; 35 | } 36 | 37 | private: 38 | int count_{0}; 39 | ReaderWriterLatch mutex{}; 40 | }; 41 | 42 | // NOLINTNEXTLINE 43 | TEST(RWLatchTest, BasicTest) { 44 | int num_threads = 100; 45 | Counter counter{}; 46 | counter.Add(5); 47 | std::vector threads; 48 | for (int tid = 0; tid < num_threads; tid++) { 49 | if (tid % 2 == 0) { 50 | threads.emplace_back([&counter]() { counter.Read(); }); 51 | } else { 52 | threads.emplace_back([&counter]() { counter.Add(1); }); 53 | } 54 | } 55 | for (int i = 0; i < num_threads; i++) { 56 | threads[i].join(); 57 | } 58 | EXPECT_EQ(counter.Read(), 55); 59 | } 60 | } // namespace bustub 61 | -------------------------------------------------------------------------------- /src/include/buffer/replacer.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // replacer.h 6 | // 7 | // Identification: src/include/buffer/replacer.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include "common/config.h" 16 | 17 | namespace bustub { 18 | 19 | /** 20 | * Replacer is an abstract class that tracks page usage. 21 | */ 22 | class Replacer { 23 | public: 24 | Replacer() = default; 25 | virtual ~Replacer() = default; 26 | 27 | /** 28 | * Remove the victim frame as defined by the replacement policy. 29 | * @param[out] frame_id id of frame that was removed, nullptr if no victim was found 30 | * @return true if a victim frame was found, false otherwise 31 | */ 32 | virtual bool Victim(frame_id_t *frame_id) = 0; 33 | 34 | /** 35 | * Pins a frame, indicating that it should not be victimized until it is unpinned. 36 | * @param frame_id the id of the frame to pin 37 | */ 38 | virtual void Pin(frame_id_t frame_id) = 0; 39 | 40 | /** 41 | * Unpins a frame, indicating that it can now be victimized. 42 | * @param frame_id the id of the frame to unpin 43 | */ 44 | virtual void Unpin(frame_id_t frame_id) = 0; 45 | 46 | /** @return the number of elements in the replacer that can be victimized */ 47 | virtual size_t Size() = 0; 48 | }; 49 | 50 | } // namespace bustub 51 | -------------------------------------------------------------------------------- /src/include/buffer/clock_replacer.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // clock_replacer.h 6 | // 7 | // Identification: src/include/buffer/clock_replacer.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include // NOLINT 17 | #include 18 | 19 | #include "buffer/replacer.h" 20 | #include "common/config.h" 21 | 22 | namespace bustub { 23 | 24 | /** 25 | * ClockReplacer implements the clock replacement policy, which approximates the Least Recently Used policy. 26 | */ 27 | class ClockReplacer : public Replacer { 28 | public: 29 | /** 30 | * Create a new ClockReplacer. 31 | * @param num_pages the maximum number of pages the ClockReplacer will be required to store 32 | */ 33 | explicit ClockReplacer(size_t num_pages); 34 | 35 | /** 36 | * Destroys the ClockReplacer. 37 | */ 38 | ~ClockReplacer() override; 39 | 40 | bool Victim(frame_id_t *frame_id) override; 41 | 42 | void Pin(frame_id_t frame_id) override; 43 | 44 | void Unpin(frame_id_t frame_id) override; 45 | 46 | size_t Size() override; 47 | 48 | private: 49 | // TODO(student): implement me! 50 | struct ClockItem { 51 | bool isPin; 52 | bool ref; 53 | }; 54 | 55 | std::vector clock_replacer; 56 | size_t clock_hand; 57 | size_t clock_size; 58 | std::mutex clock_mutex; 59 | }; 60 | 61 | } // namespace bustub 62 | -------------------------------------------------------------------------------- /test/catalog/catalog_test.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // catalog_test.cpp 6 | // 7 | // Identification: test/catalog/catalog_test.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "buffer/buffer_pool_manager.h" 18 | #include "catalog/simple_catalog.h" 19 | #include "gtest/gtest.h" 20 | #include "type/value_factory.h" 21 | 22 | namespace bustub { 23 | 24 | // NOLINTNEXTLINE 25 | TEST(CatalogTest, CreateTableTest) { 26 | auto disk_manager = new DiskManager("catalog_test.db"); 27 | auto bpm = new BufferPoolManager(32, disk_manager); 28 | auto catalog = new SimpleCatalog(bpm, nullptr, nullptr); 29 | std::string table_name = "potato"; 30 | 31 | // The table shouldn't exist in the catalog yet. 32 | EXPECT_THROW(catalog->GetTable(table_name), std::out_of_range); 33 | 34 | // Put the table into the catalog. 35 | std::vector columns; 36 | columns.emplace_back("A", TypeId::INTEGER); 37 | columns.emplace_back("B", TypeId::BOOLEAN); 38 | 39 | Schema schema(columns); 40 | auto *table_metadata = catalog->CreateTable(nullptr, table_name, schema); 41 | (void)table_metadata; 42 | 43 | // Notice that this test case doesn't check anything! :( 44 | // It is up to you to extend it 45 | 46 | delete catalog; 47 | delete bpm; 48 | delete disk_manager; 49 | } 50 | 51 | } // namespace bustub 52 | -------------------------------------------------------------------------------- /src/include/storage/index/linear_probe_hash_table_index.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // linear_probe_hash_table_index.h 6 | // 7 | // Identification: src/include/storage/index/linear_probe_hash_table_index.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "container/hash/hash_function.h" 20 | #include "container/hash/linear_probe_hash_table.h" 21 | #include "storage/index/index.h" 22 | 23 | namespace bustub { 24 | 25 | #define HASH_TABLE_INDEX_TYPE LinearProbeHashTableIndex 26 | 27 | template 28 | class LinearProbeHashTableIndex : public Index { 29 | public: 30 | LinearProbeHashTableIndex(IndexMetadata *metadata, BufferPoolManager *buffer_pool_manager, size_t num_buckets, 31 | const HashFunction &hash_fn); 32 | 33 | ~LinearProbeHashTableIndex() override = default; 34 | 35 | void InsertEntry(const Tuple &key, RID rid, Transaction *transaction) override; 36 | 37 | void DeleteEntry(const Tuple &key, RID rid, Transaction *transaction) override; 38 | 39 | void ScanKey(const Tuple &key, std::vector *result, Transaction *transaction) override; 40 | 41 | protected: 42 | // comparator for key 43 | KeyComparator comparator_; 44 | // container 45 | LinearProbeHashTable container_; 46 | }; 47 | 48 | } // namespace bustub 49 | -------------------------------------------------------------------------------- /src/catalog/schema.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // schema.cpp 6 | // 7 | // Identification: src/catalog/schema.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "catalog/schema.h" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | namespace bustub { 20 | 21 | Schema::Schema(const std::vector &columns) : tuple_is_inlined_(true) { 22 | uint32_t curr_offset = 0; 23 | for (uint32_t index = 0; index < columns.size(); index++) { 24 | Column column = columns[index]; 25 | // handle uninlined column 26 | if (!column.IsInlined()) { 27 | tuple_is_inlined_ = false; 28 | uninlined_columns_.push_back(index); 29 | } 30 | // set column offset 31 | column.column_offset_ = curr_offset; 32 | curr_offset += column.GetFixedLength(); 33 | 34 | // add column 35 | this->columns_.push_back(column); 36 | } 37 | // set tuple length 38 | length_ = curr_offset; 39 | } 40 | 41 | std::string Schema::ToString() const { 42 | std::ostringstream os; 43 | 44 | os << "Schema[" 45 | << "NumColumns:" << GetColumnCount() << ", " 46 | << "IsInlined:" << tuple_is_inlined_ << ", " 47 | << "Length:" << length_ << "]"; 48 | 49 | bool first = true; 50 | os << " :: ("; 51 | for (uint32_t i = 0; i < GetColumnCount(); i++) { 52 | if (first) { 53 | first = false; 54 | } else { 55 | os << ", "; 56 | } 57 | os << columns_[i].ToString(); 58 | } 59 | os << ")"; 60 | 61 | return os.str(); 62 | } 63 | 64 | } // namespace bustub 65 | -------------------------------------------------------------------------------- /src/include/recovery/log_recovery.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // log_recovery.h 6 | // 7 | // Identification: src/include/recovery/log_recovery.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include // NOLINT 17 | #include 18 | 19 | #include "buffer/buffer_pool_manager.h" 20 | #include "concurrency/lock_manager.h" 21 | #include "recovery/log_record.h" 22 | 23 | namespace bustub { 24 | 25 | /** 26 | * Read log file from disk, redo and undo. 27 | */ 28 | class LogRecovery { 29 | public: 30 | LogRecovery(DiskManager *disk_manager, BufferPoolManager *buffer_pool_manager) 31 | : disk_manager_(disk_manager), buffer_pool_manager_(buffer_pool_manager), offset_(0) { 32 | log_buffer_ = new char[LOG_BUFFER_SIZE]; 33 | } 34 | 35 | ~LogRecovery() { 36 | delete[] log_buffer_; 37 | log_buffer_ = nullptr; 38 | } 39 | 40 | void Redo(); 41 | void Undo(); 42 | bool DeserializeLogRecord(const char *data, LogRecord *log_record); 43 | 44 | private: 45 | DiskManager *disk_manager_ __attribute__((__unused__)); 46 | BufferPoolManager *buffer_pool_manager_ __attribute__((__unused__)); 47 | 48 | /** Maintain active transactions and its corresponding latest lsn. */ 49 | std::unordered_map active_txn_; 50 | /** Mapping the log sequence number to log file offset for undos. */ 51 | std::unordered_map lsn_mapping_; 52 | 53 | int offset_ __attribute__((__unused__)); 54 | char *log_buffer_; 55 | }; 56 | 57 | } // namespace bustub 58 | -------------------------------------------------------------------------------- /src/recovery/log_manager.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // log_manager.cpp 6 | // 7 | // Identification: src/recovery/log_manager.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "recovery/log_manager.h" 14 | 15 | namespace bustub { 16 | /* 17 | * set enable_logging = true 18 | * Start a separate thread to execute flush to disk operation periodically 19 | * The flush can be triggered when the log buffer is full or buffer pool 20 | * manager wants to force flush (it only happens when the flushed page has a 21 | * larger LSN than persistent LSN) 22 | */ 23 | void LogManager::RunFlushThread() {} 24 | 25 | /* 26 | * Stop and join the flush thread, set enable_logging = false 27 | */ 28 | void LogManager::StopFlushThread() {} 29 | 30 | /* 31 | * append a log record into log buffer 32 | * you MUST set the log record's lsn within this method 33 | * @return: lsn that is assigned to this log record 34 | * 35 | * 36 | * example below 37 | * // First, serialize the must have fields(20 bytes in total) 38 | * log_record.lsn_ = next_lsn_++; 39 | * memcpy(log_buffer_ + offset_, &log_record, 20); 40 | * int pos = offset_ + 20; 41 | * 42 | * if (log_record.log_record_type_ == LogRecordType::INSERT) { 43 | * memcpy(log_buffer_ + pos, &log_record.insert_rid_, sizeof(RID)); 44 | * pos += sizeof(RID); 45 | * // we have provided serialize function for tuple class 46 | * log_record.insert_tuple_.SerializeTo(log_buffer_ + pos); 47 | * } 48 | * 49 | */ 50 | lsn_t LogManager::AppendLogRecord(LogRecord *log_record) { return INVALID_LSN; } 51 | 52 | } // namespace bustub 53 | -------------------------------------------------------------------------------- /src/include/execution/executors/abstract_executor.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // abstract_executor.h 6 | // 7 | // Identification: src/include/execution/executors/abstract_executor.h 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include "execution/executor_context.h" 16 | #include "storage/table/tuple.h" 17 | 18 | namespace bustub { 19 | /** 20 | * AbstractExecutor implements the Volcano tuple-at-a-time iterator model. 21 | */ 22 | class AbstractExecutor { 23 | public: 24 | /** 25 | * Constructs a new AbstractExecutor. 26 | * @param exec_ctx the executor context that the executor runs with 27 | */ 28 | explicit AbstractExecutor(ExecutorContext *exec_ctx) : exec_ctx_{exec_ctx} {} 29 | 30 | /** Virtual destructor. */ 31 | virtual ~AbstractExecutor() = default; 32 | 33 | /** 34 | * Initializes this executor. 35 | * @warning This function must be called before Next() is called! 36 | */ 37 | virtual void Init() = 0; 38 | 39 | /** 40 | * Produces the next tuple from this executor. 41 | * @param[out] tuple the next tuple produced by this executor 42 | * @return true if a tuple was produced, false if there are no more tuples 43 | */ 44 | virtual bool Next(Tuple *tuple) = 0; 45 | 46 | /** @return the schema of the tuples that this executor produces */ 47 | virtual const Schema *GetOutputSchema() = 0; 48 | 49 | /** @return the executor context in which this executor runs */ 50 | ExecutorContext *GetExecutorContext() { return exec_ctx_; } 51 | 52 | protected: 53 | ExecutorContext *exec_ctx_; 54 | }; 55 | } // namespace bustub 56 | -------------------------------------------------------------------------------- /src/include/type/numeric_type.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // numeric_type.h 6 | // 7 | // Identification: src/include/type/numeric_type.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | #include 15 | 16 | #include "type/value.h" 17 | 18 | namespace bustub { 19 | // A numeric value is an abstract type representing a number. Numerics can be 20 | // either integral or non-integral (decimal), but must provide arithmetic 21 | // operations on its value. 22 | class NumericType : public Type { 23 | public: 24 | explicit NumericType(TypeId type) : Type(type) {} 25 | ~NumericType() override = default; 26 | 27 | // Other mathematical functions 28 | Value Add(const Value &left, const Value &right) const override = 0; 29 | Value Subtract(const Value &left, const Value &right) const override = 0; 30 | Value Multiply(const Value &left, const Value &right) const override = 0; 31 | Value Divide(const Value &left, const Value &right) const override = 0; 32 | Value Modulo(const Value &left, const Value &right) const override = 0; 33 | Value Min(const Value &left, const Value &right) const override = 0; 34 | Value Max(const Value &left, const Value &right) const override = 0; 35 | Value Sqrt(const Value &val) const override = 0; 36 | Value OperateNull(const Value &left, const Value &right) const override = 0; 37 | bool IsZero(const Value &val) const override = 0; 38 | 39 | protected: 40 | static inline double ValMod(double x, double y) { 41 | return x - std::trunc(static_cast(x) / static_cast(y)) * y; 42 | } 43 | }; 44 | } // namespace bustub 45 | -------------------------------------------------------------------------------- /test/storage/tmp_tuple_page_test.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // tmp_tuple_page_test.cpp 6 | // 7 | // Identification: test/storage/tmp_tuple_page_test.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include 14 | 15 | #include "gtest/gtest.h" 16 | #include "storage/page/tmp_tuple_page.h" 17 | #include "type/value_factory.h" 18 | 19 | namespace bustub { 20 | 21 | // NOLINTNEXTLINE 22 | TEST(TmpTuplePageTest, DISABLED_BasicTest) { 23 | // There are many ways to do this assignment, and this is only one of them. 24 | // If you don't like the TmpTuplePage idea, please feel free to delete this test case entirely. 25 | // You will get full credit as long as you are correctly using a linear probe hash table. 26 | 27 | TmpTuplePage page{}; 28 | page_id_t page_id = 15445; 29 | page.Init(page_id, PAGE_SIZE); 30 | 31 | char *data = page.GetData(); 32 | ASSERT_EQ(*reinterpret_cast(data), page_id); 33 | ASSERT_EQ(*reinterpret_cast(data + sizeof(page_id_t) + sizeof(lsn_t)), PAGE_SIZE); 34 | 35 | std::vector columns; 36 | columns.emplace_back("A", TypeId::INTEGER); 37 | Schema schema(columns); 38 | 39 | std::vector values; 40 | values.emplace_back(ValueFactory::GetIntegerValue(123)); 41 | 42 | Tuple tuple(values, &schema); 43 | TmpTuple tmp_tuple(INVALID_PAGE_ID, 0); 44 | page.Insert(tuple, &tmp_tuple); 45 | 46 | ASSERT_EQ(*reinterpret_cast(data + sizeof(page_id_t) + sizeof(lsn_t)), PAGE_SIZE - 8); 47 | ASSERT_EQ(*reinterpret_cast(data + PAGE_SIZE - 8), 4); 48 | ASSERT_EQ(*reinterpret_cast(data + PAGE_SIZE - 4), 123); 49 | } 50 | 51 | } // namespace bustub 52 | -------------------------------------------------------------------------------- /test/buffer/clock_replacer_test.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // clock_replacer_test.cpp 6 | // 7 | // Identification: test/buffer/clock_replacer_test.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include 14 | #include // NOLINT 15 | #include 16 | 17 | #include "buffer/clock_replacer.h" 18 | #include "gtest/gtest.h" 19 | 20 | namespace bustub { 21 | 22 | TEST(ClockReplacerTest, SampleTest) { 23 | ClockReplacer clock_replacer(7); 24 | 25 | // Scenario: unpin six elements, i.e. add them to the replacer. 26 | clock_replacer.Unpin(1); 27 | clock_replacer.Unpin(2); 28 | clock_replacer.Unpin(3); 29 | clock_replacer.Unpin(4); 30 | clock_replacer.Unpin(5); 31 | clock_replacer.Unpin(6); 32 | clock_replacer.Unpin(1); 33 | EXPECT_EQ(6, clock_replacer.Size()); 34 | 35 | // Scenario: get three victims from the clock. 36 | int value; 37 | clock_replacer.Victim(&value); 38 | EXPECT_EQ(1, value); 39 | clock_replacer.Victim(&value); 40 | EXPECT_EQ(2, value); 41 | clock_replacer.Victim(&value); 42 | EXPECT_EQ(3, value); 43 | 44 | // Scenario: pin elements in the replacer. 45 | // Note that 3 has already been victimized, so pinning 3 should have no effect. 46 | clock_replacer.Pin(3); 47 | clock_replacer.Pin(4); 48 | EXPECT_EQ(2, clock_replacer.Size()); 49 | 50 | // Scenario: unpin 4. We expect that the reference bit of 4 will be set to 1. 51 | clock_replacer.Unpin(4); 52 | 53 | // Scenario: continue looking for victims. We expect these victims. 54 | clock_replacer.Victim(&value); 55 | EXPECT_EQ(5, value); 56 | clock_replacer.Victim(&value); 57 | EXPECT_EQ(6, value); 58 | clock_replacer.Victim(&value); 59 | EXPECT_EQ(4, value); 60 | } 61 | 62 | } // namespace bustub 63 | -------------------------------------------------------------------------------- /src/include/execution/plans/seq_scan_plan.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // seq_scan_plan.h 6 | // 7 | // Identification: src/include/execution/plans/seq_scan_plan.h 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include "catalog/simple_catalog.h" 16 | #include "execution/expressions/abstract_expression.h" 17 | #include "execution/plans/abstract_plan.h" 18 | 19 | namespace bustub { 20 | /** 21 | * SeqScanPlanNode identifies a table that should be scanned with an optional predicate. 22 | */ 23 | class SeqScanPlanNode : public AbstractPlanNode { 24 | public: 25 | /** 26 | * Creates a new sequential scan plan node. 27 | * @param output the output format of this scan plan node 28 | * @param predicate the predicate to scan with, tuples are returned if predicate(tuple) = true or predicate = nullptr 29 | * @param table_oid the identifier of table to be scanned 30 | */ 31 | SeqScanPlanNode(const Schema *output, const AbstractExpression *predicate, table_oid_t table_oid) 32 | : AbstractPlanNode(output, {}), predicate_{predicate}, table_oid_(table_oid) {} 33 | 34 | PlanType GetType() const override { return PlanType::SeqScan; } 35 | 36 | /** @return the predicate to test tuples against; tuples should only be returned if they evaluate to true */ 37 | const AbstractExpression *GetPredicate() const { return predicate_; } 38 | 39 | /** @return the identifier of the table that should be scanned */ 40 | table_oid_t GetTableOid() const { return table_oid_; } 41 | 42 | private: 43 | /** The predicate that all returned tuples must satisfy. */ 44 | const AbstractExpression *predicate_; 45 | /** The table whose tuples should be scanned. */ 46 | table_oid_t table_oid_; 47 | }; 48 | 49 | } // namespace bustub 50 | -------------------------------------------------------------------------------- /src/include/container/hash/hash_table.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // hash_table.h 6 | // 7 | // Identification: src/include/container/hash/hash_table.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "concurrency/transaction.h" 20 | #include "storage/page/hash_table_page_defs.h" 21 | 22 | namespace bustub { 23 | 24 | template 25 | class HashTable { 26 | public: 27 | virtual ~HashTable() = default; 28 | 29 | /** 30 | * Inserts a key-value pair into the hash table. 31 | * @param transaction the current transaction 32 | * @param key the key to create 33 | * @param value the value to be associated with the key 34 | * @return true if insert succeeded, false otherwise 35 | */ 36 | virtual bool Insert(Transaction *transaction, const KeyType &key, const ValueType &value) = 0; 37 | 38 | /** 39 | * Deletes the associated value for the given key. 40 | * @param transaction the current transaction 41 | * @param key the key to delete 42 | * @param value the value to delete 43 | * @return true if remove succeeded, false otherwise 44 | */ 45 | virtual bool Remove(Transaction *transaction, const KeyType &key, const ValueType &value) = 0; 46 | 47 | /** 48 | * Performs a point query on the hash table. 49 | * @param transaction the current transaction 50 | * @param key the key to look up 51 | * @param[out] result the value(s) associated with a given key 52 | * @return the value(s) associated with the given key 53 | */ 54 | virtual bool GetValue(Transaction *transaction, const KeyType &key, std::vector *result) = 0; 55 | }; 56 | 57 | } // namespace bustub 58 | -------------------------------------------------------------------------------- /src/include/type/boolean_type.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // boolean_type.h 6 | // 7 | // Identification: src/include/type/boolean_type.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | #include 15 | #include "common/exception.h" 16 | #include "type/type.h" 17 | #include "type/value.h" 18 | 19 | namespace bustub { 20 | // A boolean value isn't a real SQL type, but we treat it as one to keep 21 | // consistent in the expression subsystem. 22 | class BooleanType : public Type { 23 | public: 24 | ~BooleanType() override = default; 25 | BooleanType(); 26 | 27 | // Comparison functions 28 | CmpBool CompareEquals(const Value &left, const Value &right) const override; 29 | CmpBool CompareNotEquals(const Value &left, const Value &right) const override; 30 | CmpBool CompareLessThan(const Value &left, const Value &right) const override; 31 | CmpBool CompareLessThanEquals(const Value &left, const Value &right) const override; 32 | CmpBool CompareGreaterThan(const Value &left, const Value &right) const override; 33 | CmpBool CompareGreaterThanEquals(const Value &left, const Value &right) const override; 34 | 35 | // Decimal types are always inlined 36 | bool IsInlined(const Value &val) const override { return true; } 37 | 38 | // Debug 39 | std::string ToString(const Value &val) const override; 40 | 41 | // Serialize this value into the given storage space 42 | void SerializeTo(const Value &val, char *storage) const override; 43 | 44 | // Deserialize a value of the given type from the given storage space. 45 | Value DeserializeFrom(const char *storage) const override; 46 | 47 | // Create a copy of this value 48 | Value Copy(const Value &val) const override; 49 | 50 | Value CastAs(const Value &val, TypeId type_id) const override; 51 | }; 52 | } // namespace bustub 53 | -------------------------------------------------------------------------------- /src/include/execution/expressions/aggregate_value_expression.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // aggregate_value_expression.h 6 | // 7 | // Identification: src/include/expression/aggregate_value_expression.h 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | #include "catalog/schema.h" 18 | #include "execution/expressions/abstract_expression.h" 19 | #include "storage/table/tuple.h" 20 | 21 | namespace bustub { 22 | /** 23 | * AggregateValueExpression represents aggregations such as MAX(a), MIN(b), COUNT(c) 24 | */ 25 | class AggregateValueExpression : public AbstractExpression { 26 | public: 27 | /** 28 | * Creates a new AggregateValueExpression. 29 | * @param is_group_by_term true if this is a group by 30 | * @param term_idx the index of the term 31 | * @param ret_type the return type of the aggregate value expression 32 | */ 33 | AggregateValueExpression(bool is_group_by_term, uint32_t term_idx, TypeId ret_type) 34 | : AbstractExpression({}, ret_type), is_group_by_term_{is_group_by_term}, term_idx_{term_idx} {} 35 | 36 | Value Evaluate(const Tuple *tuple, const Schema *schema) const override { 37 | BUSTUB_ASSERT(false, "Aggregation should only refer to group-by and aggregates."); 38 | } 39 | 40 | Value EvaluateJoin(const Tuple *left_tuple, const Schema *left_schema, const Tuple *right_tuple, 41 | const Schema *right_schema) const override { 42 | BUSTUB_ASSERT(false, "Aggregation should only refer to group-by and aggregates."); 43 | } 44 | 45 | Value EvaluateAggregate(const std::vector &group_bys, const std::vector &aggregates) const override { 46 | return is_group_by_term_ ? group_bys[term_idx_] : aggregates[term_idx_]; 47 | } 48 | 49 | private: 50 | bool is_group_by_term_; 51 | uint32_t term_idx_; 52 | }; 53 | } // namespace bustub 54 | -------------------------------------------------------------------------------- /src/include/execution/executors/seq_scan_executor.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // seq_scan_executor.h 6 | // 7 | // Identification: src/include/execution/executors/seq_scan_executor.h 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | #include "execution/executor_context.h" 18 | #include "execution/executors/abstract_executor.h" 19 | #include "execution/plans/seq_scan_plan.h" 20 | #include "storage/table/tuple.h" 21 | 22 | namespace bustub { 23 | 24 | /** 25 | * SeqScanExecutor executes a sequential scan over a table. 26 | */ 27 | class SeqScanExecutor : public AbstractExecutor { 28 | public: 29 | /** 30 | * Creates a new sequential scan executor. 31 | * @param exec_ctx the executor context 32 | * @param plan the sequential scan plan to be executed 33 | */ 34 | SeqScanExecutor(ExecutorContext *exec_ctx, const SeqScanPlanNode *plan) 35 | : AbstractExecutor(exec_ctx), plan_{plan} {} 36 | 37 | void Init() override { 38 | table_info_ = exec_ctx_->GetCatalog()->GetTable(plan_->GetTableOid()); 39 | table_iter_ = static_cast>(new TableIterator{table_info_->table_->Begin(exec_ctx_->GetTransaction())}); 40 | } 41 | 42 | bool Next(Tuple *tuple) override { 43 | while (*table_iter_ != table_info_->table_->End()) { 44 | *tuple = **table_iter_; 45 | ++(*table_iter_); 46 | if (!plan_->GetPredicate() || plan_->GetPredicate()->Evaluate(tuple, &table_info_->schema_).GetAs()) return true; 47 | } 48 | return false; 49 | } 50 | 51 | const Schema *GetOutputSchema() override { return plan_->OutputSchema(); } 52 | 53 | private: 54 | /** The sequential scan plan node to be executed. */ 55 | const SeqScanPlanNode *plan_; 56 | const TableMetadata* table_info_; 57 | std::unique_ptr table_iter_; 58 | }; 59 | } // namespace bustub 60 | -------------------------------------------------------------------------------- /src/include/common/bustub_instance.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // bustub_instance.h 6 | // 7 | // Identification: src/include/common/bustub_instance.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include 14 | 15 | #include "buffer/buffer_pool_manager.h" 16 | #include "common/config.h" 17 | #include "concurrency/lock_manager.h" 18 | #include "recovery/checkpoint_manager.h" 19 | #include "recovery/log_manager.h" 20 | #include "storage/disk/disk_manager.h" 21 | 22 | namespace bustub { 23 | 24 | class BustubInstance { 25 | public: 26 | explicit BustubInstance(const std::string &db_file_name) { 27 | enable_logging = false; 28 | 29 | // storage related 30 | disk_manager_ = new DiskManager(db_file_name); 31 | 32 | // log related 33 | log_manager_ = new LogManager(disk_manager_); 34 | 35 | buffer_pool_manager_ = new BufferPoolManager(BUFFER_POOL_SIZE, disk_manager_, log_manager_); 36 | 37 | // txn related 38 | lock_manager_ = new LockManager(TwoPLMode::STRICT, DeadlockMode::PREVENTION); // S2PL 39 | transaction_manager_ = new TransactionManager(lock_manager_, log_manager_); 40 | 41 | // checkpoints 42 | checkpoint_manager_ = new CheckpointManager(transaction_manager_, log_manager_, buffer_pool_manager_); 43 | } 44 | 45 | ~BustubInstance() { 46 | if (enable_logging) { 47 | log_manager_->StopFlushThread(); 48 | } 49 | delete checkpoint_manager_; 50 | delete log_manager_; 51 | delete buffer_pool_manager_; 52 | delete lock_manager_; 53 | delete transaction_manager_; 54 | delete disk_manager_; 55 | } 56 | 57 | DiskManager *disk_manager_; 58 | BufferPoolManager *buffer_pool_manager_; 59 | LockManager *lock_manager_; 60 | TransactionManager *transaction_manager_; 61 | LogManager *log_manager_; 62 | CheckpointManager *checkpoint_manager_; 63 | }; 64 | 65 | } // namespace bustub 66 | -------------------------------------------------------------------------------- /src/buffer/clock_replacer.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // clock_replacer.cpp 6 | // 7 | // Identification: src/buffer/clock_replacer.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "buffer/clock_replacer.h" 14 | 15 | namespace bustub { 16 | 17 | ClockReplacer::ClockReplacer(size_t num_pages) { 18 | ClockItem clock_item = {true, false}; 19 | for (size_t i = 0; i != num_pages; ++i) { 20 | clock_replacer.emplace_back(clock_item); 21 | } 22 | clock_hand = 0; 23 | clock_size = 0; 24 | } 25 | 26 | ClockReplacer::~ClockReplacer() = default; 27 | 28 | bool ClockReplacer::Victim(frame_id_t *frame_id) { 29 | std::scoped_lock clock_clk{clock_mutex}; 30 | while (clock_size > 0) { 31 | if (clock_hand == clock_replacer.size()) { 32 | clock_hand = 0; 33 | } 34 | 35 | if (clock_replacer[clock_hand].isPin) { 36 | clock_hand++; 37 | } else if (clock_replacer[clock_hand].ref == true) { 38 | clock_replacer[clock_hand].ref = false; 39 | clock_hand++; 40 | } else { 41 | clock_replacer[clock_hand].isPin = true; 42 | clock_size--; 43 | *frame_id = clock_hand++; 44 | return true; 45 | } 46 | } 47 | 48 | return false; 49 | } 50 | 51 | void ClockReplacer::Pin(frame_id_t frame_id) { 52 | std::scoped_lock clock_clk{clock_mutex}; 53 | if (clock_replacer[frame_id].isPin == false) { 54 | clock_replacer[frame_id].isPin = true; 55 | clock_size--; 56 | } 57 | } 58 | 59 | void ClockReplacer::Unpin(frame_id_t frame_id) { 60 | std::scoped_lock clock_clk{clock_mutex}; 61 | if (clock_replacer[frame_id].isPin == true) { 62 | clock_replacer[frame_id].isPin = false; 63 | clock_replacer[frame_id].ref = true; 64 | clock_size++; 65 | } 66 | } 67 | 68 | size_t ClockReplacer::Size() { 69 | std::scoped_lock clock_clk{clock_mutex}; 70 | return clock_size; 71 | } 72 | 73 | } // namespace bustub 74 | -------------------------------------------------------------------------------- /src/include/execution/executor_context.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // executor_context.h 6 | // 7 | // Identification: src/include/execution/executor_context.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "catalog/simple_catalog.h" 20 | #include "concurrency/transaction.h" 21 | #include "storage/page/tmp_tuple_page.h" 22 | 23 | namespace bustub { 24 | /** 25 | * ExecutorContext stores all the context necessary to run an executor. 26 | */ 27 | class ExecutorContext { 28 | public: 29 | /** 30 | * Creates an ExecutorContext for the transaction that is executing the query. 31 | * @param transaction the transaction executing the query 32 | * @param catalog the catalog that the executor should use 33 | * @param bpm the buffer pool manager that the executor should use 34 | */ 35 | ExecutorContext(Transaction *transaction, SimpleCatalog *catalog, BufferPoolManager *bpm) 36 | : transaction_(transaction), catalog_{catalog}, bpm_{bpm} {} 37 | 38 | DISALLOW_COPY_AND_MOVE(ExecutorContext); 39 | 40 | ~ExecutorContext() = default; 41 | 42 | /** @return the running transaction */ 43 | Transaction *GetTransaction() const { return transaction_; } 44 | 45 | /** @return the catalog */ 46 | SimpleCatalog *GetCatalog() { return catalog_; } 47 | 48 | /** @return the buffer pool manager */ 49 | BufferPoolManager *GetBufferPoolManager() { return bpm_; } 50 | 51 | /** @return the log manager - don't worry about it for now */ 52 | LogManager *GetLogManager() { return nullptr; } 53 | 54 | /** @return the lock manager - don't worry about it for now */ 55 | LockManager *GetLockManager() { return nullptr; } 56 | 57 | private: 58 | Transaction *transaction_; 59 | SimpleCatalog *catalog_; 60 | BufferPoolManager *bpm_; 61 | }; 62 | 63 | } // namespace bustub 64 | -------------------------------------------------------------------------------- /src/include/type/timestamp_type.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // timestamp_type.h 6 | // 7 | // Identification: src/include/type/timestamp_type.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include "type/abstract_pool.h" 17 | #include "type/value.h" 18 | 19 | namespace bustub { 20 | 21 | class TimestampType : public Type { 22 | public: 23 | static constexpr uint64_t K_USECS_PER_DATE = 86400000000UL; 24 | 25 | ~TimestampType() override = default; 26 | TimestampType(); 27 | 28 | // Comparison functions 29 | CmpBool CompareEquals(const Value &left, const Value &right) const override; 30 | CmpBool CompareNotEquals(const Value &left, const Value &right) const override; 31 | CmpBool CompareLessThan(const Value &left, const Value &right) const override; 32 | CmpBool CompareLessThanEquals(const Value &left, const Value &right) const override; 33 | CmpBool CompareGreaterThan(const Value &left, const Value &right) const override; 34 | CmpBool CompareGreaterThanEquals(const Value &left, const Value &right) const override; 35 | 36 | // Other mathematical functions 37 | Value Min(const Value &left, const Value &right) const override; 38 | Value Max(const Value &left, const Value &right) const override; 39 | 40 | bool IsInlined(const Value &val) const override { return true; } 41 | 42 | // Debug 43 | std::string ToString(const Value &val) const override; 44 | 45 | // Serialize this value into the given storage space 46 | void SerializeTo(const Value &val, char *storage) const override; 47 | 48 | // Deserialize a value of the given type from the given storage space. 49 | Value DeserializeFrom(const char *storage) const override; 50 | 51 | // Create a copy of this value 52 | Value Copy(const Value &val) const override; 53 | 54 | Value CastAs(const Value &val, TypeId type_id) const override; 55 | }; 56 | 57 | } // namespace bustub 58 | -------------------------------------------------------------------------------- /src/include/common/config.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // config.h 6 | // 7 | // Identification: src/include/common/config.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include // NOLINT 17 | #include 18 | 19 | namespace bustub { 20 | 21 | /** Cycle detection is performed every CYCLE_DETECTION_INTERVAL milliseconds. */ 22 | extern std::chrono::milliseconds cycle_detection_interval; 23 | 24 | /** True if logging should be enabled, false otherwise. */ 25 | extern std::atomic enable_logging; 26 | 27 | /** If ENABLE_LOGGING is true, the log should be flushed to disk every LOG_TIMEOUT. */ 28 | extern std::chrono::duration log_timeout; 29 | 30 | static constexpr int INVALID_PAGE_ID = -1; // invalid page id 31 | static constexpr int INVALID_TXN_ID = -1; // invalid transaction id 32 | static constexpr int INVALID_LSN = -1; // invalid log sequence number 33 | static constexpr int HEADER_PAGE_ID = 0; // the header page id 34 | static constexpr int PAGE_SIZE = 4096; // size of a data page in byte 35 | static constexpr int BUFFER_POOL_SIZE = 10; // size of buffer pool 36 | static constexpr int LOG_BUFFER_SIZE = ((BUFFER_POOL_SIZE + 1) * PAGE_SIZE); // size of a log buffer in byte 37 | static constexpr int BUCKET_SIZE = 50; // size of extendible hash bucket 38 | 39 | using frame_id_t = int32_t; // frame id type 40 | using page_id_t = int32_t; // page id type 41 | using txn_id_t = int32_t; // transaction id type 42 | using lsn_t = int32_t; // log sequence number type 43 | using slot_offset_t = size_t; // slot offset type 44 | using oid_t = uint16_t; 45 | 46 | } // namespace bustub 47 | -------------------------------------------------------------------------------- /src/concurrency/lock_manager.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // lock_manager.cpp 6 | // 7 | // Identification: src/concurrency/lock_manager.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "concurrency/lock_manager.h" 14 | 15 | #include 16 | #include 17 | 18 | namespace bustub { 19 | 20 | bool LockManager::LockShared(Transaction *txn, const RID &rid) { 21 | txn->GetSharedLockSet()->emplace(rid); 22 | return true; 23 | } 24 | 25 | bool LockManager::LockExclusive(Transaction *txn, const RID &rid) { 26 | txn->GetExclusiveLockSet()->emplace(rid); 27 | return true; 28 | } 29 | 30 | bool LockManager::LockUpgrade(Transaction *txn, const RID &rid) { 31 | txn->GetSharedLockSet()->erase(rid); 32 | txn->GetExclusiveLockSet()->emplace(rid); 33 | return true; 34 | } 35 | 36 | bool LockManager::Unlock(Transaction *txn, const RID &rid) { 37 | txn->GetSharedLockSet()->erase(rid); 38 | txn->GetExclusiveLockSet()->erase(rid); 39 | return true; 40 | } 41 | 42 | void LockManager::AddEdge(txn_id_t t1, txn_id_t t2) { assert(Detection()); } 43 | 44 | void LockManager::RemoveEdge(txn_id_t t1, txn_id_t t2) { assert(Detection()); } 45 | 46 | bool LockManager::HasCycle(txn_id_t *txn_id) { 47 | BUSTUB_ASSERT(Detection(), "Detection should be enabled!"); 48 | return false; 49 | } 50 | 51 | std::vector> LockManager::GetEdgeList() { 52 | BUSTUB_ASSERT(Detection(), "Detection should be enabled!"); 53 | return {}; 54 | } 55 | 56 | void LockManager::RunCycleDetection() { 57 | BUSTUB_ASSERT(Detection(), "Detection should be enabled!"); 58 | while (enable_cycle_detection_) { 59 | std::this_thread::sleep_for(cycle_detection_interval); 60 | { 61 | std::unique_lock l(latch_); 62 | // TODO(student): remove the continue and add your cycle detection and abort code here 63 | continue; 64 | } 65 | } 66 | } 67 | 68 | } // namespace bustub 69 | -------------------------------------------------------------------------------- /src/storage/index/linear_probe_hash_table_index.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "storage/index/linear_probe_hash_table_index.h" 4 | 5 | namespace bustub { 6 | /* 7 | * Constructor 8 | */ 9 | template 10 | HASH_TABLE_INDEX_TYPE::LinearProbeHashTableIndex(IndexMetadata *metadata, BufferPoolManager *buffer_pool_manager, 11 | size_t num_buckets, const HashFunction &hash_fn) 12 | : Index(metadata), 13 | comparator_(metadata->GetKeySchema()), 14 | container_(metadata->GetName(), buffer_pool_manager, comparator_, num_buckets, hash_fn) {} 15 | 16 | template 17 | void HASH_TABLE_INDEX_TYPE::InsertEntry(const Tuple &key, RID rid, Transaction *transaction) { 18 | // construct insert index key 19 | KeyType index_key; 20 | index_key.SetFromKey(key); 21 | 22 | container_.Insert(transaction, index_key, rid); 23 | } 24 | 25 | template 26 | void HASH_TABLE_INDEX_TYPE::DeleteEntry(const Tuple &key, RID rid, Transaction *transaction) { 27 | // construct delete index key 28 | KeyType index_key; 29 | index_key.SetFromKey(key); 30 | 31 | container_.Remove(transaction, index_key, rid); 32 | } 33 | 34 | template 35 | void HASH_TABLE_INDEX_TYPE::ScanKey(const Tuple &key, std::vector *result, Transaction *transaction) { 36 | // construct scan index key 37 | KeyType index_key; 38 | index_key.SetFromKey(key); 39 | 40 | container_.GetValue(transaction, index_key, result); 41 | } 42 | template class LinearProbeHashTableIndex, RID, GenericComparator<4>>; 43 | template class LinearProbeHashTableIndex, RID, GenericComparator<8>>; 44 | template class LinearProbeHashTableIndex, RID, GenericComparator<16>>; 45 | template class LinearProbeHashTableIndex, RID, GenericComparator<32>>; 46 | template class LinearProbeHashTableIndex, RID, GenericComparator<64>>; 47 | 48 | } // namespace bustub 49 | -------------------------------------------------------------------------------- /src/include/common/rid.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // rid.h 6 | // 7 | // Identification: src/include/common/rid.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "common/config.h" 20 | 21 | namespace bustub { 22 | 23 | class RID { 24 | public: 25 | /** The default constructor creates an invalid RID! */ 26 | RID() = default; 27 | 28 | /** 29 | * Creates a new Record Identifier for the given page identifier and slot number. 30 | * @param page_id page identifier 31 | * @param slot_num slot number 32 | */ 33 | RID(page_id_t page_id, uint32_t slot_num) : page_id_(page_id), slot_num_(slot_num) {} 34 | 35 | explicit RID(int64_t rid) : page_id_(static_cast(rid >> 32)), slot_num_(static_cast(rid)) {} 36 | 37 | inline int64_t Get() const { return (static_cast(page_id_)) << 32 | slot_num_; } 38 | 39 | inline page_id_t GetPageId() const { return page_id_; } 40 | 41 | inline uint32_t GetSlotNum() const { return slot_num_; } 42 | 43 | inline void Set(page_id_t page_id, uint32_t slot_num) { 44 | page_id_ = page_id; 45 | slot_num_ = slot_num; 46 | } 47 | 48 | inline std::string ToString() const { 49 | std::stringstream os; 50 | os << "page_id: " << page_id_; 51 | os << " slot_num: " << slot_num_ << "\n"; 52 | 53 | return os.str(); 54 | } 55 | 56 | friend std::ostream &operator<<(std::ostream &os, const RID &rid) { 57 | os << rid.ToString(); 58 | return os; 59 | } 60 | 61 | bool operator==(const RID &other) const { return page_id_ == other.page_id_ && slot_num_ == other.slot_num_; } 62 | 63 | private: 64 | page_id_t page_id_{INVALID_PAGE_ID}; 65 | uint32_t slot_num_{0}; // logical offset from 0, 1... 66 | }; 67 | 68 | } // namespace bustub 69 | 70 | namespace std { 71 | template <> 72 | struct hash { 73 | size_t operator()(const bustub::RID &obj) const { return hash()(obj.Get()); } 74 | }; 75 | } // namespace std 76 | -------------------------------------------------------------------------------- /src/include/execution/expressions/column_value_expression.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // column_value_expression.h 6 | // 7 | // Identification: src/include/expression/column_value_expression.h 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | #include "catalog/schema.h" 18 | #include "execution/expressions/abstract_expression.h" 19 | #include "storage/table/tuple.h" 20 | 21 | namespace bustub { 22 | /** 23 | * ColumnValueExpression maintains the tuple index and column index relative to a particular schema or join. 24 | */ 25 | class ColumnValueExpression : public AbstractExpression { 26 | public: 27 | /** 28 | * ColumnValueExpression is an abstraction around "Table.member" in terms of indexes. 29 | * @param tuple_idx {tuple index 0 = left side of join, tuple index 1 = right side of join} 30 | * @param col_idx the index of the column in the schema 31 | * @param ret_type the return type of the expression 32 | */ 33 | ColumnValueExpression(uint32_t tuple_idx, uint32_t col_idx, TypeId ret_type) 34 | : AbstractExpression({}, ret_type), tuple_idx_{tuple_idx}, col_idx_{col_idx} {} 35 | 36 | Value Evaluate(const Tuple *tuple, const Schema *schema) const override { return tuple->GetValue(schema, col_idx_); } 37 | 38 | Value EvaluateJoin(const Tuple *left_tuple, const Schema *left_schema, const Tuple *right_tuple, 39 | const Schema *right_schema) const override { 40 | return tuple_idx_ == 0 ? left_tuple->GetValue(left_schema, col_idx_) 41 | : right_tuple->GetValue(right_schema, col_idx_); 42 | } 43 | 44 | Value EvaluateAggregate(const std::vector &group_bys, const std::vector &aggregates) const override { 45 | BUSTUB_ASSERT(false, "Aggregation should only refer to group-by and aggregates."); 46 | } 47 | 48 | private: 49 | /** Tuple index 0 = left side of join, tuple index 1 = right side of join */ 50 | uint32_t tuple_idx_; 51 | /** Column index refers to the index within the schema of the tuple, e.g. schema {A,B,C} has indexes {0,1,2} */ 52 | uint32_t col_idx_; 53 | }; 54 | } // namespace bustub 55 | -------------------------------------------------------------------------------- /src/include/common/rwlatch.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // rwmutex.h 6 | // 7 | // Identification: src/include/common/rwlatch.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include // NOLINT 17 | #include // NOLINT 18 | 19 | #include "common/macros.h" 20 | 21 | namespace bustub { 22 | 23 | /** 24 | * Reader-Writer latch backed by std::mutex. 25 | */ 26 | class ReaderWriterLatch { 27 | using mutex_t = std::mutex; 28 | using cond_t = std::condition_variable; 29 | static const uint32_t MAX_READERS = UINT_MAX; 30 | 31 | public: 32 | ReaderWriterLatch() = default; 33 | ~ReaderWriterLatch() { std::lock_guard guard(mutex_); } 34 | 35 | DISALLOW_COPY(ReaderWriterLatch); 36 | 37 | /** 38 | * Acquire a write latch. 39 | */ 40 | void WLock() { 41 | std::unique_lock latch(mutex_); 42 | while (writer_entered_) { 43 | reader_.wait(latch); 44 | } 45 | writer_entered_ = true; 46 | while (reader_count_ > 0) { 47 | writer_.wait(latch); 48 | } 49 | } 50 | 51 | /** 52 | * Release a write latch. 53 | */ 54 | void WUnlock() { 55 | std::lock_guard guard(mutex_); 56 | writer_entered_ = false; 57 | reader_.notify_all(); 58 | } 59 | 60 | /** 61 | * Acquire a read latch. 62 | */ 63 | void RLock() { 64 | std::unique_lock latch(mutex_); 65 | while (writer_entered_ || reader_count_ == MAX_READERS) { 66 | reader_.wait(latch); 67 | } 68 | reader_count_++; 69 | } 70 | 71 | /** 72 | * Release a read latch. 73 | */ 74 | void RUnlock() { 75 | std::lock_guard guard(mutex_); 76 | reader_count_--; 77 | if (writer_entered_) { 78 | if (reader_count_ == 0) { 79 | writer_.notify_one(); 80 | } 81 | } else { 82 | if (reader_count_ == MAX_READERS - 1) { 83 | reader_.notify_one(); 84 | } 85 | } 86 | } 87 | 88 | private: 89 | mutex_t mutex_; 90 | cond_t writer_; 91 | cond_t reader_; 92 | uint32_t reader_count_{0}; 93 | bool writer_entered_{false}; 94 | }; 95 | 96 | } // namespace bustub 97 | -------------------------------------------------------------------------------- /src/include/recovery/log_manager.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // log_manager.h 6 | // 7 | // Identification: src/include/recovery/log_manager.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include // NOLINT 17 | #include // NOLINT 18 | #include // NOLINT 19 | 20 | #include "recovery/log_record.h" 21 | #include "storage/disk/disk_manager.h" 22 | 23 | namespace bustub { 24 | 25 | /** 26 | * LogManager maintains a separate thread that is awakened whenever the log buffer is full or whenever a timeout 27 | * happens. When the thread is awakened, the log buffer's content is written into the disk log file. 28 | */ 29 | class LogManager { 30 | public: 31 | explicit LogManager(DiskManager *disk_manager) 32 | : next_lsn_(0), persistent_lsn_(INVALID_LSN), disk_manager_(disk_manager) { 33 | log_buffer_ = new char[LOG_BUFFER_SIZE]; 34 | flush_buffer_ = new char[LOG_BUFFER_SIZE]; 35 | } 36 | 37 | ~LogManager() { 38 | delete[] log_buffer_; 39 | delete[] flush_buffer_; 40 | log_buffer_ = nullptr; 41 | flush_buffer_ = nullptr; 42 | } 43 | 44 | void RunFlushThread(); 45 | void StopFlushThread(); 46 | 47 | lsn_t AppendLogRecord(LogRecord *log_record); 48 | 49 | inline lsn_t GetNextLSN() { return next_lsn_; } 50 | inline lsn_t GetPersistentLSN() { return persistent_lsn_; } 51 | inline void SetPersistentLSN(lsn_t lsn) { persistent_lsn_ = lsn; } 52 | inline char *GetLogBuffer() { return log_buffer_; } 53 | 54 | private: 55 | // TODO(students): you may add your own member variables 56 | 57 | /** The atomic counter which records the next log sequence number. */ 58 | std::atomic next_lsn_; 59 | /** The log records before and including the persistent lsn have been written to disk. */ 60 | std::atomic persistent_lsn_; 61 | 62 | char *log_buffer_; 63 | char *flush_buffer_; 64 | 65 | std::mutex latch_; 66 | 67 | std::thread *flush_thread_ __attribute__((__unused__)); 68 | 69 | std::condition_variable cv_; 70 | 71 | DiskManager *disk_manager_ __attribute__((__unused__)); 72 | }; 73 | 74 | } // namespace bustub 75 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | language: cpp 3 | matrix: 4 | fast_finish: true 5 | include: 6 | - os: osx 7 | osx_image: xcode10.1 8 | compiler: clang 9 | env: 10 | - NAME="macos-10.14/AppleClang-1001.0.46.4 (Debug/packages.sh)" CMAKE_BUILD_TYPE=debug 11 | install: 12 | - echo 'y' | ./build_support/packages.sh 13 | - export LLVM_DIR=/usr/local/Cellar/llvm/8.0.1 14 | - os: linux 15 | dist: trusty 16 | env: 17 | - NAME="ubuntu-18.04/gcc-7.3.0 (Debug/packages.sh)" CMAKE_BUILD_TYPE=debug DOCKER=true 18 | install: 19 | - docker pull ubuntu:18.04 20 | - docker run -itd --name build ubuntu:18.04 21 | - docker cp . build:/repo 22 | - docker exec build /bin/sh -c "echo 'y' | /repo/build_support/packages.sh" 23 | - os: linux 24 | dist: trusty 25 | env: 26 | - NAME="ubuntu-18.04/gcc-7.3.0 (Debug/Dockerfile)" CMAKE_BUILD_TYPE=debug DOCKER=true 27 | install: 28 | - docker build -t cmu-db/bustub . 29 | - docker run -itd --name build cmu-db/bustub 30 | - docker cp . build:/repo 31 | - os: linux 32 | dist: trusty 33 | env: 34 | - NAME="ubuntu-18.04/clang-8.0.0 (Debug/Dockerfile)" CMAKE_BUILD_TYPE=debug DOCKER=true 35 | install: 36 | - docker build -t cmu-db/bustub . 37 | - docker run -itd -e "CC=/usr/bin/clang-8" -e "CXX=/usr/bin/clang++-8" --name build cmu-db/bustub 38 | - docker cp . build:/repo 39 | 40 | before_script: 41 | - if [[ "$DOCKER" = true ]]; then 42 | docker exec build /bin/sh -c "mkdir -p /repo/build" && 43 | docker exec -e CMAKE_BUILD_TYPE="$CMAKE_BUILD_TYPE" build /bin/sh -c "cd /repo/build && cmake -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE .." && 44 | docker exec build /bin/sh -c "cd /repo/build && make check-format" && 45 | docker exec build /bin/sh -c "cd /repo/build && make check-lint" && 46 | docker exec build /bin/sh -c "cd /repo/build && make check-clang-tidy" && 47 | docker exec build /bin/sh -c "cd /repo/build && make check-tests"; 48 | else 49 | mkdir build && 50 | cd build && 51 | cmake -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE .. && 52 | make check-lint && 53 | make check-tests; 54 | fi 55 | 56 | script: 57 | - if [[ "$DOCKER" = true ]]; then 58 | docker exec build /bin/sh -c "cd /repo/build && make -j4"; 59 | else 60 | make -j4; 61 | fi 62 | -------------------------------------------------------------------------------- /src/include/type/bigint_type.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // bigint_type.h 6 | // 7 | // Identification: src/include/type/bigint_type.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | #include 15 | #include "type/integer_parent_type.h" 16 | 17 | namespace bustub { 18 | // An integer value of the common sizes. 19 | class BigintType : public IntegerParentType { 20 | public: 21 | ~BigintType() override = default; 22 | 23 | BigintType(); 24 | 25 | // Other mathematical functions 26 | Value Add(const Value &left, const Value &right) const override; 27 | Value Subtract(const Value &left, const Value &right) const override; 28 | Value Multiply(const Value &left, const Value &right) const override; 29 | Value Divide(const Value &left, const Value &right) const override; 30 | Value Modulo(const Value &left, const Value &right) const override; 31 | Value Sqrt(const Value &val) const override; 32 | 33 | // Comparison functions 34 | CmpBool CompareEquals(const Value &left, const Value &right) const override; 35 | CmpBool CompareNotEquals(const Value &left, const Value &right) const override; 36 | CmpBool CompareLessThan(const Value &left, const Value &right) const override; 37 | CmpBool CompareLessThanEquals(const Value &left, const Value &right) const override; 38 | CmpBool CompareGreaterThan(const Value &left, const Value &right) const override; 39 | CmpBool CompareGreaterThanEquals(const Value &left, const Value &right) const override; 40 | 41 | Value CastAs(const Value &val, TypeId type_id) const override; 42 | 43 | // Debug 44 | std::string ToString(const Value &val) const override; 45 | 46 | // Serialize this value into the given storage space 47 | void SerializeTo(const Value &val, char *storage) const override; 48 | 49 | // Deserialize a value of the given type from the given storage space. 50 | Value DeserializeFrom(const char *storage) const override; 51 | 52 | // Create a copy of this value 53 | Value Copy(const Value &val) const override; 54 | 55 | protected: 56 | Value OperateNull(const Value &left, const Value &right) const override; 57 | 58 | bool IsZero(const Value &val) const override; 59 | }; 60 | } // namespace bustub 61 | -------------------------------------------------------------------------------- /src/include/type/tinyint_type.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // tinyint_type.h 6 | // 7 | // Identification: src/include/type/tinyint_type.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | #include 15 | #include "type/integer_parent_type.h" 16 | 17 | namespace bustub { 18 | // An integer value of the common sizes. 19 | class TinyintType : public IntegerParentType { 20 | public: 21 | ~TinyintType() override = default; 22 | 23 | TinyintType(); 24 | 25 | // Other mathematical functions 26 | Value Add(const Value &left, const Value &right) const override; 27 | Value Subtract(const Value &left, const Value &right) const override; 28 | Value Multiply(const Value &left, const Value &right) const override; 29 | Value Divide(const Value &left, const Value &right) const override; 30 | Value Modulo(const Value &left, const Value &right) const override; 31 | Value Sqrt(const Value &val) const override; 32 | 33 | // Comparison functions 34 | CmpBool CompareEquals(const Value &left, const Value &right) const override; 35 | CmpBool CompareNotEquals(const Value &left, const Value &right) const override; 36 | CmpBool CompareLessThan(const Value &left, const Value &right) const override; 37 | CmpBool CompareLessThanEquals(const Value &left, const Value &right) const override; 38 | CmpBool CompareGreaterThan(const Value &left, const Value &right) const override; 39 | CmpBool CompareGreaterThanEquals(const Value &left, const Value &right) const override; 40 | 41 | Value CastAs(const Value &val, TypeId type_id) const override; 42 | 43 | // Debug 44 | std::string ToString(const Value &val) const override; 45 | 46 | // Serialize this value into the given storage space 47 | void SerializeTo(const Value &val, char *storage) const override; 48 | 49 | // Deserialize a value of the given type from the given storage space. 50 | Value DeserializeFrom(const char *storage) const override; 51 | 52 | // Create a copy of this value 53 | Value Copy(const Value &val) const override; 54 | 55 | protected: 56 | Value OperateNull(const Value &left, const Value &right) const override; 57 | 58 | bool IsZero(const Value &val) const override; 59 | }; 60 | } // namespace bustub 61 | -------------------------------------------------------------------------------- /third_party/murmur3/MurmurHash3.h: -------------------------------------------------------------------------------- 1 | // This source file was originally from: 2 | // https://github.com/PeterScott/murmur3 3 | // 4 | // We've changed it for use with VoltDB: 5 | // - We changed the functions declared below to return their hash by 6 | // value, rather than accept a pointer to storage for the result 7 | 8 | //----------------------------------------------------------------------------- 9 | // MurmurHash3 was written by Austin Appleby, and is placed in the public 10 | // domain. The author hereby disclaims copyright to this source code. 11 | 12 | #ifndef _MURMURHASH3_H_ 13 | #define _MURMURHASH3_H_ 14 | 15 | #include 16 | 17 | namespace murmur3 { 18 | 19 | //----------------------------------------------------------------------------- 20 | // Platform-specific functions and macros 21 | 22 | // Microsoft Visual Studio 23 | 24 | #if defined(_MSC_VER) 25 | 26 | typedef unsigned char uint8_t; 27 | typedef unsigned long uint32_t; 28 | typedef unsigned __int64 uint64_t; 29 | 30 | // Other compilers 31 | 32 | #else // defined(_MSC_VER) 33 | 34 | #include 35 | 36 | #endif // !defined(_MSC_VER) 37 | 38 | //----------------------------------------------------------------------------- 39 | 40 | int32_t MurmurHash3_x64_128 (const void * key, int len, uint32_t seed ); 41 | 42 | inline int32_t MurmurHash3_x64_128(int32_t value, uint32_t seed) { 43 | return MurmurHash3_x64_128(&value, 4, seed); 44 | } 45 | inline int32_t MurmurHash3_x64_128(int32_t value) { 46 | return MurmurHash3_x64_128(&value, 4, 0); 47 | } 48 | 49 | inline int32_t MurmurHash3_x64_128(int64_t value, uint32_t seed) { 50 | return MurmurHash3_x64_128(&value, 8, seed); 51 | } 52 | inline int32_t MurmurHash3_x64_128(int64_t value) { 53 | return MurmurHash3_x64_128(&value, 8, 0); 54 | } 55 | 56 | inline int32_t MurmurHash3_x64_128(double value, uint32_t seed) { 57 | return MurmurHash3_x64_128(&value, 8, seed); 58 | } 59 | 60 | inline int32_t MurmurHash3_x64_128(std::string &value, uint32_t seed) { 61 | return MurmurHash3_x64_128(value.data(), static_cast(value.size()), seed); 62 | } 63 | 64 | uint32_t MurmurHash3_x86_32(const void* key, uint32_t len, uint32_t seed); 65 | 66 | void MurmurHash3_x64_128 ( const void * key, const int len, 67 | const uint32_t seed, void * out ); 68 | 69 | //----------------------------------------------------------------------------- 70 | 71 | } 72 | #endif // _MURMURHASH3_H_ 73 | -------------------------------------------------------------------------------- /src/include/type/smallint_type.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // smallint_type.h 6 | // 7 | // Identification: src/include/type/smallint_type.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | #include 15 | #include "type/integer_parent_type.h" 16 | 17 | namespace bustub { 18 | // An integer value of the common sizes. 19 | class SmallintType : public IntegerParentType { 20 | public: 21 | ~SmallintType() override = default; 22 | 23 | SmallintType(); 24 | 25 | // Other mathematical functions 26 | Value Add(const Value &left, const Value &right) const override; 27 | Value Subtract(const Value &left, const Value &right) const override; 28 | Value Multiply(const Value &left, const Value &right) const override; 29 | Value Divide(const Value &left, const Value &right) const override; 30 | Value Modulo(const Value &left, const Value &right) const override; 31 | Value Sqrt(const Value &val) const override; 32 | 33 | // Comparison functions 34 | CmpBool CompareEquals(const Value &left, const Value &right) const override; 35 | CmpBool CompareNotEquals(const Value &left, const Value &right) const override; 36 | CmpBool CompareLessThan(const Value &left, const Value &right) const override; 37 | CmpBool CompareLessThanEquals(const Value &left, const Value &right) const override; 38 | CmpBool CompareGreaterThan(const Value &left, const Value &right) const override; 39 | CmpBool CompareGreaterThanEquals(const Value &left, const Value &right) const override; 40 | 41 | Value CastAs(const Value &val, TypeId type_id) const override; 42 | 43 | // Debug 44 | std::string ToString(const Value &val) const override; 45 | 46 | // Serialize this value into the given storage space 47 | void SerializeTo(const Value &val, char *storage) const override; 48 | 49 | // Deserialize a value of the given type from the given storage space. 50 | Value DeserializeFrom(const char *storage) const override; 51 | 52 | // Create a copy of this value 53 | Value Copy(const Value &val) const override; 54 | 55 | protected: 56 | Value OperateNull(const Value &left, const Value &right) const override; 57 | 58 | bool IsZero(const Value &val) const override; 59 | }; 60 | } // namespace bustub 61 | -------------------------------------------------------------------------------- /test/include/logging/common.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // common.h 6 | // 7 | // Identification: test/include/logging/common.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include // NOLINT 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "storage/table/tuple.h" 22 | 23 | namespace bustub { 24 | 25 | // use a fixed schema to construct a random tuple 26 | Tuple ConstructTuple(Schema *schema) { 27 | std::vector values; 28 | Value v(TypeId::INVALID); 29 | 30 | auto seed = std::chrono::system_clock::now().time_since_epoch().count(); 31 | 32 | std::mt19937 generator(seed); // mt19937 is a standard mersenne_twister_engine 33 | 34 | for (uint32_t i = 0; i < schema->GetColumnCount(); i++) { 35 | // get type 36 | const auto &col = schema->GetColumn(i); 37 | TypeId type = col.GetType(); 38 | switch (type) { 39 | case TypeId::BOOLEAN: 40 | v = Value(type, static_cast(generator() % 2)); 41 | break; 42 | case TypeId::TINYINT: 43 | v = Value(type, static_cast(generator()) % 1000); 44 | break; 45 | case TypeId::SMALLINT: 46 | v = Value(type, static_cast(generator()) % 1000); 47 | break; 48 | case TypeId::INTEGER: 49 | v = Value(type, static_cast(generator()) % 1000); 50 | break; 51 | case TypeId::BIGINT: 52 | v = Value(type, static_cast(generator()) % 1000); 53 | break; 54 | case TypeId::VARCHAR: { 55 | static const char alphanum[] = 56 | "0123456789" 57 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 58 | "abcdefghijklmnopqrstuvwxyz"; 59 | auto len = static_cast(1 + generator() % 9); 60 | char s[10]; 61 | for (uint32_t j = 0; j < len; ++j) { 62 | s[j] = alphanum[generator() % (sizeof(alphanum) - 1)]; 63 | } 64 | s[len] = 0; 65 | v = Value(type, s, len + 1, true); 66 | break; 67 | } 68 | default: 69 | break; 70 | } 71 | values.emplace_back(v); 72 | } 73 | return Tuple(values, schema); 74 | } 75 | 76 | } // namespace bustub 77 | -------------------------------------------------------------------------------- /src/include/type/integer_type.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // integer_type.h 6 | // 7 | // Identification: src/include/type/integer_type.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | #include 15 | #include "type/integer_parent_type.h" 16 | 17 | namespace bustub { 18 | // An integer value of the common sizes. 19 | class IntegerType : public IntegerParentType { 20 | public: 21 | ~IntegerType() override = default; 22 | 23 | explicit IntegerType(TypeId type); 24 | 25 | // Other mathematical functions 26 | Value Add(const Value &left, const Value &right) const override; 27 | Value Subtract(const Value &left, const Value &right) const override; 28 | Value Multiply(const Value &left, const Value &right) const override; 29 | Value Divide(const Value &left, const Value &right) const override; 30 | Value Modulo(const Value &left, const Value &right) const override; 31 | Value Sqrt(const Value &val) const override; 32 | 33 | // Comparison functions 34 | CmpBool CompareEquals(const Value &left, const Value &right) const override; 35 | CmpBool CompareNotEquals(const Value &left, const Value &right) const override; 36 | CmpBool CompareLessThan(const Value &left, const Value &right) const override; 37 | CmpBool CompareLessThanEquals(const Value &left, const Value &right) const override; 38 | CmpBool CompareGreaterThan(const Value &left, const Value &right) const override; 39 | CmpBool CompareGreaterThanEquals(const Value &left, const Value &right) const override; 40 | 41 | Value CastAs(const Value &val, TypeId type_id) const override; 42 | 43 | // Debug 44 | std::string ToString(const Value &val) const override; 45 | 46 | // Serialize this value into the given storage space 47 | void SerializeTo(const Value &val, char *storage) const override; 48 | 49 | // Deserialize a value of the given type from the given storage space. 50 | Value DeserializeFrom(const char *storage) const override; 51 | 52 | // Create a copy of this value 53 | Value Copy(const Value &val) const override; 54 | 55 | protected: 56 | Value OperateNull(const Value &left, const Value &right) const override; 57 | 58 | bool IsZero(const Value &val) const override; 59 | }; 60 | } // namespace bustub 61 | -------------------------------------------------------------------------------- /src/storage/table/table_iterator.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // table_iterator.cpp 6 | // 7 | // Identification: src/storage/table/table_iterator.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include 14 | 15 | #include "storage/table/table_heap.h" 16 | 17 | namespace bustub { 18 | 19 | TableIterator::TableIterator(TableHeap *table_heap, RID rid, Transaction *txn) 20 | : table_heap_(table_heap), tuple_(new Tuple(rid)), txn_(txn) { 21 | if (rid.GetPageId() != INVALID_PAGE_ID) { 22 | table_heap_->GetTuple(tuple_->rid_, tuple_, txn_); 23 | } 24 | } 25 | 26 | const Tuple &TableIterator::operator*() { 27 | assert(*this != table_heap_->End()); 28 | return *tuple_; 29 | } 30 | 31 | Tuple *TableIterator::operator->() { 32 | assert(*this != table_heap_->End()); 33 | return tuple_; 34 | } 35 | 36 | TableIterator &TableIterator::operator++() { 37 | BufferPoolManager *buffer_pool_manager = table_heap_->buffer_pool_manager_; 38 | auto cur_page = static_cast(buffer_pool_manager->FetchPage(tuple_->rid_.GetPageId())); 39 | cur_page->RLatch(); 40 | assert(cur_page != nullptr); // all pages are pinned 41 | 42 | RID next_tuple_rid; 43 | if (!cur_page->GetNextTupleRid(tuple_->rid_, 44 | &next_tuple_rid)) { // end of this page 45 | while (cur_page->GetNextPageId() != INVALID_PAGE_ID) { 46 | auto next_page = static_cast(buffer_pool_manager->FetchPage(cur_page->GetNextPageId())); 47 | cur_page->RUnlatch(); 48 | buffer_pool_manager->UnpinPage(cur_page->GetTablePageId(), false); 49 | cur_page = next_page; 50 | cur_page->RLatch(); 51 | if (cur_page->GetFirstTupleRid(&next_tuple_rid)) { 52 | break; 53 | } 54 | } 55 | } 56 | tuple_->rid_ = next_tuple_rid; 57 | 58 | if (*this != table_heap_->End()) { 59 | table_heap_->GetTuple(tuple_->rid_, tuple_, txn_); 60 | } 61 | // release until copy the tuple 62 | cur_page->RUnlatch(); 63 | buffer_pool_manager->UnpinPage(cur_page->GetTablePageId(), false); 64 | return *this; 65 | } 66 | 67 | TableIterator TableIterator::operator++(int) { 68 | TableIterator clone(*this); 69 | ++(*this); 70 | return clone; 71 | } 72 | 73 | } // namespace bustub 74 | -------------------------------------------------------------------------------- /src/include/execution/plans/abstract_plan.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // abstract_plan.h 6 | // 7 | // Identification: src/include/execution/plans/abstract_plan.h 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | #include "catalog/schema.h" 19 | 20 | namespace bustub { 21 | 22 | /** PlanType represents the types of plans that we have in our system. */ 23 | enum class PlanType { SeqScan, HashJoin, Insert, Aggregation }; 24 | 25 | /** 26 | * AbstractPlanNode represents all the possible types of plan nodes in our system. 27 | * Plan nodes are modeled as trees, so each plan node can have a variable number of children. 28 | * Per the Volcano model, the plan node receives the tuples of its children. 29 | * The ordering of the children may matter. 30 | */ 31 | class AbstractPlanNode { 32 | public: 33 | /** 34 | * Create a new AbstractPlanNode with the specified output schema and children. 35 | * @param output_schema the schema for the output of this plan node 36 | * @param children the children of this plan node 37 | */ 38 | AbstractPlanNode(const Schema *output_schema, std::vector &&children) 39 | : output_schema_(output_schema), children_(std::move(children)) {} 40 | 41 | /** Virtual destructor. */ 42 | virtual ~AbstractPlanNode() = default; 43 | 44 | /** @return the schema for the output of this plan node */ 45 | const Schema *OutputSchema() const { return output_schema_; } 46 | 47 | /** @return the child of this plan node at index child_idx */ 48 | const AbstractPlanNode *GetChildAt(uint32_t child_idx) const { return children_[child_idx]; } 49 | 50 | /** @return the children of this plan node */ 51 | const std::vector &GetChildren() const { return children_; } 52 | 53 | /** @return the type of this plan node */ 54 | virtual PlanType GetType() const = 0; 55 | 56 | private: 57 | /** 58 | * The schema for the output of this plan node. In the volcano model, every plan node will spit out tuples, 59 | * and this tells you what schema this plan node's tuples will have. 60 | */ 61 | const Schema *output_schema_; 62 | /** The children of this plan node. */ 63 | std::vector children_; 64 | }; 65 | } // namespace bustub 66 | -------------------------------------------------------------------------------- /src/include/type/varlen_type.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // varlen_type.h 6 | // 7 | // Identification: src/include/type/varlen_type.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | #include 15 | #include "type/value.h" 16 | 17 | namespace bustub { 18 | /* A varlen value is an abstract class representing all objects that have 19 | * variable length. 20 | * For simplicity, for valen_type we always set flag "inline" as true, which 21 | * means we store actual data along with its size rather than a pointer 22 | */ 23 | class VarlenType : public Type { 24 | public: 25 | explicit VarlenType(TypeId type); 26 | ~VarlenType() override; 27 | 28 | // Access the raw variable length data 29 | const char *GetData(const Value &val) const override; 30 | 31 | // Get the length of the variable length data 32 | uint32_t GetLength(const Value &val) const override; 33 | 34 | // Comparison functions 35 | CmpBool CompareEquals(const Value &left, const Value &right) const override; 36 | CmpBool CompareNotEquals(const Value &left, const Value &right) const override; 37 | CmpBool CompareLessThan(const Value &left, const Value &right) const override; 38 | CmpBool CompareLessThanEquals(const Value &left, const Value &right) const override; 39 | CmpBool CompareGreaterThan(const Value &left, const Value &right) const override; 40 | CmpBool CompareGreaterThanEquals(const Value &left, const Value &right) const override; 41 | 42 | // Other mathematical functions 43 | Value Min(const Value &left, const Value &right) const override; 44 | Value Max(const Value &left, const Value &right) const override; 45 | 46 | Value CastAs(const Value &value, TypeId type_id) const override; 47 | 48 | // Decimal types are always inlined 49 | bool IsInlined(const Value & /*val*/) const override { return false; } 50 | 51 | // Debug 52 | std::string ToString(const Value &val) const override; 53 | 54 | // Serialize this value into the given storage space 55 | void SerializeTo(const Value &val, char *storage) const override; 56 | 57 | // Deserialize a value of the given type from the given storage space. 58 | Value DeserializeFrom(const char *storage) const override; 59 | 60 | // Create a copy of this value 61 | Value Copy(const Value &val) const override; 62 | }; 63 | } // namespace bustub 64 | -------------------------------------------------------------------------------- /test/table/tuple_test.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // tuple_test.cpp 6 | // 7 | // Identification: test/table/tuple_test.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "buffer/buffer_pool_manager.h" 20 | #include "gtest/gtest.h" 21 | #include "logging/common.h" 22 | #include "storage/table/table_heap.h" 23 | #include "storage/table/tuple.h" 24 | 25 | namespace bustub { 26 | // NOLINTNEXTLINE 27 | TEST(TupleTest, DISABLED_TableHeapTest) { 28 | // test1: parse create sql statement 29 | std::string create_stmt = "a varchar(20), b smallint, c bigint, d bool, e varchar(16)"; 30 | Column col1{"a", TypeId::VARCHAR, 20}; 31 | Column col2{"b", TypeId::SMALLINT}; 32 | Column col3{"c", TypeId::BIGINT}; 33 | Column col4{"d", TypeId::BOOLEAN}; 34 | Column col5{"e", TypeId::VARCHAR, 16}; 35 | std::vector cols{col1, col2, col3, col4, col5}; 36 | Schema schema{cols}; 37 | Tuple tuple = ConstructTuple(&schema); 38 | 39 | // create transaction 40 | auto *transaction = new Transaction(0); 41 | auto *disk_manager = new DiskManager("test.db"); 42 | auto *buffer_pool_manager = new BufferPoolManager(50, disk_manager); 43 | auto *lock_manager = new LockManager(TwoPLMode::REGULAR, DeadlockMode::PREVENTION); 44 | auto *log_manager = new LogManager(disk_manager); 45 | auto *table = new TableHeap(buffer_pool_manager, lock_manager, log_manager, transaction); 46 | 47 | std::vector rid_v; 48 | for (int i = 0; i < 5000; ++i) { 49 | RID rid; 50 | table->InsertTuple(tuple, &rid, transaction); 51 | rid_v.push_back(rid); 52 | } 53 | 54 | TableIterator itr = table->Begin(transaction); 55 | while (itr != table->End()) { 56 | // std::cout << itr->ToString(schema) << std::endl; 57 | ++itr; 58 | } 59 | 60 | // int i = 0; 61 | std::shuffle(rid_v.begin(), rid_v.end(), std::default_random_engine(0)); 62 | for (const auto &rid : rid_v) { 63 | // std::cout << i++ << std::endl; 64 | assert(table->MarkDelete(rid, transaction) == 1); 65 | } 66 | disk_manager->ShutDown(); 67 | remove("test.db"); // remove db file 68 | remove("test.log"); 69 | delete table; 70 | delete buffer_pool_manager; 71 | delete disk_manager; 72 | } 73 | 74 | } // namespace bustub 75 | -------------------------------------------------------------------------------- /src/include/type/limits.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // limits.h 6 | // 7 | // Identification: src/include/type/limits.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace bustub { 20 | 21 | static constexpr double DBL_LOWEST = std::numeric_limits::lowest(); 22 | static constexpr double FLT_LOWEST = std::numeric_limits::lowest(); 23 | 24 | static constexpr int8_t BUSTUB_INT8_MIN = (SCHAR_MIN + 1); 25 | static constexpr int16_t BUSTUB_INT16_MIN = (SHRT_MIN + 1); 26 | static constexpr int32_t BUSTUB_INT32_MIN = (INT_MIN + 1); 27 | static constexpr int64_t BUSTUB_INT64_MIN = (LLONG_MIN + 1); 28 | static constexpr double BUSTUB_DECIMAL_MIN = FLT_LOWEST; 29 | static constexpr uint64_t BUSTUB_TIMESTAMP_MIN = 0; 30 | static constexpr uint32_t BUSTUB_DATE_MIN = 0; 31 | static constexpr int8_t BUSTUB_BOOLEAN_MIN = 0; 32 | 33 | static constexpr int8_t BUSTUB_INT8_MAX = SCHAR_MAX; 34 | static constexpr int16_t BUSTUB_INT16_MAX = SHRT_MAX; 35 | static constexpr int32_t BUSTUB_INT32_MAX = INT_MAX; 36 | static constexpr int64_t BUSTUB_INT64_MAX = LLONG_MAX; 37 | static constexpr uint64_t BUSTUB_UINT64_MAX = ULLONG_MAX - 1; 38 | static constexpr double BUSTUB_DECIMAL_MAX = DBL_MAX; 39 | static constexpr uint64_t BUSTUB_TIMESTAMP_MAX = 11231999986399999999U; 40 | static constexpr uint64_t BUSTUB_DATE_MAX = INT_MAX; 41 | static constexpr int8_t BUSTUB_BOOLEAN_MAX = 1; 42 | 43 | static constexpr uint32_t BUSTUB_VALUE_NULL = UINT_MAX; 44 | static constexpr int8_t BUSTUB_INT8_NULL = SCHAR_MIN; 45 | static constexpr int16_t BUSTUB_INT16_NULL = SHRT_MIN; 46 | static constexpr int32_t BUSTUB_INT32_NULL = INT_MIN; 47 | static constexpr int64_t BUSTUB_INT64_NULL = LLONG_MIN; 48 | static constexpr uint64_t BUSTUB_DATE_NULL = 0; 49 | static constexpr uint64_t BUSTUB_TIMESTAMP_NULL = ULLONG_MAX; 50 | static constexpr double BUSTUB_DECIMAL_NULL = DBL_LOWEST; 51 | static constexpr int8_t BUSTUB_BOOLEAN_NULL = SCHAR_MIN; 52 | 53 | static constexpr uint32_t BUSTUB_VARCHAR_MAX_LEN = UINT_MAX; 54 | 55 | // Use to make TEXT type as the alias of VARCHAR(TEXT_MAX_LENGTH) 56 | static constexpr uint32_t BUSTUB_TEXT_MAX_LEN = 1000000000; 57 | 58 | // Objects (i.e., VARCHAR) with length prefix of -1 are NULL 59 | static constexpr int OBJECTLENGTH_NULL = -1; 60 | } // namespace bustub 61 | -------------------------------------------------------------------------------- /src/include/type/decimal_type.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // decimal_type.h 6 | // 7 | // Identification: src/include/type/decimal_type.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | #include 15 | #include "type/numeric_type.h" 16 | 17 | namespace bustub { 18 | class DecimalType : public NumericType { 19 | public: 20 | DecimalType(); 21 | // DecimalValue(DecDef definition); 22 | 23 | // Other mathematical functions 24 | Value Add(const Value &left, const Value &right) const override; 25 | Value Subtract(const Value &left, const Value &right) const override; 26 | Value Multiply(const Value &left, const Value &right) const override; 27 | Value Divide(const Value &left, const Value &right) const override; 28 | Value Modulo(const Value &left, const Value &right) const override; 29 | Value Min(const Value &left, const Value &right) const override; 30 | Value Max(const Value &left, const Value &right) const override; 31 | Value Sqrt(const Value &val) const override; 32 | bool IsZero(const Value &val) const override; 33 | 34 | // Comparison functions 35 | CmpBool CompareEquals(const Value &left, const Value &right) const override; 36 | CmpBool CompareNotEquals(const Value &left, const Value &right) const override; 37 | CmpBool CompareLessThan(const Value &left, const Value &right) const override; 38 | CmpBool CompareLessThanEquals(const Value &left, const Value &right) const override; 39 | CmpBool CompareGreaterThan(const Value &left, const Value &right) const override; 40 | CmpBool CompareGreaterThanEquals(const Value &left, const Value &right) const override; 41 | 42 | Value CastAs(const Value &val, TypeId type_id) const override; 43 | 44 | // Decimal types are always inlined 45 | bool IsInlined(const Value &val) const override { return true; } 46 | 47 | // Debug 48 | std::string ToString(const Value &val) const override; 49 | 50 | // Serialize this value into the given storage space 51 | void SerializeTo(const Value &val, char *storage) const override; 52 | 53 | // Deserialize a value of the given type from the given storage space. 54 | Value DeserializeFrom(const char *storage) const override; 55 | 56 | // Create a copy of this value 57 | Value Copy(const Value &val) const override; 58 | 59 | private: 60 | Value OperateNull(const Value &left, const Value &right) const override; 61 | }; 62 | } // namespace bustub 63 | -------------------------------------------------------------------------------- /src/execution/executor_factory.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // executor_factory.cpp 6 | // 7 | // Identification: src/execution/executor_factory.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "execution/executor_factory.h" 14 | 15 | #include 16 | #include 17 | 18 | #include "execution/executors/abstract_executor.h" 19 | #include "execution/executors/aggregation_executor.h" 20 | #include "execution/executors/hash_join_executor.h" 21 | #include "execution/executors/insert_executor.h" 22 | #include "execution/executors/seq_scan_executor.h" 23 | 24 | namespace bustub { 25 | std::unique_ptr ExecutorFactory::CreateExecutor(ExecutorContext *exec_ctx, 26 | const AbstractPlanNode *plan) { 27 | switch (plan->GetType()) { 28 | // Create a new sequential scan executor. 29 | case PlanType::SeqScan: { 30 | return std::make_unique(exec_ctx, dynamic_cast(plan)); 31 | } 32 | 33 | // Create a new insert executor. 34 | case PlanType::Insert: { 35 | auto insert_plan = dynamic_cast(plan); 36 | auto child_executor = 37 | insert_plan->IsRawInsert() ? nullptr : ExecutorFactory::CreateExecutor(exec_ctx, insert_plan->GetChildPlan()); 38 | return std::make_unique(exec_ctx, insert_plan, std::move(child_executor)); 39 | } 40 | 41 | // Create a new hash join executor. 42 | case PlanType::HashJoin: { 43 | auto join_plan = dynamic_cast(plan); 44 | auto left_executor = ExecutorFactory::CreateExecutor(exec_ctx, join_plan->GetLeftPlan()); 45 | auto right_executor = ExecutorFactory::CreateExecutor(exec_ctx, join_plan->GetRightPlan()); 46 | return std::make_unique(exec_ctx, join_plan, std::move(left_executor), 47 | std::move(right_executor)); 48 | } 49 | 50 | // Create a new aggregation executor. 51 | case PlanType::Aggregation: { 52 | auto agg_plan = dynamic_cast(plan); 53 | auto child_executor = ExecutorFactory::CreateExecutor(exec_ctx, agg_plan->GetChildPlan()); 54 | return std::make_unique(exec_ctx, agg_plan, std::move(child_executor)); 55 | } 56 | 57 | default: { 58 | BUSTUB_ASSERT(false, "Unsupported plan type."); 59 | } 60 | } 61 | } 62 | } // namespace bustub 63 | -------------------------------------------------------------------------------- /src/storage/page/hash_table_block_page.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // hash_table_block_page.cpp 6 | // 7 | // Identification: src/storage/page/hash_table_block_page.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "storage/page/hash_table_block_page.h" 14 | 15 | #include "storage/index/generic_key.h" 16 | #include "common/logger.h" 17 | 18 | namespace bustub { 19 | 20 | template 21 | KeyType HASH_TABLE_BLOCK_TYPE::KeyAt(slot_offset_t bucket_ind) const { 22 | return std::get<0>(array_[bucket_ind]); 23 | } 24 | 25 | template 26 | ValueType HASH_TABLE_BLOCK_TYPE::ValueAt(slot_offset_t bucket_ind) const { 27 | return std::get<1>(array_[bucket_ind]); 28 | } 29 | 30 | template 31 | bool HASH_TABLE_BLOCK_TYPE::Insert(slot_offset_t bucket_ind, const KeyType &key, const ValueType &value) { 32 | if (!IsReadable(bucket_ind)) { 33 | array_[bucket_ind] = {key, value}; 34 | occupied_[bucket_ind/8] |= (1 << bucket_ind%8); 35 | readable_[bucket_ind/8] |= (1 << bucket_ind%8); 36 | return true; 37 | } 38 | return false; 39 | } 40 | 41 | template 42 | void HASH_TABLE_BLOCK_TYPE::Remove(slot_offset_t bucket_ind) { 43 | if (HASH_TABLE_BLOCK_TYPE::IsOccupied(bucket_ind)) 44 | readable_[bucket_ind/8] &= ~(1 << bucket_ind%8); 45 | } 46 | 47 | template 48 | bool HASH_TABLE_BLOCK_TYPE::IsOccupied(slot_offset_t bucket_ind) const { 49 | return occupied_[bucket_ind/8] & (1 << bucket_ind%8); 50 | } 51 | 52 | template 53 | bool HASH_TABLE_BLOCK_TYPE::IsReadable(slot_offset_t bucket_ind) const { 54 | return readable_[bucket_ind/8] & (1 << bucket_ind%8); 55 | } 56 | 57 | // DO NOT REMOVE ANYTHING BELOW THIS LINE 58 | template class HashTableBlockPage; 59 | template class HashTableBlockPage, RID, GenericComparator<4>>; 60 | template class HashTableBlockPage, RID, GenericComparator<8>>; 61 | template class HashTableBlockPage, RID, GenericComparator<16>>; 62 | template class HashTableBlockPage, RID, GenericComparator<32>>; 63 | template class HashTableBlockPage, RID, GenericComparator<64>>; 64 | 65 | } // namespace bustub 66 | -------------------------------------------------------------------------------- /test/buffer/buffer_pool_manager_test.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // buffer_pool_manager_test.cpp 6 | // 7 | // Identification: test/buffer/buffer_pool_manager_test.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include 14 | #include 15 | 16 | #include "buffer/buffer_pool_manager.h" 17 | #include "gtest/gtest.h" 18 | 19 | namespace bustub { 20 | 21 | // NOLINTNEXTLINE 22 | TEST(BufferPoolManagerTest, SampleTest) { 23 | const std::string db_name = "test.db"; 24 | const size_t buffer_pool_size = 10; 25 | 26 | auto *disk_manager = new DiskManager(db_name); 27 | auto *bpm = new BufferPoolManager(buffer_pool_size, disk_manager); 28 | 29 | page_id_t page_id_temp; 30 | auto *page0 = bpm->NewPage(&page_id_temp); 31 | 32 | // Scenario: The buffer pool is empty. We should be able to create a new page. 33 | ASSERT_NE(nullptr, page0); 34 | EXPECT_EQ(0, page_id_temp); 35 | 36 | // Scenario: Once we have a page, we should be able to read and write content. 37 | snprintf(page0->GetData(), sizeof(page0->GetData()), "Hello"); 38 | EXPECT_EQ(0, strcmp(page0->GetData(), "Hello")); 39 | 40 | // Scenario: We should be able to create new pages until we fill up the buffer pool. 41 | for (size_t i = 1; i < buffer_pool_size; ++i) { 42 | EXPECT_NE(nullptr, bpm->NewPage(&page_id_temp)); 43 | } 44 | 45 | // Scenario: Once the buffer pool is full, we should not be able to create any new pages. 46 | for (size_t i = buffer_pool_size; i < buffer_pool_size * 2; ++i) { 47 | EXPECT_EQ(nullptr, bpm->NewPage(&page_id_temp)); 48 | } 49 | 50 | // Scenario: After unpinning pages {0, 1, 2, 3, 4} and pinning another 4 new pages, 51 | // there would still be one buffer page left for reading page 0. 52 | for (int i = 0; i < 5; ++i) { 53 | EXPECT_EQ(true, bpm->UnpinPage(i, true)); 54 | } 55 | for (int i = 0; i < 4; ++i) { 56 | EXPECT_NE(nullptr, bpm->NewPage(&page_id_temp)); 57 | } 58 | 59 | // Scenario: We should be able to fetch the data we wrote a while ago. 60 | page0 = bpm->FetchPage(0); 61 | EXPECT_EQ(0, strcmp(page0->GetData(), "Hello")); 62 | 63 | // Scenario: If we unpin page 0 and then make a new page, all the buffer pages should 64 | // now be pinned. Fetching page 0 should fail. 65 | EXPECT_EQ(true, bpm->UnpinPage(0, true)); 66 | EXPECT_NE(nullptr, bpm->NewPage(&page_id_temp)); 67 | EXPECT_EQ(nullptr, bpm->FetchPage(0)); 68 | 69 | // Shutdown the disk manager and remove the temporary file we created. 70 | disk_manager->ShutDown(); 71 | remove("test.db"); 72 | 73 | delete bpm; 74 | delete disk_manager; 75 | } 76 | 77 | } // namespace bustub 78 | -------------------------------------------------------------------------------- /src/include/storage/page/hash_table_header_page.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // hash_table_header_page.h 6 | // 7 | // Identification: src/include/storage/page/hash_table_header_page.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "storage/index/generic_key.h" 21 | #include "storage/page/hash_table_page_defs.h" 22 | 23 | namespace bustub { 24 | 25 | /** 26 | * 27 | * Header Page for linear probing hash table. 28 | * 29 | * Header format (size in byte, 16 bytes in total): 30 | * ------------------------------------------------------------- 31 | * | LSN (4) | Size (4) | PageId(4) | NextBlockIndex(4) 32 | * ------------------------------------------------------------- 33 | */ 34 | class HashTableHeaderPage { 35 | public: 36 | /** 37 | * @return the number of buckets in the hash table; 38 | */ 39 | size_t GetSize() const; 40 | 41 | /** 42 | * Sets the size field of the hash table to size 43 | * 44 | * @param size the size for the size field to be set to 45 | */ 46 | void SetSize(size_t size); 47 | 48 | /** 49 | * @return the page ID of this page 50 | */ 51 | page_id_t GetPageId() const; 52 | 53 | /** 54 | * Sets the page ID of this page 55 | * 56 | * @param page_id the page id for the page id field to be set to 57 | */ 58 | void SetPageId(page_id_t page_id); 59 | 60 | /** 61 | * @return the lsn of this page 62 | */ 63 | lsn_t GetLSN() const; 64 | 65 | /** 66 | * Sets the LSN of this page 67 | * 68 | * @param lsn the log sequence number for the lsn field to be set to 69 | */ 70 | void SetLSN(lsn_t lsn); 71 | 72 | /** 73 | * Adds a block page_id to the end of header page 74 | * 75 | * @param page_id page_id to be added 76 | */ 77 | void AddBlockPageId(page_id_t page_id); 78 | 79 | /** 80 | * Returns the page_id of the index-th block 81 | * 82 | * @param index the index of the block 83 | * @return the page_id for the block. 84 | */ 85 | page_id_t GetBlockPageId(size_t index); 86 | 87 | /** 88 | * @return the number of blocks currently stored in the header page 89 | */ 90 | size_t NumBlocks(); 91 | 92 | private: 93 | __attribute__((unused)) lsn_t lsn_; 94 | __attribute__((unused)) size_t size_; 95 | __attribute__((unused)) page_id_t page_id_; 96 | __attribute__((unused)) size_t next_ind_; 97 | __attribute__((unused)) page_id_t block_page_ids_[0]; 98 | }; 99 | 100 | } // namespace bustub 101 | -------------------------------------------------------------------------------- /src/include/execution/executors/insert_executor.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // insert_executor.h 6 | // 7 | // Identification: src/include/execution/executors/insert_executor.h 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | #include "execution/executor_context.h" 19 | #include "execution/executors/abstract_executor.h" 20 | #include "execution/plans/insert_plan.h" 21 | #include "storage/table/tuple.h" 22 | 23 | namespace bustub { 24 | /** 25 | * InsertExecutor executes an insert into a table. 26 | * Inserted values can either be embedded in the plan itself ("raw insert") or come from a child executor. 27 | */ 28 | class InsertExecutor : public AbstractExecutor { 29 | public: 30 | /** 31 | * Creates a new insert executor. 32 | * @param exec_ctx the executor context 33 | * @param plan the insert plan to be executed 34 | * @param child_executor the child executor to obtain insert values from, can be nullptr 35 | */ 36 | InsertExecutor(ExecutorContext *exec_ctx, const InsertPlanNode *plan, 37 | std::unique_ptr &&child_executor) 38 | : AbstractExecutor(exec_ctx), plan_{plan} {} 39 | 40 | const Schema *GetOutputSchema() override { return plan_->OutputSchema(); } 41 | 42 | void Init() override { 43 | table_info_ = exec_ctx_->GetCatalog()->GetTable(plan_->TableOid()); 44 | if (!plan_->IsRawInsert()) { 45 | child_executor_ = ExecutorFactory::CreateExecutor(GetExecutorContext(), plan_->GetChildPlan()); 46 | child_executor_->Init(); 47 | } 48 | } 49 | 50 | // Note that Insert does not make use of the tuple pointer being passed in. 51 | // We return false if the insert failed for any reason, and return true if all inserts succeeded. 52 | bool Next([[maybe_unused]] Tuple *tuple) override { 53 | if (plan_->IsRawInsert()) { 54 | int size = plan_->RawValues().size(); 55 | for (int i=0; i < size; i++) { 56 | Tuple tuple1 {plan_->RawValuesAt(i), &table_info_->schema_}; 57 | RID rid; 58 | if (!table_info_->table_->InsertTuple(tuple1, &rid, exec_ctx_->GetTransaction())) 59 | return false; 60 | } 61 | } else { 62 | Tuple tuple1; 63 | RID rid; 64 | while (child_executor_->Next(&tuple1)) { 65 | if (!table_info_->table_->InsertTuple(tuple1, &rid, exec_ctx_->GetTransaction())) 66 | return false; 67 | } 68 | } 69 | return true; 70 | } 71 | 72 | private: 73 | /** The insert plan node to be executed. */ 74 | const InsertPlanNode *plan_; 75 | const TableMetadata *table_info_; 76 | std::unique_ptr child_executor_; 77 | }; 78 | } // namespace bustub 79 | -------------------------------------------------------------------------------- /src/include/storage/table/tuple.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // tuple.h 6 | // 7 | // Identification: src/include/storage/table/tuple.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | #include "catalog/schema.h" 19 | #include "common/rid.h" 20 | #include "type/value.h" 21 | 22 | namespace bustub { 23 | 24 | /** 25 | * Tuple format: 26 | * --------------------------------------------------------------------- 27 | * | FIXED-SIZE or VARIED-SIZED OFFSET | PAYLOAD OF VARIED-SIZED FIELD | 28 | * --------------------------------------------------------------------- 29 | */ 30 | class Tuple { 31 | friend class TablePage; 32 | 33 | friend class TableHeap; 34 | 35 | friend class TableIterator; 36 | 37 | public: 38 | // Default constructor (to create a dummy tuple) 39 | Tuple() = default; 40 | 41 | // constructor for table heap tuple 42 | explicit Tuple(RID rid) : rid_(rid) {} 43 | 44 | // constructor for creating a new tuple based on input value 45 | Tuple(std::vector values, const Schema *schema); 46 | 47 | // copy constructor, deep copy 48 | Tuple(const Tuple &other); 49 | 50 | // assign operator, deep copy 51 | Tuple &operator=(const Tuple &other); 52 | 53 | ~Tuple() { 54 | if (allocated_) { 55 | delete[] data_; 56 | } 57 | allocated_ = false; 58 | data_ = nullptr; 59 | } 60 | // serialize tuple data 61 | void SerializeTo(char *storage) const; 62 | 63 | // deserialize tuple data(deep copy) 64 | void DeserializeFrom(const char *storage); 65 | 66 | // return RID of current tuple 67 | inline RID GetRid() const { return rid_; } 68 | 69 | // Get the address of this tuple in the table's backing store 70 | inline char *GetData() const { return data_; } 71 | 72 | // Get length of the tuple, including varchar legth 73 | inline uint32_t GetLength() const { return size_; } 74 | 75 | // Get the value of a specified column (const) 76 | // checks the schema to see how to return the Value. 77 | Value GetValue(const Schema *schema, uint32_t column_idx) const; 78 | 79 | // Is the column value null ? 80 | inline bool IsNull(const Schema *schema, uint32_t column_idx) const { 81 | Value value = GetValue(schema, column_idx); 82 | return value.IsNull(); 83 | } 84 | inline bool IsAllocated() { return allocated_; } 85 | 86 | std::string ToString(const Schema *schema) const; 87 | 88 | private: 89 | // Get the starting storage address of specific column 90 | const char *GetDataPtr(const Schema *schema, uint32_t column_idx) const; 91 | 92 | bool allocated_{false}; // is allocated? 93 | RID rid_{}; // if pointing to the table heap, the rid is valid 94 | uint32_t size_{0}; 95 | char *data_{nullptr}; 96 | }; 97 | 98 | } // namespace bustub 99 | -------------------------------------------------------------------------------- /src/include/catalog/table_generator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "catalog/simple_catalog.h" 7 | #include "execution/executor_context.h" 8 | #include "storage/table/table_heap.h" 9 | 10 | namespace bustub { 11 | 12 | static constexpr uint32_t TEST1_SIZE = 1000; 13 | static constexpr uint32_t TEST2_SIZE = 100; 14 | static constexpr uint32_t TEST_VARLEN_SIZE = 10; 15 | 16 | class TableGenerator { 17 | public: 18 | /** 19 | * Constructor 20 | */ 21 | explicit TableGenerator(ExecutorContext *exec_ctx) : exec_ctx_{exec_ctx} {} 22 | 23 | /** 24 | * Generate test tables. 25 | */ 26 | void GenerateTestTables(); 27 | 28 | private: 29 | /** 30 | * Enumeration to characterize the distribution of values in a given column 31 | */ 32 | enum class Dist : uint8_t { Uniform, Zipf_50, Zipf_75, Zipf_95, Zipf_99, Serial }; 33 | 34 | /** 35 | * Metadata about the data for a given column. Specifically, the type of the 36 | * column, the distribution of values, a min and max if appropriate. 37 | */ 38 | struct ColumnInsertMeta { 39 | /** 40 | * Name of the column 41 | */ 42 | const char *name_; 43 | /** 44 | * Type of the column 45 | */ 46 | const TypeId type_; 47 | /** 48 | * Whether the column is nullable 49 | */ 50 | bool nullable_; 51 | /** 52 | * Distribution of values 53 | */ 54 | Dist dist_; 55 | /** 56 | * Min value of the column 57 | */ 58 | uint64_t min_; 59 | /** 60 | * Max value of the column 61 | */ 62 | uint64_t max_; 63 | /** 64 | * Counter to generate serial data 65 | */ 66 | uint64_t serial_counter_{0}; 67 | 68 | /** 69 | * Constructor 70 | */ 71 | ColumnInsertMeta(const char *name, const TypeId type, bool nullable, Dist dist, uint64_t min, uint64_t max) 72 | : name_(name), type_(type), nullable_(nullable), dist_(dist), min_(min), max_(max) {} 73 | }; 74 | 75 | /** 76 | * Metadata about a table. Specifically, the schema and number of 77 | * rows in the table. 78 | */ 79 | struct TableInsertMeta { 80 | /** 81 | * Name of the table 82 | */ 83 | const char *name_; 84 | /** 85 | * Number of rows 86 | */ 87 | uint32_t num_rows_; 88 | /** 89 | * Columns 90 | */ 91 | std::vector col_meta_; 92 | 93 | /** 94 | * Constructor 95 | */ 96 | TableInsertMeta(const char *name, uint32_t num_rows, std::vector col_meta) 97 | : name_(name), num_rows_(num_rows), col_meta_(std::move(col_meta)) {} 98 | }; 99 | 100 | void FillTable(TableMetadata *info, TableInsertMeta *table_meta); 101 | 102 | std::vector MakeValues(ColumnInsertMeta *col_meta, uint32_t count); 103 | 104 | template 105 | std::vector GenNumericValues(ColumnInsertMeta *col_meta, uint32_t count); 106 | 107 | private: 108 | ExecutorContext *exec_ctx_; 109 | }; 110 | } // namespace bustub 111 | -------------------------------------------------------------------------------- /src/include/execution/plans/hash_join_plan.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // hash_join_plan.h 6 | // 7 | // Identification: src/include/execution/plans/hash_join_plan.h 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | #include "execution/plans/abstract_plan.h" 19 | #include "storage/table/tuple.h" 20 | 21 | namespace bustub { 22 | 23 | /** 24 | * HashJoinPlanNode is used to represent performing a hash join between two children plan nodes. 25 | * By convention, the left child (index 0) is used to build the hash table, 26 | * and the right child (index 1) is used in probing the hash table. 27 | */ 28 | class HashJoinPlanNode : public AbstractPlanNode { 29 | public: 30 | HashJoinPlanNode(const Schema *output_schema, std::vector &&children, 31 | const AbstractExpression *predicate, std::vector &&left_hash_keys, 32 | std::vector &&right_hash_keys) 33 | : AbstractPlanNode(output_schema, std::move(children)), 34 | predicate_(predicate), 35 | left_hash_keys_(std::move(left_hash_keys)), 36 | right_hash_keys_(std::move(right_hash_keys)) {} 37 | 38 | PlanType GetType() const override { return PlanType::HashJoin; } 39 | 40 | /** @return the predicate to be used in the hash join */ 41 | const AbstractExpression *Predicate() const { return predicate_; } 42 | 43 | /** @return the left plan node of the hash join, by convention this is used to build the table */ 44 | const AbstractPlanNode *GetLeftPlan() const { 45 | BUSTUB_ASSERT(GetChildren().size() == 2, "Hash joins should have exactly two children plans."); 46 | return GetChildAt(0); 47 | } 48 | 49 | /** @return the right plan node of the hash join */ 50 | const AbstractPlanNode *GetRightPlan() const { 51 | BUSTUB_ASSERT(GetChildren().size() == 2, "Hash joins should have exactly two children plans."); 52 | return GetChildAt(1); 53 | } 54 | 55 | /** @return the left key at the given index */ 56 | const AbstractExpression *GetLeftKeyAt(uint32_t idx) const { return left_hash_keys_[idx]; } 57 | 58 | /** @return the left keys */ 59 | const std::vector &GetLeftKeys() const { return left_hash_keys_; } 60 | 61 | /** @return the right key at the given index */ 62 | const AbstractExpression *GetRightKeyAt(uint32_t idx) const { return right_hash_keys_[idx]; } 63 | 64 | /** @return the right keys */ 65 | const std::vector &GetRightKeys() const { return right_hash_keys_; } 66 | 67 | private: 68 | /** The hash join predicate. */ 69 | const AbstractExpression *predicate_; 70 | /** The left child's hash keys. */ 71 | std::vector left_hash_keys_; 72 | /** The right child's hash keys. */ 73 | std::vector right_hash_keys_; 74 | }; 75 | } // namespace bustub 76 | -------------------------------------------------------------------------------- /src/include/execution/expressions/abstract_expression.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // abstract_expression.h 6 | // 7 | // Identification: src/include/expression/abstract_expression.h 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | #include "catalog/schema.h" 19 | #include "storage/table/tuple.h" 20 | 21 | namespace bustub { 22 | /** 23 | * AbstractExpression is the base class of all the expressions in the system. 24 | * Expressions are modeled as trees, i.e. every expression may have a variable number of children. 25 | */ 26 | class AbstractExpression { 27 | public: 28 | /** 29 | * Create a new AbstractExpression with the given children and return type. 30 | * @param children the children of this abstract expression 31 | * @param ret_type the return type of this abstract expression when it is evaluated 32 | */ 33 | AbstractExpression(std::vector &&children, TypeId ret_type) 34 | : children_{std::move(children)}, ret_type_{ret_type} {} 35 | 36 | /** Virtual destructor. */ 37 | virtual ~AbstractExpression() = default; 38 | 39 | /** @return the value obtained by evaluating the tuple with the given schema */ 40 | virtual Value Evaluate(const Tuple *tuple, const Schema *schema) const = 0; 41 | 42 | /** 43 | * Returns the value obtained by evaluating a join. 44 | * @param left_tuple the left tuple 45 | * @param left_schema the left tuple's schema 46 | * @param right_tuple the right tuple 47 | * @param right_schema the right tuple's schema 48 | * @return the value obtained by evaluating a join on the left and right 49 | */ 50 | virtual Value EvaluateJoin(const Tuple *left_tuple, const Schema *left_schema, const Tuple *right_tuple, 51 | const Schema *right_schema) const = 0; 52 | 53 | /** 54 | * Returns the value obtained by evaluating the aggregates. 55 | * @param group_bys the group by values 56 | * @param aggregates the aggregate values 57 | * @return the value obtained by checking the aggregates and group bys 58 | */ 59 | virtual Value EvaluateAggregate(const std::vector &group_bys, const std::vector &aggregates) const = 0; 60 | 61 | /** @return the child_idx'th child of this expression */ 62 | const AbstractExpression *GetChildAt(uint32_t child_idx) const { return children_[child_idx]; } 63 | 64 | /** @return the children of this expression, ordering may matter */ 65 | const std::vector &GetChildren() const { return children_; } 66 | 67 | /** @return the type of this expression if it were to be evaluated */ 68 | virtual TypeId GetReturnType() const { return ret_type_; } 69 | 70 | private: 71 | /** The children of this expression. Note that the order of appearance of children may matter. */ 72 | std::vector children_; 73 | /** The return type of this expression. */ 74 | TypeId ret_type_; 75 | }; 76 | } // namespace bustub 77 | -------------------------------------------------------------------------------- /src/concurrency/transaction_manager.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // transaction_manager.cpp 6 | // 7 | // Identification: src/concurrency/transaction_manager.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "concurrency/transaction_manager.h" 14 | 15 | #include 16 | #include 17 | 18 | #include "storage/table/table_heap.h" 19 | 20 | namespace bustub { 21 | 22 | std::unordered_map TransactionManager::txn_map = {}; 23 | 24 | Transaction *TransactionManager::Begin(Transaction *txn) { 25 | // Acquire the global transaction latch in shared mode. 26 | global_txn_latch_.RLock(); 27 | 28 | if (txn == nullptr) { 29 | txn = new Transaction(next_txn_id_++); 30 | } 31 | 32 | if (enable_logging) { 33 | // TODO(student): Add logging here. 34 | } 35 | 36 | txn_map[txn->GetTransactionId()] = txn; 37 | return txn; 38 | } 39 | 40 | void TransactionManager::Commit(Transaction *txn) { 41 | txn->SetState(TransactionState::COMMITTED); 42 | 43 | // Perform all deletes before we commit. 44 | auto write_set = txn->GetWriteSet(); 45 | while (!write_set->empty()) { 46 | auto &item = write_set->back(); 47 | auto table = item.table_; 48 | if (item.wtype_ == WType::DELETE) { 49 | // Note that this also releases the lock when holding the page latch. 50 | table->ApplyDelete(item.rid_, txn); 51 | } 52 | write_set->pop_back(); 53 | } 54 | write_set->clear(); 55 | 56 | if (enable_logging) { 57 | // TODO(student): add logging here 58 | } 59 | 60 | // Release all the locks. 61 | ReleaseLocks(txn); 62 | // Release the global transaction latch. 63 | global_txn_latch_.RUnlock(); 64 | } 65 | 66 | void TransactionManager::Abort(Transaction *txn) { 67 | txn->SetState(TransactionState::ABORTED); 68 | 69 | // Rollback before releasing the lock. 70 | auto write_set = txn->GetWriteSet(); 71 | while (!write_set->empty()) { 72 | auto &item = write_set->back(); 73 | auto table = item.table_; 74 | if (item.wtype_ == WType::DELETE) { 75 | table->RollbackDelete(item.rid_, txn); 76 | } else if (item.wtype_ == WType::INSERT) { 77 | // Note that this also releases the lock when holding the page latch. 78 | table->ApplyDelete(item.rid_, txn); 79 | } else if (item.wtype_ == WType::UPDATE) { 80 | table->UpdateTuple(item.tuple_, item.rid_, txn); 81 | } 82 | write_set->pop_back(); 83 | } 84 | write_set->clear(); 85 | 86 | if (enable_logging) { 87 | // TODO(student): add logging here 88 | } 89 | 90 | // Release all the locks. 91 | ReleaseLocks(txn); 92 | // Release the global transaction latch. 93 | global_txn_latch_.RUnlock(); 94 | } 95 | 96 | void TransactionManager::BlockAllTransactions() { global_txn_latch_.WLock(); } 97 | 98 | void TransactionManager::ResumeTransactions() { global_txn_latch_.WUnlock(); } 99 | 100 | } // namespace bustub 101 | -------------------------------------------------------------------------------- /src/include/storage/page/page.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // page.h 6 | // 7 | // Identification: src/include/storage/page/page.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | #include "common/config.h" 19 | #include "common/rwlatch.h" 20 | 21 | namespace bustub { 22 | 23 | /** 24 | * Page is the basic unit of storage within the database system. Page provides a wrapper for actual data pages being 25 | * held in main memory. Page also contains book-keeping information that is used by the buffer pool manager, e.g. 26 | * pin count, dirty flag, page id, etc. 27 | */ 28 | class Page { 29 | // There is book-keeping information inside the page that should only be relevant to the buffer pool manager. 30 | friend class BufferPoolManager; 31 | 32 | public: 33 | /** Constructor. Zeros out the page data. */ 34 | Page() { ResetMemory(); } 35 | 36 | /** Default destructor. */ 37 | ~Page() = default; 38 | 39 | /** @return the actual data contained within this page */ 40 | inline char *GetData() { return data_; } 41 | 42 | /** @return the page id of this page */ 43 | inline page_id_t GetPageId() { return page_id_; } 44 | 45 | /** @return the pin count of this page */ 46 | inline int GetPinCount() { return pin_count_; } 47 | 48 | /** @return true if the page in memory has been modified from the page on disk, false otherwise */ 49 | inline bool IsDirty() { return is_dirty_; } 50 | 51 | /** Acquire the page write latch. */ 52 | inline void WLatch() { rwlatch_.WLock(); } 53 | 54 | /** Release the page write latch. */ 55 | inline void WUnlatch() { rwlatch_.WUnlock(); } 56 | 57 | /** Acquire the page read latch. */ 58 | inline void RLatch() { rwlatch_.RLock(); } 59 | 60 | /** Release the page read latch. */ 61 | inline void RUnlatch() { rwlatch_.RUnlock(); } 62 | 63 | /** @return the page LSN. */ 64 | inline lsn_t GetLSN() { return *reinterpret_cast(GetData() + OFFSET_LSN); } 65 | 66 | /** Sets the page LSN. */ 67 | inline void SetLSN(lsn_t lsn) { memcpy(GetData() + OFFSET_LSN, &lsn, sizeof(lsn_t)); } 68 | 69 | protected: 70 | static_assert(sizeof(page_id_t) == 4); 71 | static_assert(sizeof(lsn_t) == 4); 72 | 73 | static constexpr size_t SIZE_PAGE_HEADER = 8; 74 | static constexpr size_t OFFSET_PAGE_START = 0; 75 | static constexpr size_t OFFSET_LSN = 4; 76 | 77 | private: 78 | /** Zeroes out the data that is held within the page. */ 79 | inline void ResetMemory() { memset(data_, OFFSET_PAGE_START, PAGE_SIZE); } 80 | 81 | /** The actual data that is stored within a page. */ 82 | char data_[PAGE_SIZE]{}; 83 | /** The ID of this page. */ 84 | page_id_t page_id_ = INVALID_PAGE_ID; 85 | /** The pin count of this page. */ 86 | int pin_count_ = 0; 87 | /** True if the page is dirty, i.e. it is different from its corresponding page on disk. */ 88 | bool is_dirty_ = false; 89 | /** Page latch. */ 90 | ReaderWriterLatch rwlatch_; 91 | }; 92 | 93 | } // namespace bustub 94 | -------------------------------------------------------------------------------- /test/type/type_test.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // type_test.cpp 6 | // 7 | // Identification: test/type/type_test.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "common/exception.h" 18 | #include "gtest/gtest.h" 19 | #include "type/value.h" 20 | 21 | namespace bustub { 22 | //===--------------------------------------------------------------------===// 23 | // Type Tests 24 | //===--------------------------------------------------------------------===// 25 | const std::vector TYPE_TEST_TYPES = { 26 | TypeId::BOOLEAN, TypeId::TINYINT, TypeId::SMALLINT, TypeId::INTEGER, TypeId::BIGINT, TypeId::DECIMAL, 27 | }; 28 | 29 | template 30 | class BPlusTreePage { 31 | public: 32 | void GetInfo(KeyType key, ValueType val) { 33 | if (key.CompareEquals(val) == CmpBool::CmpTrue) { 34 | std::cout << "key info" << key.ToString() << '\n'; 35 | } 36 | } 37 | }; 38 | 39 | // NOLINTNEXTLINE 40 | TEST(TypeTests, InvalidTypeTest) { 41 | // First get the INVALID type instance 42 | TypeId type_id = TypeId::INVALID; 43 | auto t = Type::GetInstance(type_id); 44 | EXPECT_NE(nullptr, t); 45 | EXPECT_EQ(type_id, t->GetTypeId()); 46 | EXPECT_FALSE(t->IsCoercableFrom(type_id)); 47 | 48 | // Then hit up all of the mofos methods 49 | // They should all throw exceptions 50 | EXPECT_THROW(Type::GetTypeSize(type_id), Exception); 51 | EXPECT_THROW(Type::GetMinValue(type_id), Exception); 52 | EXPECT_THROW(Type::GetMaxValue(type_id), Exception); 53 | } 54 | 55 | // NOLINTNEXTLINE 56 | TEST(TypeTests, GetInstanceTest) { 57 | for (auto col_type : TYPE_TEST_TYPES) { 58 | auto t = Type::GetInstance(col_type); 59 | EXPECT_NE(nullptr, t); 60 | EXPECT_EQ(col_type, t->GetTypeId()); 61 | EXPECT_TRUE(t->IsCoercableFrom(col_type)); 62 | } 63 | } 64 | 65 | // NOLINTNEXTLINE 66 | TEST(TypeTests, MaxValueTest) { 67 | for (auto col_type : TYPE_TEST_TYPES) { 68 | auto max_val = Type::GetMaxValue(col_type); 69 | EXPECT_FALSE(max_val.IsNull()); 70 | // NOTE: We should not be allowed to create a value that is greater than 71 | // the max value. 72 | } 73 | } 74 | 75 | // NOLINTNEXTLINE 76 | TEST(TypeTests, MinValueTest) { 77 | for (auto col_type : TYPE_TEST_TYPES) { 78 | auto min_val = Type::GetMinValue(col_type); 79 | EXPECT_FALSE(min_val.IsNull()); 80 | // NOTE: We should not be allowed to create a value that is less than 81 | // the min value. 82 | } 83 | std::string temp = "32"; 84 | Value val1(TypeId::VARCHAR, temp); 85 | Value val2(TypeId::INTEGER, 32); 86 | EXPECT_EQ(val1.CompareEquals(val2), CmpBool::CmpTrue); 87 | } 88 | 89 | // NOLINTNEXTLINE 90 | TEST(TypeTests, TemplateTest) { 91 | std::string temp = "32"; 92 | Value val1(TypeId::INTEGER, 32); 93 | Value val2(TypeId::INTEGER, 32); 94 | std::cout << "size is " << sizeof(std::make_pair(val1, val2)) << '\n'; 95 | BPlusTreePage node; 96 | node.GetInfo(val1, val2); 97 | } 98 | } // namespace bustub 99 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB BUSTUB_TEST_SOURCES "${PROJECT_SOURCE_DIR}/test/*/*test.cpp") 2 | 3 | ###################################################################################################################### 4 | # DEPENDENCIES 5 | ###################################################################################################################### 6 | 7 | # valgrind 8 | find_program(VALGRIND_BIN valgrind) 9 | if ("${VALGRIND_BIN}" STREQUAL "VALGRIND_BIN-NOTFOUND") 10 | message(WARNING "BusTub/test couldn't find valgrind.") 11 | else() 12 | message(STATUS "BusTub/test found valgrind at ${VALGRIND_BIN}") 13 | endif() 14 | 15 | set(VALGRIND_OPTIONS 16 | --error-exitcode=1 # if leaks are detected, return nonzero value 17 | # --gen-suppressions=all # uncomment for leak suppression syntax 18 | --leak-check=full # detailed leak information 19 | --soname-synonyms=somalloc=*jemalloc* # also intercept jemalloc 20 | --trace-children=yes # trace child processes 21 | --track-origins=yes # track origin of uninitialized values 22 | ) 23 | set(VALGRIND_SUPPRESSIONS_FILE "${PROJECT_SOURCE_DIR}/build_support/valgrind.supp") 24 | 25 | ###################################################################################################################### 26 | # MAKE TARGETS 27 | ###################################################################################################################### 28 | 29 | ########################################## 30 | # "make check-tests" 31 | ########################################## 32 | add_custom_target(build-tests COMMAND ${CMAKE_CTEST_COMMAND} --show-only) 33 | add_custom_target(check-tests COMMAND ${CMAKE_CTEST_COMMAND} --verbose) 34 | 35 | ########################################## 36 | # "make XYZ_test" 37 | ########################################## 38 | foreach (bustub_test_source ${BUSTUB_TEST_SOURCES}) 39 | # Create a human readable name. 40 | get_filename_component(bustub_test_filename ${bustub_test_source} NAME) 41 | string(REPLACE ".cpp" "" bustub_test_name ${bustub_test_filename}) 42 | 43 | # Add the test target separately and as part of "make check-tests". 44 | add_executable(${bustub_test_name} EXCLUDE_FROM_ALL ${bustub_test_source}) 45 | add_dependencies(build-tests ${bustub_test_name}) 46 | add_dependencies(check-tests ${bustub_test_name}) 47 | 48 | target_link_libraries(${bustub_test_name} bustub_shared gtest gmock_main) 49 | 50 | # Set test target properties and dependencies. 51 | set_target_properties(${bustub_test_name} 52 | PROPERTIES 53 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test" 54 | COMMAND ${bustub_test_name} 55 | ) 56 | 57 | # Add the test under CTest. 58 | add_test(${bustub_test_name} ${VALGRIND_BIN} ${VALGRIND_OPTIONS} 59 | --suppressions=${VALGRIND_SUPPRESSIONS_FILE} ${CMAKE_BINARY_DIR}/test/${bustub_test_name} 60 | --gtest_color=yes --gtest_output=xml:${CMAKE_BINARY_DIR}/test/unit_${test_name}.xml) 61 | add_test(${bustub_test_name} ${CMAKE_BINARY_DIR}/test/${bustub_test_name} --gtest_color=yes 62 | --gtest_output=xml:${CMAKE_BINARY_DIR}/test/${bustub_test_name}.xml) 63 | endforeach(bustub_test_source ${BUSTUB_TEST_SOURCES}) 64 | -------------------------------------------------------------------------------- /src/include/execution/plans/insert_plan.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // insert_plan.h 6 | // 7 | // Identification: src/include/execution/plans/insert_plan.h 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | #include "catalog/simple_catalog.h" 19 | #include "execution/expressions/abstract_expression.h" 20 | #include "execution/plans/abstract_plan.h" 21 | 22 | namespace bustub { 23 | /** 24 | * InsertPlanNode identifies a table that should be inserted into. 25 | * The values to be inserted are either embedded into the InsertPlanNode itself, i.e. a "raw insert", 26 | * or will come from the child of the InsertPlanNode. To simplify the assignment, InsertPlanNode has at most one child. 27 | */ 28 | class InsertPlanNode : public AbstractPlanNode { 29 | public: 30 | /** 31 | * Creates a new insert plan node for inserting raw values. 32 | * @param raw_values the raw values to be inserted 33 | * @param table_oid the identifier of the table to be inserted into 34 | */ 35 | InsertPlanNode(std::vector> &&raw_values, table_oid_t table_oid) 36 | : AbstractPlanNode(nullptr, {}), raw_values_(std::move(raw_values)), table_oid_(table_oid) {} 37 | 38 | /** 39 | * Creates a new insert plan node for inserting values from a child plan. 40 | * @param child the child plan to obtain values from 41 | * @param table_oid the identifier of the table that should be inserted into 42 | */ 43 | InsertPlanNode(const AbstractPlanNode *child, table_oid_t table_oid) 44 | : AbstractPlanNode(nullptr, {child}), table_oid_(table_oid) {} 45 | 46 | PlanType GetType() const override { return PlanType::Insert; } 47 | 48 | /** @return the identifier of the table that should be inserted into */ 49 | table_oid_t TableOid() const { return table_oid_; } 50 | 51 | /** @return true if we embed insert values directly into the plan, false if we have a child plan providing tuples */ 52 | bool IsRawInsert() const { return GetChildren().empty(); } 53 | 54 | /** @return the raw values to be inserted at the particular index */ 55 | const std::vector &RawValuesAt(uint32_t idx) const { 56 | BUSTUB_ASSERT(IsRawInsert(), "This is not a raw insert, you should use the child plan."); 57 | return raw_values_[idx]; 58 | } 59 | 60 | /** @return the raw values to be inserted */ 61 | const std::vector> &RawValues() const { 62 | BUSTUB_ASSERT(IsRawInsert(), "This is not a raw insert, you should use the child plan."); 63 | return raw_values_; 64 | } 65 | 66 | /** @return the child plan providing tuples to be inserted */ 67 | const AbstractPlanNode *GetChildPlan() const { 68 | BUSTUB_ASSERT(!IsRawInsert(), "This is a raw insert, no child plan should be used."); 69 | BUSTUB_ASSERT(GetChildren().size() == 1, "Insert should have at most one child plan."); 70 | return GetChildAt(0); 71 | } 72 | 73 | private: 74 | /** The raw values embedded in this insert plan. */ 75 | std::vector> raw_values_; 76 | /** The table to be inserted into. */ 77 | table_oid_t table_oid_; 78 | }; 79 | } // namespace bustub 80 | -------------------------------------------------------------------------------- /src/include/common/util/hash_util.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // hash_util.h 6 | // 7 | // Identification: src/include/common/util/hash_util.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "common/macros.h" 21 | #include "type/value.h" 22 | 23 | namespace bustub { 24 | 25 | using hash_t = std::size_t; 26 | 27 | class HashUtil { 28 | private: 29 | static const hash_t prime_factor = 10000019; 30 | 31 | public: 32 | static inline hash_t HashBytes(const char *bytes, size_t length) { 33 | // https://github.com/greenplum-db/gpos/blob/b53c1acd6285de94044ff91fbee91589543feba1/libgpos/src/utils.cpp#L126 34 | hash_t hash = length; 35 | for (size_t i = 0; i < length; ++i) { 36 | hash = ((hash << 5) ^ (hash >> 27)) ^ bytes[i]; 37 | } 38 | return hash; 39 | } 40 | 41 | static inline hash_t CombineHashes(hash_t l, hash_t r) { 42 | hash_t both[2]; 43 | both[0] = l; 44 | both[1] = r; 45 | return HashBytes(reinterpret_cast(both), sizeof(hash_t) * 2); 46 | } 47 | 48 | static inline hash_t SumHashes(hash_t l, hash_t r) { return (l % prime_factor + r % prime_factor) % prime_factor; } 49 | 50 | template 51 | static inline hash_t Hash(const T *ptr) { 52 | return HashBytes(reinterpret_cast(ptr), sizeof(T)); 53 | } 54 | 55 | template 56 | static inline hash_t HashPtr(const T *ptr) { 57 | return HashBytes(reinterpret_cast(&ptr), sizeof(void *)); 58 | } 59 | 60 | /** @return the hash of the value */ 61 | static inline hash_t HashValue(const Value *val) { 62 | switch (val->GetTypeId()) { 63 | case TypeId::TINYINT: { 64 | auto raw = static_cast(val->GetAs()); 65 | return Hash(&raw); 66 | } 67 | case TypeId::SMALLINT: { 68 | auto raw = static_cast(val->GetAs()); 69 | return Hash(&raw); 70 | } 71 | case TypeId::INTEGER: { 72 | auto raw = static_cast(val->GetAs()); 73 | return Hash(&raw); 74 | } 75 | case TypeId::BIGINT: { 76 | auto raw = static_cast(val->GetAs()); 77 | return Hash(&raw); 78 | } 79 | case TypeId::BOOLEAN: { 80 | auto raw = val->GetAs(); 81 | return Hash(&raw); 82 | } 83 | case TypeId::DECIMAL: { 84 | auto raw = val->GetAs(); 85 | return Hash(&raw); 86 | } 87 | case TypeId::VARCHAR: { 88 | auto raw = val->GetData(); 89 | auto len = val->GetLength(); 90 | return HashBytes(raw, len); 91 | } 92 | case TypeId::TIMESTAMP: { 93 | auto raw = val->GetAs(); 94 | return Hash(&raw); 95 | } 96 | default: { 97 | BUSTUB_ASSERT(false, "Unsupported type."); 98 | } 99 | } 100 | } 101 | }; 102 | 103 | } // namespace bustub 104 | -------------------------------------------------------------------------------- /src/include/execution/expressions/comparison_expression.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // comparison_expression.h 6 | // 7 | // Identification: src/include/expression/comparison_expression.h 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | #include "catalog/schema.h" 19 | #include "execution/expressions/abstract_expression.h" 20 | #include "storage/table/tuple.h" 21 | #include "type/value_factory.h" 22 | 23 | namespace bustub { 24 | 25 | /** ComparisonType represents the type of comparison that we want to perform. */ 26 | enum class ComparisonType { Equal, NotEqual, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual }; 27 | 28 | /** 29 | * ComparisonExpression represents two expressions being compared. 30 | */ 31 | class ComparisonExpression : public AbstractExpression { 32 | public: 33 | /** Creates a new comparison expression representing (left comp_type right). */ 34 | ComparisonExpression(const AbstractExpression *left, const AbstractExpression *right, ComparisonType comp_type) 35 | : AbstractExpression({left, right}, TypeId::BOOLEAN), comp_type_{comp_type} {} 36 | 37 | Value Evaluate(const Tuple *tuple, const Schema *schema) const override { 38 | Value lhs = GetChildAt(0)->Evaluate(tuple, schema); 39 | Value rhs = GetChildAt(1)->Evaluate(tuple, schema); 40 | return ValueFactory::GetBooleanValue(PerformComparison(lhs, rhs)); 41 | } 42 | 43 | Value EvaluateJoin(const Tuple *left_tuple, const Schema *left_schema, const Tuple *right_tuple, 44 | const Schema *right_schema) const override { 45 | Value lhs = GetChildAt(0)->EvaluateJoin(left_tuple, left_schema, right_tuple, right_schema); 46 | Value rhs = GetChildAt(1)->EvaluateJoin(left_tuple, left_schema, right_tuple, right_schema); 47 | return ValueFactory::GetBooleanValue(PerformComparison(lhs, rhs)); 48 | } 49 | 50 | Value EvaluateAggregate(const std::vector &group_bys, const std::vector &aggregates) const override { 51 | Value lhs = GetChildAt(0)->EvaluateAggregate(group_bys, aggregates); 52 | Value rhs = GetChildAt(1)->EvaluateAggregate(group_bys, aggregates); 53 | return ValueFactory::GetBooleanValue(PerformComparison(lhs, rhs)); 54 | } 55 | 56 | private: 57 | CmpBool PerformComparison(const Value &lhs, const Value &rhs) const { 58 | switch (comp_type_) { 59 | case ComparisonType::Equal: 60 | return lhs.CompareEquals(rhs); 61 | case ComparisonType::NotEqual: 62 | return lhs.CompareNotEquals(rhs); 63 | case ComparisonType::LessThan: 64 | return lhs.CompareLessThan(rhs); 65 | case ComparisonType::LessThanOrEqual: 66 | return lhs.CompareLessThanEquals(rhs); 67 | case ComparisonType::GreaterThan: 68 | return lhs.CompareGreaterThan(rhs); 69 | case ComparisonType::GreaterThanOrEqual: 70 | return lhs.CompareGreaterThanEquals(rhs); 71 | default: 72 | BUSTUB_ASSERT(false, "Unsupported comparison type."); 73 | } 74 | } 75 | 76 | std::vector children_; 77 | ComparisonType comp_type_; 78 | }; 79 | } // namespace bustub 80 | -------------------------------------------------------------------------------- /test/container/hash_table_test.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // hash_table_test.cpp 6 | // 7 | // Identification: test/container/hash_table_test.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include // NOLINT 14 | #include 15 | 16 | #include "common/logger.h" 17 | #include "container/hash/linear_probe_hash_table.h" 18 | #include "gtest/gtest.h" 19 | #include "murmur3/MurmurHash3.h" 20 | 21 | namespace bustub { 22 | 23 | // NOLINTNEXTLINE 24 | TEST(HashTableTest, SampleTest) { 25 | auto *disk_manager = new DiskManager("test.db"); 26 | auto *bpm = new BufferPoolManager(50, disk_manager); 27 | 28 | LinearProbeHashTable ht("blah", bpm, IntComparator(), 1000, HashFunction()); 29 | 30 | // insert a few values 31 | for (int i = 0; i < 5; i++) { 32 | ht.Insert(nullptr, i, i); 33 | std::vector res; 34 | ht.GetValue(nullptr, i, &res); 35 | EXPECT_EQ(1, res.size()) << "Failed to insert " << i << std::endl; 36 | EXPECT_EQ(i, res[0]); 37 | } 38 | 39 | // check if the inserted values are all there 40 | for (int i = 0; i < 5; i++) { 41 | std::vector res; 42 | ht.GetValue(nullptr, i, &res); 43 | EXPECT_EQ(1, res.size()) << "Failed to keep " << i << std::endl; 44 | EXPECT_EQ(i, res[0]); 45 | } 46 | 47 | // insert one more value for each key 48 | for (int i = 0; i < 5; i++) { 49 | if (i == 0) { 50 | // duplicate values for the same key are not allowed 51 | EXPECT_FALSE(ht.Insert(nullptr, i, 2 * i)); 52 | } else { 53 | EXPECT_TRUE(ht.Insert(nullptr, i, 2 * i)); 54 | } 55 | ht.Insert(nullptr, i, 2 * i); 56 | std::vector res; 57 | ht.GetValue(nullptr, i, &res); 58 | if (i == 0) { 59 | // duplicate values for the same key are not allowed 60 | EXPECT_EQ(1, res.size()); 61 | EXPECT_EQ(i, res[0]); 62 | } else { 63 | EXPECT_EQ(2, res.size()); 64 | if (res[0] == i) { 65 | EXPECT_EQ(2 * i, res[1]); 66 | } else { 67 | EXPECT_EQ(2 * i, res[0]); 68 | EXPECT_EQ(i, res[1]); 69 | } 70 | } 71 | } 72 | 73 | // look for a key that does not exist 74 | std::vector res; 75 | ht.GetValue(nullptr, 20, &res); 76 | EXPECT_EQ(0, res.size()); 77 | 78 | // delete some values 79 | for (int i = 0; i < 5; i++) { 80 | EXPECT_TRUE(ht.Remove(nullptr, i, i)); 81 | std::vector res; 82 | ht.GetValue(nullptr, i, &res); 83 | if (i == 0) { 84 | // (0, 0) is the only pair with key 0 85 | EXPECT_EQ(0, res.size()); 86 | } else { 87 | EXPECT_EQ(1, res.size()); 88 | EXPECT_EQ(2 * i, res[0]); 89 | } 90 | } 91 | 92 | // delete all values 93 | for (int i = 0; i < 5; i++) { 94 | if (i == 0) { 95 | // (0, 0) has been deleted 96 | EXPECT_FALSE(ht.Remove(nullptr, i, 2 * i)); 97 | } else { 98 | EXPECT_TRUE(ht.Remove(nullptr, i, 2 * i)); 99 | } 100 | } 101 | disk_manager->ShutDown(); 102 | remove("test.db"); 103 | delete disk_manager; 104 | delete bpm; 105 | } 106 | 107 | } // namespace bustub 108 | -------------------------------------------------------------------------------- /src/include/common/util/string_util.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // string_util.h 6 | // 7 | // Identification: src/include/common/util/string_util.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | namespace bustub { 19 | 20 | /** 21 | * StringUtil provides INEFFICIENT utility functions for working with strings. They should only be used for debugging. 22 | */ 23 | class StringUtil { 24 | public: 25 | /** @return true if haystack contains needle, false otherwise */ 26 | static bool Contains(const std::string &haystack, const std::string &needle); 27 | 28 | /** @return true if target string starts with given prefix, false otherwise */ 29 | static bool StartsWith(const std::string &str, const std::string &prefix); 30 | 31 | /** @return true if target string ends with the given suffix, false otherwise */ 32 | static bool EndsWith(const std::string &str, const std::string &suffix); 33 | 34 | /** @return str repeated n times */ 35 | static std::string Repeat(const std::string &str, std::size_t n); 36 | 37 | /** @return input string split based on the delimiter */ 38 | static std::vector Split(const std::string &str, char delimiter); 39 | 40 | /** @return concatenation of all input strings, separated by the separator */ 41 | static std::string Join(const std::vector &input, const std::string &separator); 42 | 43 | /** @return prefix prepended to the beginning of each line in str */ 44 | static std::string Prefix(const std::string &str, const std::string &prefix); 45 | 46 | /** @return bytes formatted into the appropriate kilobyte, megabyte or gigabyte representation */ 47 | static std::string FormatSize(uint64_t bytes); 48 | 49 | /** @return string wrapped with control characters to appear bold in the console */ 50 | static std::string Bold(const std::string &str); 51 | 52 | /** @return uppercase version of the string */ 53 | static std::string Upper(const std::string &str); 54 | 55 | /** @return lowercase version of the string */ 56 | static std::string Lower(const std::string &str); 57 | 58 | /** @return string formatted with printf semantics */ 59 | static std::string Format(std::string fmt_str, ...); 60 | 61 | /** @return input string split based on the split string */ 62 | static std::vector Split(const std::string &input, const std::string &split); 63 | 64 | /** 65 | * Removes the whitespace characters from the right side of the string. 66 | * @param[in,out] str string to be trimmed on the right 67 | */ 68 | static void RTrim(std::string *str); 69 | 70 | /** @return indented string */ 71 | static std::string Indent(int num_indent); 72 | 73 | /** 74 | * Return a new string that has stripped all occurrences of the provided character from the provided string. 75 | * 76 | * NOTE: WASTEFUL. Performs a copy. Do NOT use for performance-critical code! 77 | * 78 | * @param str input string 79 | * @param c character to be removed 80 | * @return a new string with no occurrences of the provided character 81 | */ 82 | static std::string Strip(const std::string &str, char c); 83 | }; 84 | 85 | } // namespace bustub 86 | -------------------------------------------------------------------------------- /src/include/common/exception.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // exception.h 6 | // 7 | // Identification: src/include/common/exception.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "type/type.h" 23 | 24 | namespace bustub { 25 | 26 | // TODO(WAN): the comment I added below is a lie, but you shouldn't need to poke around here. Don't worry about it. 27 | // Most of the exception types are type subsystem madness. I think we can get rid of it at some point. 28 | /** ExceptionType is all the types of exceptions that we expect to throw in our system. */ 29 | enum class ExceptionType { 30 | /** Invalid exception type.*/ 31 | INVALID = 0, 32 | /** Value out of range. */ 33 | OUT_OF_RANGE = 1, 34 | /** Conversion/casting error. */ 35 | CONVERSION = 2, 36 | /** Unknown type in the type subsystem. */ 37 | UNKNOWN_TYPE = 3, 38 | /** Decimal-related errors. */ 39 | DECIMAL = 4, 40 | /** Type mismatch. */ 41 | MISMATCH_TYPE = 5, 42 | /** Division by 0. */ 43 | DIVIDE_BY_ZERO = 6, 44 | /** Incompatible type. */ 45 | INCOMPATIBLE_TYPE = 8, 46 | /** Method not implemented. */ 47 | NOT_IMPLEMENTED = 11, 48 | }; 49 | 50 | class Exception : public std::runtime_error { 51 | public: 52 | explicit Exception(const std::string &message) : std::runtime_error(message), type_(ExceptionType::INVALID) { 53 | std::string exception_message = "Message :: " + message + "\n"; 54 | std::cerr << exception_message; 55 | } 56 | 57 | Exception(ExceptionType exception_type, const std::string &message) 58 | : std::runtime_error(message), type_(exception_type) { 59 | std::string exception_message = 60 | "\nException Type :: " + ExpectionTypeToString(type_) + "\nMessage :: " + message + "\n"; 61 | std::cerr << exception_message; 62 | } 63 | 64 | std::string ExpectionTypeToString(ExceptionType type) { 65 | switch (type) { 66 | case ExceptionType::INVALID: 67 | return "Invalid"; 68 | case ExceptionType::OUT_OF_RANGE: 69 | return "Out of Range"; 70 | case ExceptionType::CONVERSION: 71 | return "Conversion"; 72 | case ExceptionType::UNKNOWN_TYPE: 73 | return "Unknown Type"; 74 | case ExceptionType::DECIMAL: 75 | return "Decimal"; 76 | case ExceptionType::MISMATCH_TYPE: 77 | return "Mismatch Type"; 78 | case ExceptionType::DIVIDE_BY_ZERO: 79 | return "Divide by Zero"; 80 | case ExceptionType::INCOMPATIBLE_TYPE: 81 | return "Incompatible type"; 82 | case ExceptionType::NOT_IMPLEMENTED: 83 | return "Not implemented"; 84 | default: 85 | return "Unknown"; 86 | } 87 | } 88 | 89 | private: 90 | ExceptionType type_; 91 | }; 92 | 93 | class NotImplementedException : public Exception { 94 | public: 95 | NotImplementedException() = delete; 96 | explicit NotImplementedException(const std::string &msg) : Exception(ExceptionType::NOT_IMPLEMENTED, msg) {} 97 | }; 98 | 99 | } // namespace bustub 100 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | # 18 | # Modified from the Apache Arrow project for the Terrier project. 19 | # 20 | --- 21 | Checks: ' 22 | bugprone-*, 23 | clang-analyzer-*, 24 | google-*, 25 | modernize-*, 26 | performance-*, 27 | portability-*, 28 | readability-*, 29 | -bugprone-too-small-loop-variable, 30 | -clang-analyzer-cplusplus.NewDelete, 31 | -clang-analyzer-cplusplus.NewDeleteLeaks, 32 | -modernize-use-nodiscard, 33 | -modernize-avoid-c-arrays, 34 | -readability-magic-numbers, 35 | ' 36 | # TODO(WAN): To be enabled in Fall 2020. 37 | #CheckOptions: 38 | # - { key: readability-identifier-naming.ClassCase, value: CamelCase } 39 | # - { key: readability-identifier-naming.EnumCase, value: CamelCase } 40 | # - { key: readability-identifier-naming.FunctionCase, value: CamelCase } 41 | # - { key: readability-identifier-naming.GlobalConstantCase, value: UPPER_CASE } 42 | # - { key: readability-identifier-naming.MemberCase, value: lower_case } 43 | # - { key: readability-identifier-naming.MemberSuffix, value: _ } 44 | # - { key: readability-identifier-naming.NamespaceCase, value: lower_case } 45 | # - { key: readability-identifier-naming.StructCase, value: CamelCase } 46 | # - { key: readability-identifier-naming.UnionCase, value: CamelCase } 47 | # - { key: readability-identifier-naming.VariableCase, value: lower_case } 48 | WarningsAsErrors: '*' 49 | HeaderFilterRegex: '/(src|test)/include' 50 | AnalyzeTemporaryDtors: true 51 | 52 | #### Disabled checks and why: ##### 53 | # 54 | # -bugprone-too-small-loop-variable, 55 | # Complains about uint8_t or uint16_t when the limit on the loop is a container's .size() (size_t). 56 | # We usually do this when we know the maximum size of the container though, so propose leaving disabled. 57 | # -clang-analyzer-cplusplus.NewDelete, 58 | # Seems to generate false positives. Suggest relying on ASAN and valgrind for memory stuff. 59 | # -clang-analyzer-cplusplus.NewDeleteLeaks, 60 | # Seems to generate false positives. Suggest relying on ASAN and valgrind for memory stuff. 61 | # -modernize-use-nodiscard, 62 | # New C++17 feature, slightly polarizing. Would clutter codebase. 63 | # -modernize-avoid-c-arrays, 64 | # We use C-style arrays in page.h, type.h and logger.h. They're a little more ergonomic than std::array. Thoughts? 65 | # -readability-magic-numbers, 66 | # Let's not deal with people doing ridiculous things to hack around this. If it bites them, it bites them. 67 | -------------------------------------------------------------------------------- /src/include/storage/index/generic_key.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // generic_key.h 6 | // 7 | // Identification: src/include/storage/index/generic_key.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | #include "storage/table/tuple.h" 18 | #include "type/value.h" 19 | 20 | namespace bustub { 21 | 22 | /** 23 | * Generic key is used for indexing with opaque data. 24 | * 25 | * This key type uses an fixed length array to hold data for indexing 26 | * purposes, the actual size of which is specified and instantiated 27 | * with a template argument. 28 | */ 29 | template 30 | class GenericKey { 31 | public: 32 | inline void SetFromKey(const Tuple &tuple) { 33 | // intialize to 0 34 | memset(data_, 0, KeySize); 35 | memcpy(data_, tuple.GetData(), tuple.GetLength()); 36 | } 37 | 38 | // NOTE: for test purpose only 39 | inline void SetFromInteger(int64_t key) { 40 | memset(data_, 0, KeySize); 41 | memcpy(data_, &key, sizeof(int64_t)); 42 | } 43 | 44 | inline Value ToValue(Schema *schema, uint32_t column_idx) const { 45 | const char *data_ptr; 46 | const auto &col = schema->GetColumn(column_idx); 47 | const TypeId column_type = col.GetType(); 48 | const bool is_inlined = col.IsInlined(); 49 | if (is_inlined) { 50 | data_ptr = (data_ + col.GetOffset()); 51 | } else { 52 | int32_t offset = *reinterpret_cast(const_cast(data_ + col.GetOffset())); 53 | data_ptr = (data_ + offset); 54 | } 55 | return Value::DeserializeFrom(data_ptr, column_type); 56 | } 57 | 58 | // NOTE: for test purpose only 59 | // interpret the first 8 bytes as int64_t from data vector 60 | inline int64_t ToString() const { return *reinterpret_cast(const_cast(data_)); } 61 | 62 | // NOTE: for test purpose only 63 | // interpret the first 8 bytes as int64_t from data vector 64 | friend std::ostream &operator<<(std::ostream &os, const GenericKey &key) { 65 | os << key.ToString(); 66 | return os; 67 | } 68 | 69 | // actual location of data, extends past the end. 70 | char data_[KeySize]; 71 | }; 72 | 73 | /** 74 | * Function object returns true if lhs < rhs, used for trees 75 | */ 76 | template 77 | class GenericComparator { 78 | public: 79 | inline int operator()(const GenericKey &lhs, const GenericKey &rhs) const { 80 | uint32_t column_count = key_schema_->GetColumnCount(); 81 | 82 | for (uint32_t i = 0; i < column_count; i++) { 83 | Value lhs_value = (lhs.ToValue(key_schema_, i)); 84 | Value rhs_value = (rhs.ToValue(key_schema_, i)); 85 | 86 | if (lhs_value.CompareLessThan(rhs_value) == CmpBool::CmpTrue) { 87 | return -1; 88 | } 89 | if (lhs_value.CompareGreaterThan(rhs_value) == CmpBool::CmpTrue) { 90 | return 1; 91 | } 92 | } 93 | // equals 94 | return 0; 95 | } 96 | 97 | GenericComparator(const GenericComparator &other) : key_schema_{other.key_schema_} {} 98 | 99 | // constructor 100 | explicit GenericComparator(Schema *key_schema) : key_schema_(key_schema) {} 101 | 102 | private: 103 | Schema *key_schema_; 104 | }; 105 | 106 | } // namespace bustub 107 | -------------------------------------------------------------------------------- /src/include/concurrency/transaction_manager.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // transaction_manager.h 6 | // 7 | // Identification: src/include/concurrency/transaction_manager.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "common/config.h" 20 | #include "concurrency/lock_manager.h" 21 | #include "concurrency/transaction.h" 22 | #include "recovery/log_manager.h" 23 | 24 | namespace bustub { 25 | class LockManager; 26 | 27 | /** 28 | * TransactionManager keeps track of all the transactions running in the system. 29 | */ 30 | class TransactionManager { 31 | public: 32 | explicit TransactionManager(LockManager *lock_manager, LogManager *log_manager = nullptr) 33 | : lock_manager_(lock_manager), log_manager_(log_manager) {} 34 | 35 | ~TransactionManager() = default; 36 | 37 | /** 38 | * Begins a new transaction. 39 | * @param txn an optional transaction object to be initialized, otherwise a new transaction is created 40 | * @return an initialized transaction 41 | */ 42 | Transaction *Begin(Transaction *txn = nullptr); 43 | 44 | /** 45 | * Commits a transaction. 46 | * @param txn the transaction to commit 47 | */ 48 | void Commit(Transaction *txn); 49 | 50 | /** 51 | * Aborts a transaction 52 | * @param txn the transaction to abort 53 | */ 54 | void Abort(Transaction *txn); 55 | 56 | /** 57 | * Global list of running transactions 58 | */ 59 | 60 | /** The transaction map is a global list of all the running transactions in the system. */ 61 | static std::unordered_map txn_map; 62 | 63 | /** 64 | * Locates and returns the transaction with the given transaction ID. 65 | * @param txn_id the id of the transaction to be found, it must exist! 66 | * @return the transaction with the given transaction id 67 | */ 68 | static Transaction *GetTransaction(txn_id_t txn_id) { 69 | assert(TransactionManager::txn_map.find(txn_id) != TransactionManager::txn_map.end()); 70 | auto *res = TransactionManager::txn_map[txn_id]; 71 | assert(res != nullptr); 72 | return res; 73 | } 74 | 75 | /** Prevents all transactions from performing operations, used for checkpointing. */ 76 | void BlockAllTransactions(); 77 | 78 | /** Resumes all transactions, used for checkpointing. */ 79 | void ResumeTransactions(); 80 | 81 | private: 82 | /** 83 | * Releases all the locks held by the given transaction. 84 | * @param txn the transaction whose locks should be released 85 | */ 86 | void ReleaseLocks(Transaction *txn) { 87 | std::unordered_set lock_set; 88 | for (auto item : *txn->GetExclusiveLockSet()) { 89 | lock_set.emplace(item); 90 | } 91 | for (auto item : *txn->GetSharedLockSet()) { 92 | lock_set.emplace(item); 93 | } 94 | for (auto locked_rid : lock_set) { 95 | lock_manager_->Unlock(txn, locked_rid); 96 | } 97 | } 98 | 99 | std::atomic next_txn_id_{0}; 100 | LockManager *lock_manager_ __attribute__((__unused__)); 101 | LogManager *log_manager_ __attribute__((__unused__)); 102 | 103 | /** The global transaction latch is used for checkpointing. */ 104 | ReaderWriterLatch global_txn_latch_; 105 | }; 106 | 107 | } // namespace bustub 108 | -------------------------------------------------------------------------------- /src/include/catalog/simple_catalog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "buffer/buffer_pool_manager.h" 9 | #include "catalog/schema.h" 10 | #include "storage/index/index.h" 11 | #include "storage/table/table_heap.h" 12 | 13 | namespace bustub { 14 | 15 | /** 16 | * Typedefs 17 | */ 18 | using table_oid_t = uint32_t; 19 | using column_oid_t = uint32_t; 20 | 21 | /** 22 | * Metadata about a table. 23 | */ 24 | struct TableMetadata { 25 | TableMetadata(Schema schema, std::string name, std::unique_ptr &&table, table_oid_t oid) 26 | : schema_(std::move(schema)), name_(std::move(name)), table_(std::move(table)), oid_(oid) {} 27 | Schema schema_; 28 | std::string name_; 29 | std::unique_ptr table_; 30 | table_oid_t oid_; 31 | }; 32 | 33 | /** 34 | * SimpleCatalog is a non-persistent catalog that is designed for the executor to use. 35 | * It handles table creation and table lookup. 36 | */ 37 | class SimpleCatalog { 38 | public: 39 | /** 40 | * Creates a new catalog object. 41 | * @param bpm the buffer pool manager backing tables created by this catalog 42 | * @param lock_manager the lock manager in use by the system 43 | * @param log_manager the log manager in use by the system 44 | */ 45 | SimpleCatalog(BufferPoolManager *bpm, LockManager *lock_manager, LogManager *log_manager) 46 | : bpm_{bpm}, lock_manager_{lock_manager}, log_manager_{log_manager} {} 47 | 48 | /** 49 | * Create a new table and return its metadata. 50 | * @param txn the transaction in which the table is being created 51 | * @param table_name the name of the new table 52 | * @param schema the schema of the new table 53 | * @return a pointer to the metadata of the new table 54 | */ 55 | TableMetadata *CreateTable(Transaction *txn, const std::string &table_name, const Schema &schema) { 56 | BUSTUB_ASSERT(names_.count(table_name) == 0, "Table names should be unique!"); 57 | table_oid_t table_oid = next_table_oid_++; 58 | names_.insert({table_name, table_oid}); 59 | TableHeap* table_heap = new TableHeap{bpm_, lock_manager_, log_manager_, txn}; 60 | TableMetadata *table = new TableMetadata {schema, table_name, static_cast>(table_heap), table_oid}; 61 | tables_.insert({table_oid, static_cast>(table)}); 62 | return table; 63 | } 64 | 65 | /** @return table metadata by name */ 66 | TableMetadata *GetTable(const std::string &table_name) { 67 | auto iter = names_.find(table_name); 68 | if (iter == names_.end()) throw std::out_of_range {"The table shouldn't exist in the catalog yet."}; 69 | return tables_.find(iter->second)->second.get(); 70 | } 71 | 72 | /** @return table metadata by oid */ 73 | TableMetadata *GetTable(table_oid_t table_oid) { 74 | auto iter = tables_.find(table_oid); 75 | if (iter ==tables_.end()) throw std::out_of_range {"The table shouldn't exist in the catalog yet."}; 76 | return iter->second.get(); 77 | } 78 | 79 | private: 80 | [[maybe_unused]] BufferPoolManager *bpm_; 81 | [[maybe_unused]] LockManager *lock_manager_; 82 | [[maybe_unused]] LogManager *log_manager_; 83 | 84 | /** tables_ : table identifiers -> table metadata. Note that tables_ owns all table metadata. */ 85 | std::unordered_map> tables_; 86 | /** names_ : table names -> table identifiers */ 87 | std::unordered_map names_; 88 | /** The next table identifier to be used. */ 89 | std::atomic next_table_oid_{0}; 90 | }; 91 | } // namespace bustub 92 | -------------------------------------------------------------------------------- /src/include/catalog/schema.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // schema.h 6 | // 7 | // Identification: src/include/catalog/schema.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "catalog/column.h" 20 | #include "type/type.h" 21 | 22 | namespace bustub { 23 | 24 | class Schema { 25 | public: 26 | /** 27 | * Constructs the schema corresponding to the vector of columns, read left-to-right. 28 | * @param columns columns that describe the schema's individual columns 29 | */ 30 | explicit Schema(const std::vector &columns); 31 | 32 | static Schema *CopySchema(const Schema *from, const std::vector &attrs) { 33 | std::vector cols; 34 | cols.reserve(attrs.size()); 35 | for (const auto i : attrs) { 36 | cols.emplace_back(from->columns_[i]); 37 | } 38 | return new Schema{cols}; 39 | } 40 | 41 | /** @return all the columns in the schema */ 42 | const std::vector &GetColumns() const { return columns_; } 43 | 44 | /** 45 | * Returns a specific column from the schema. 46 | * @param col_idx index of requested column 47 | * @return requested column 48 | */ 49 | const Column &GetColumn(const uint32_t col_idx) const { return columns_[col_idx]; } 50 | 51 | /** 52 | * @param col_name name of the wanted column 53 | * @return the column with the given name 54 | */ 55 | 56 | /** 57 | * Looks up and returns the index of the first column in the schema with the specified name. 58 | * If multiple columns have the same name, the first such index is returned. 59 | * @param col_name name of column to look for 60 | * @return the index of a column with the given name, throws an exception if it does not exist 61 | */ 62 | uint32_t GetColIdx(const std::string &col_name) const { 63 | for (uint32_t i = 0; i < columns_.size(); ++i) { 64 | if (columns_[i].GetName() == col_name) { 65 | return i; 66 | } 67 | } 68 | UNREACHABLE("Column does not exist"); 69 | } 70 | 71 | /** @return the indices of non-inlined columns */ 72 | const std::vector &GetUnlinedColumns() const { return uninlined_columns_; } 73 | 74 | /** @return the number of columns in the schema for the tuple */ 75 | uint32_t GetColumnCount() const { return static_cast(columns_.size()); } 76 | 77 | /** @return the number of non-inlined columns */ 78 | uint32_t GetUnlinedColumnCount() const { return static_cast(uninlined_columns_.size()); } 79 | 80 | /** @return the number of bytes used by one tuple */ 81 | inline uint32_t GetLength() const { return length_; } 82 | 83 | /** @return true if all columns are inlined, false otherwise */ 84 | inline bool IsInlined() const { return tuple_is_inlined_; } 85 | 86 | /** @return string representation of this schema */ 87 | std::string ToString() const; 88 | 89 | private: 90 | /** Fixed-length column size, i.e. the number of bytes used by one tuple. */ 91 | uint32_t length_; 92 | 93 | /** All the columns in the schema, inlined and uninlined. */ 94 | std::vector columns_; 95 | 96 | /** True if all the columns are inlined, false otherwise. */ 97 | bool tuple_is_inlined_; 98 | 99 | /** Indices of all uninlined columns. */ 100 | std::vector uninlined_columns_; 101 | }; 102 | 103 | } // namespace bustub 104 | -------------------------------------------------------------------------------- /src/include/storage/page/hash_table_block_page.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // hash_table_block_page.h 6 | // 7 | // Identification: src/include/storage/page/hash_table_block_page.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "common/config.h" 20 | #include "storage/index/int_comparator.h" 21 | #include "storage/page/hash_table_page_defs.h" 22 | 23 | namespace bustub { 24 | /** 25 | * Store indexed key and and value together within block page. Supports 26 | * non-unique keys. 27 | * 28 | * Block page format (keys are stored in order): 29 | * ---------------------------------------------------------------- 30 | * | KEY(1) + VALUE(1) | KEY(2) + VALUE(2) | ... | KEY(n) + VALUE(n) 31 | * ---------------------------------------------------------------- 32 | * 33 | * Here '+' means concatenation. 34 | * 35 | */ 36 | template 37 | class HashTableBlockPage { 38 | public: 39 | // Delete all constructor / destructor to ensure memory safety 40 | HashTableBlockPage() = delete; 41 | 42 | /** 43 | * Gets the key at an index in the block. 44 | * 45 | * @param bucket_ind the index in the block to get the key at 46 | * @return key at index bucket_ind of the block 47 | */ 48 | KeyType KeyAt(slot_offset_t bucket_ind) const; 49 | 50 | /** 51 | * Gets the value at an index in the block. 52 | * 53 | * @param bucket_ind the index in the block to get the value at 54 | * @return value at index bucket_ind of the block 55 | */ 56 | ValueType ValueAt(slot_offset_t bucket_ind) const; 57 | 58 | /** 59 | * Attempts to insert a key and value into an index in the block. 60 | * The insert is thread safe. It uses compare and swap to claim the index, 61 | * and then writes the key and value into the index, and then marks the 62 | * index as readable. 63 | * 64 | * @param bucket_ind index to write the key and value to 65 | * @param key key to insert 66 | * @param value value to insert 67 | * @return If the value is inserted successfully, it returns true. If the 68 | * index is marked as occupied before the key and value can be inserted, 69 | * Insert returns false. 70 | */ 71 | bool Insert(slot_offset_t bucket_ind, const KeyType &key, const ValueType &value); 72 | 73 | /** 74 | * Removes a key and value at index. 75 | * 76 | * @param bucket_ind ind to remove the value 77 | */ 78 | void Remove(slot_offset_t bucket_ind); 79 | 80 | /** 81 | * Returns whether or not an index is occupied (key/value pair or tombstone) 82 | * 83 | * @param bucket_ind index to look at 84 | * @return true if the index is occupied, false otherwise 85 | */ 86 | bool IsOccupied(slot_offset_t bucket_ind) const; 87 | 88 | /** 89 | * Returns whether or not an index is readable (valid key/value pair) 90 | * 91 | * @param bucket_ind index to look at 92 | * @return true if the index is readable, false otherwise 93 | */ 94 | bool IsReadable(slot_offset_t bucket_ind) const; 95 | 96 | private: 97 | std::atomic_char occupied_[(BLOCK_ARRAY_SIZE - 1) / 8 + 1]; 98 | 99 | // 0 if tombstone/brand new (never occupied), 1 otherwise. 100 | std::atomic_char readable_[(BLOCK_ARRAY_SIZE - 1) / 8 + 1]; 101 | MappingType array_[0]; 102 | }; 103 | 104 | } // namespace bustub 105 | -------------------------------------------------------------------------------- /test/container/hash_table_page_test.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // hash_table_page_test.cpp 6 | // 7 | // Identification: test/container/hash_table_page_test.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include // NOLINT 14 | #include 15 | 16 | #include "buffer/buffer_pool_manager.h" 17 | #include "common/logger.h" 18 | #include "gtest/gtest.h" 19 | #include "storage/disk/disk_manager.h" 20 | #include "storage/page/hash_table_block_page.h" 21 | #include "storage/page/hash_table_header_page.h" 22 | 23 | namespace bustub { 24 | 25 | // NOLINTNEXTLINE 26 | TEST(HashTablePageTest, HeaderPageSampleTest) { 27 | DiskManager *disk_manager = new DiskManager("test.db"); 28 | auto *bpm = new BufferPoolManager(5, disk_manager); 29 | 30 | // get a header page from the BufferPoolManager 31 | page_id_t header_page_id = INVALID_PAGE_ID; 32 | auto header_page = reinterpret_cast(bpm->NewPage(&header_page_id, nullptr)->GetData()); 33 | 34 | // set some fields 35 | for (int i = 0; i < 11; i++) { 36 | header_page->SetSize(i); 37 | EXPECT_EQ(i, header_page->GetSize()); 38 | header_page->SetPageId(i); 39 | EXPECT_EQ(i, header_page->GetPageId()); 40 | header_page->SetLSN(i); 41 | EXPECT_EQ(i, header_page->GetLSN()); 42 | } 43 | 44 | // add a few hypothetical block pages 45 | for (unsigned i = 0; i < 10; i++) { 46 | header_page->AddBlockPageId(i); 47 | EXPECT_EQ(i + 1, header_page->NumBlocks()); 48 | } 49 | 50 | // check for correct block page IDs 51 | for (int i = 0; i < 10; i++) { 52 | EXPECT_EQ(i, header_page->GetBlockPageId(i)); 53 | } 54 | 55 | // unpin the header page now that we are done 56 | bpm->UnpinPage(header_page_id, true, nullptr); 57 | disk_manager->ShutDown(); 58 | remove("test.db"); 59 | delete disk_manager; 60 | delete bpm; 61 | } 62 | 63 | // NOLINTNEXTLINE 64 | TEST(HashTablePageTest, BlockPageSampleTest) { 65 | DiskManager *disk_manager = new DiskManager("test.db"); 66 | auto *bpm = new BufferPoolManager(5, disk_manager); 67 | 68 | // get a block page from the BufferPoolManager 69 | page_id_t block_page_id = INVALID_PAGE_ID; 70 | 71 | auto block_page = 72 | reinterpret_cast *>(bpm->NewPage(&block_page_id, nullptr)->GetData()); 73 | 74 | // insert a few (key, value) pairs 75 | for (unsigned i = 0; i < 10; i++) { 76 | block_page->Insert(i, i, i); 77 | } 78 | 79 | // check for the inserted pairs 80 | for (unsigned i = 0; i < 10; i++) { 81 | EXPECT_EQ(i, block_page->KeyAt(i)); 82 | EXPECT_EQ(i, block_page->ValueAt(i)); 83 | } 84 | 85 | // remove a few pairs 86 | for (unsigned i = 0; i < 10; i++) { 87 | if (i % 2 == 1) { 88 | block_page->Remove(i); 89 | } 90 | } 91 | 92 | // check for the flags 93 | for (unsigned i = 0; i < 15; i++) { 94 | if (i < 10) { 95 | EXPECT_TRUE(block_page->IsOccupied(i)); 96 | if (i % 2 == 1) { 97 | EXPECT_FALSE(block_page->IsReadable(i)); 98 | } else { 99 | EXPECT_TRUE(block_page->IsReadable(i)); 100 | } 101 | } else { 102 | EXPECT_FALSE(block_page->IsOccupied(i)); 103 | } 104 | } 105 | 106 | // unpin the header page now that we are done 107 | bpm->UnpinPage(block_page_id, true, nullptr); 108 | disk_manager->ShutDown(); 109 | remove("test.db"); 110 | delete disk_manager; 111 | delete bpm; 112 | } 113 | 114 | } // namespace bustub 115 | -------------------------------------------------------------------------------- /src/include/storage/disk/disk_manager.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // disk_manager.h 6 | // 7 | // Identification: src/include/storage/disk/disk_manager.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include // NOLINT 18 | #include 19 | 20 | #include "common/config.h" 21 | 22 | namespace bustub { 23 | 24 | /** 25 | * DiskManager takes care of the allocation and deallocation of pages within a database. It performs the reading and 26 | * writing of pages to and from disk, providing a logical file layer within the context of a database management system. 27 | */ 28 | class DiskManager { 29 | public: 30 | /** 31 | * Creates a new disk manager that writes to the specified database file. 32 | * @param db_file the file name of the database file to write to 33 | */ 34 | explicit DiskManager(const std::string &db_file); 35 | 36 | ~DiskManager() = default; 37 | 38 | /** 39 | * Shut down the disk manager and close all the file resources. 40 | */ 41 | void ShutDown(); 42 | 43 | /** 44 | * Write a page to the database file. 45 | * @param page_id id of the page 46 | * @param page_data raw page data 47 | */ 48 | void WritePage(page_id_t page_id, const char *page_data); 49 | 50 | /** 51 | * Read a page from the database file. 52 | * @param page_id id of the page 53 | * @param[out] page_data output buffer 54 | */ 55 | void ReadPage(page_id_t page_id, char *page_data); 56 | 57 | /** 58 | * Append a log entry to the log file. 59 | * @param log_data raw log data 60 | * @param size size of log entry 61 | */ 62 | void WriteLog(char *log_data, int size); 63 | 64 | /** 65 | * Read a log entry from the log file. 66 | * @param[out] log_data output buffer 67 | * @param size size of the log entry 68 | * @param offset offset of the log entry in the file 69 | * @return true if the read was successful, false otherwise 70 | */ 71 | bool ReadLog(char *log_data, int size, int offset); 72 | 73 | /** 74 | * Allocate a page on disk. 75 | * @return the id of the allocated page 76 | */ 77 | page_id_t AllocatePage(); 78 | 79 | /** 80 | * Deallocate a page on disk. 81 | * @param page_id id of the page to deallocate 82 | */ 83 | void DeallocatePage(page_id_t page_id); 84 | 85 | /** @return the number of disk flushes */ 86 | int GetNumFlushes() const; 87 | 88 | /** @return true iff the in-memory content has not been flushed yet */ 89 | bool GetFlushState() const; 90 | 91 | /** @return the number of disk writes */ 92 | int GetNumWrites() const; 93 | 94 | /** 95 | * Sets the future which is used to check for non-blocking flushes. 96 | * @param f the non-blocking flush check 97 | */ 98 | inline void SetFlushLogFuture(std::future *f) { flush_log_f_ = f; } 99 | 100 | /** Checks if the non-blocking flush future was set. */ 101 | inline bool HasFlushLogFuture() { return flush_log_f_ != nullptr; } 102 | 103 | private: 104 | int GetFileSize(const std::string &file_name); 105 | // stream to write log file 106 | std::fstream log_io_; 107 | std::string log_name_; 108 | // stream to write db file 109 | std::fstream db_io_; 110 | std::string file_name_; 111 | std::atomic next_page_id_; 112 | int num_flushes_; 113 | int num_writes_; 114 | bool flush_log_; 115 | std::future *flush_log_f_; 116 | }; 117 | 118 | } // namespace bustub 119 | -------------------------------------------------------------------------------- /src/type/boolean_type.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // boolean_type.cpp 6 | // 7 | // Identification: src/type/boolean_type.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include 14 | 15 | #include 16 | #include "type/boolean_type.h" 17 | 18 | namespace bustub { 19 | #define BOOLEAN_COMPARE_FUNC(OP) GetCmpBool(left.value_.boolean_ OP right.CastAs(TypeId::BOOLEAN).value_.boolean_) 20 | 21 | BooleanType::BooleanType() : Type(TypeId::BOOLEAN) {} 22 | 23 | CmpBool BooleanType::CompareEquals(const Value &left, const Value &right) const { 24 | assert(GetTypeId() == TypeId::BOOLEAN); 25 | assert(left.CheckComparable(right)); 26 | if (left.IsNull() || right.IsNull()) { 27 | return CmpBool::CmpNull; 28 | } 29 | return BOOLEAN_COMPARE_FUNC(==); // NOLINT 30 | } 31 | 32 | CmpBool BooleanType::CompareNotEquals(const Value &left, const Value &right) const { 33 | assert(GetTypeId() == TypeId::BOOLEAN); 34 | assert(left.CheckComparable(right)); 35 | if (left.IsNull() || right.IsNull()) { 36 | return CmpBool::CmpNull; 37 | } 38 | return BOOLEAN_COMPARE_FUNC(!=); // NOLINT 39 | } 40 | 41 | CmpBool BooleanType::CompareLessThan(const Value &left, const Value &right) const { 42 | assert(GetTypeId() == TypeId::BOOLEAN); 43 | assert(left.CheckComparable(right)); 44 | if (left.IsNull() || right.IsNull()) { 45 | return CmpBool::CmpNull; 46 | } 47 | return BOOLEAN_COMPARE_FUNC(<); // NOLINT 48 | } 49 | 50 | CmpBool BooleanType::CompareLessThanEquals(const Value &left, const Value &right) const { 51 | assert(GetTypeId() == TypeId::BOOLEAN); 52 | assert(left.CheckComparable(right)); 53 | if (left.IsNull() || right.IsNull()) { 54 | return CmpBool::CmpNull; 55 | } 56 | return BOOLEAN_COMPARE_FUNC(<=); // NOLINT 57 | } 58 | 59 | CmpBool BooleanType::CompareGreaterThan(const Value &left, const Value &right) const { 60 | assert(GetTypeId() == TypeId::BOOLEAN); 61 | assert(left.CheckComparable(right)); 62 | if (left.IsNull() || right.IsNull()) { 63 | return CmpBool::CmpNull; 64 | } 65 | return BOOLEAN_COMPARE_FUNC(>); // NOLINT 66 | } 67 | 68 | CmpBool BooleanType::CompareGreaterThanEquals(const Value &left, const Value &right) const { 69 | assert(GetTypeId() == TypeId::BOOLEAN); 70 | assert(left.CheckComparable(right)); 71 | if (left.IsNull() || right.IsNull()) { 72 | return CmpBool::CmpNull; 73 | } 74 | return BOOLEAN_COMPARE_FUNC(>=); // NOLINT 75 | } 76 | 77 | std::string BooleanType::ToString(const Value &val) const { 78 | assert(GetTypeId() == TypeId::BOOLEAN); 79 | if (val.value_.boolean_ == 1) { 80 | return "true"; 81 | } 82 | if (val.value_.boolean_ == 0) { 83 | return "false"; 84 | } 85 | return "boolean_null"; 86 | } 87 | 88 | void BooleanType::SerializeTo(const Value &val, char *storage) const { 89 | *reinterpret_cast(storage) = val.value_.boolean_; 90 | } 91 | 92 | // Deserialize a value of the given type from the given storage space. 93 | Value BooleanType::DeserializeFrom(const char *storage) const { 94 | int8_t val = *reinterpret_cast(storage); 95 | return Value(TypeId::BOOLEAN, val); 96 | } 97 | 98 | Value BooleanType::Copy(const Value &val) const { return Value(TypeId::BOOLEAN, val.value_.boolean_); } 99 | 100 | Value BooleanType::CastAs(const Value &val, const TypeId type_id) const { 101 | switch (type_id) { 102 | case TypeId::BOOLEAN: 103 | return Copy(val); 104 | case TypeId::VARCHAR: { 105 | if (val.IsNull()) { 106 | return Value(TypeId::VARCHAR, nullptr, 0, false); 107 | } 108 | return Value(TypeId::VARCHAR, val.ToString()); 109 | } 110 | default: 111 | break; 112 | } 113 | throw Exception("BOOLEAN is not coercable to " + Type::TypeIdToString(type_id)); 114 | } 115 | } // namespace bustub 116 | -------------------------------------------------------------------------------- /src/include/container/hash/linear_probe_hash_table.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // linear_probe_hash_table.h 6 | // 7 | // Identification: src/include/container/hash/linear_probe_hash_table.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "buffer/buffer_pool_manager.h" 20 | #include "concurrency/transaction.h" 21 | #include "container/hash/hash_function.h" 22 | #include "container/hash/hash_table.h" 23 | #include "storage/page/hash_table_block_page.h" 24 | #include "storage/page/hash_table_header_page.h" 25 | #include "storage/page/hash_table_page_defs.h" 26 | 27 | namespace bustub { 28 | 29 | #define HASH_TABLE_TYPE LinearProbeHashTable 30 | 31 | /** 32 | * Implementation of linear probing hash table that is backed by a buffer pool 33 | * manager. Non-unique keys are supported. Supports insert and delete. The 34 | * table dynamically grows once full. 35 | */ 36 | template 37 | class LinearProbeHashTable : public HashTable { 38 | public: 39 | /** 40 | * Creates a new LinearProbeHashTable 41 | * 42 | * @param buffer_pool_manager buffer pool manager to be used 43 | * @param comparator comparator for keys 44 | * @param num_buckets initial number of buckets contained by this hash table 45 | * @param hash_fn the hash function 46 | */ 47 | explicit LinearProbeHashTable(const std::string &name, BufferPoolManager *buffer_pool_manager, 48 | const KeyComparator &comparator, size_t num_buckets, HashFunction hash_fn); 49 | 50 | /** 51 | * Inserts a key-value pair into the hash table. 52 | * @param transaction the current transaction 53 | * @param key the key to create 54 | * @param value the value to be associated with the key 55 | * @return true if insert succeeded, false otherwise 56 | */ 57 | bool Insert(Transaction *transaction, const KeyType &key, const ValueType &value) override; 58 | 59 | /** 60 | * Deletes the associated value for the given key. 61 | * @param transaction the current transaction 62 | * @param key the key to delete 63 | * @param value the value to delete 64 | * @return true if remove succeeded, false otherwise 65 | */ 66 | bool Remove(Transaction *transaction, const KeyType &key, const ValueType &value) override; 67 | 68 | /** 69 | * Performs a point query on the hash table. 70 | * @param transaction the current transaction 71 | * @param key the key to look up 72 | * @param[out] result the value(s) associated with a given key 73 | * @return the value(s) associated with the given key 74 | */ 75 | bool GetValue(Transaction *transaction, const KeyType &key, std::vector *result) override; 76 | 77 | /** 78 | * Resizes the table to at least twice the initial size provided. 79 | * @param initial_size the initial size of the hash table 80 | */ 81 | void Resize(size_t initial_size); 82 | 83 | /** 84 | * Gets the size of the hash table 85 | * @return current size of the hash table 86 | */ 87 | size_t GetSize(); 88 | 89 | private: 90 | /** 91 | * Gets the block index and the bucket index of the hash table 92 | */ 93 | void GetIndex(const KeyType &key, const size_t &num_buckets, size_t &index, size_t &block_ind, size_t &bucket_ind); 94 | 95 | // member variable 96 | page_id_t header_page_id_; 97 | BufferPoolManager *buffer_pool_manager_; 98 | KeyComparator comparator_; 99 | 100 | // Readers includes inserts and removes, writer is only resize 101 | ReaderWriterLatch table_latch_; 102 | 103 | // Hash function 104 | HashFunction hash_fn_; 105 | 106 | }; 107 | 108 | } // namespace bustub 109 | -------------------------------------------------------------------------------- /src/include/storage/table/table_heap.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // table_heap.h 6 | // 7 | // Identification: src/include/storage/table/table_heap.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include "buffer/buffer_pool_manager.h" 16 | #include "recovery/log_manager.h" 17 | #include "storage/page/table_page.h" 18 | #include "storage/table/table_iterator.h" 19 | #include "storage/table/tuple.h" 20 | 21 | namespace bustub { 22 | 23 | /** 24 | * TableHeap represents a physical table on disk. 25 | * This is just a doubly-linked list of pages. 26 | */ 27 | class TableHeap { 28 | friend class TableIterator; 29 | 30 | public: 31 | ~TableHeap() = default; 32 | 33 | /** 34 | * Create a table heap without a transaction. (open table) 35 | * @param buffer_pool_manager the buffer pool manager 36 | * @param lock_manager the lock manager 37 | * @param log_manager the log manager 38 | * @param first_page_id the id of the first page 39 | */ 40 | TableHeap(BufferPoolManager *buffer_pool_manager, LockManager *lock_manager, LogManager *log_manager, 41 | page_id_t first_page_id); 42 | 43 | /** 44 | * Create a table heap with a transaction. (create table) 45 | * @param buffer_pool_manager the buffer pool manager 46 | * @param lock_manager the lock manager 47 | * @param log_manager the log manager 48 | * @param txn the creating transaction 49 | */ 50 | TableHeap(BufferPoolManager *buffer_pool_manager, LockManager *lock_manager, LogManager *log_manager, 51 | Transaction *txn); 52 | 53 | /** 54 | * Insert a tuple into the table. If the tuple is too large (>= page_size), return false. 55 | * @param tuple tuple to insert 56 | * @param[out] rid the rid of the inserted tuple 57 | * @param txn the transaction performing the insert 58 | * @return true iff the insert is successful 59 | */ 60 | bool InsertTuple(const Tuple &tuple, RID *rid, Transaction *txn); 61 | 62 | /** 63 | * Mark the tuple as deleted. The actual delete will occur when ApplyDelete is called. 64 | * @param rid resource id of the tuple of delete 65 | * @param txn transaction performing the delete 66 | * @return true iff the delete is successful (i.e the tuple exists) 67 | */ 68 | bool MarkDelete(const RID &rid, Transaction *txn); // for delete 69 | 70 | /** 71 | * if the new tuple is too large to fit in the old page, return false (will delete and insert) 72 | * @param tuple new tuple 73 | * @param rid rid of the old tuple 74 | * @param txn transaction performing the update 75 | * @return true is update is successful. 76 | */ 77 | bool UpdateTuple(const Tuple &tuple, const RID &rid, Transaction *txn); 78 | 79 | /** 80 | * Called on Commit/Abort to actually delete a tuple or rollback an insert. 81 | * @param rid rid of the tuple to delete 82 | * @param txn transaction performing the delete. 83 | */ 84 | void ApplyDelete(const RID &rid, Transaction *txn); 85 | 86 | /** 87 | * Called on abort to rollback a delete. 88 | * @param rid rid of the deleted tuple. 89 | * @param txn transaction performing the rollback 90 | */ 91 | void RollbackDelete(const RID &rid, Transaction *txn); 92 | 93 | /** 94 | * Read a tuple from the table. 95 | * @param rid rid of the tuple to read 96 | * @param tuple output variable for the tuple 97 | * @param txn transaction performing the read 98 | * @return true if the read was successful (i.e. the tuple exists) 99 | */ 100 | bool GetTuple(const RID &rid, Tuple *tuple, Transaction *txn); 101 | 102 | /** @return the begin iterator of this table */ 103 | TableIterator Begin(Transaction *txn); 104 | 105 | /** @return the end iterator of this table */ 106 | TableIterator End(); 107 | 108 | /** @return the id of the first page of this table */ 109 | inline page_id_t GetFirstPageId() const { return first_page_id_; } 110 | 111 | private: 112 | BufferPoolManager *buffer_pool_manager_; 113 | LockManager *lock_manager_; 114 | LogManager *log_manager_; 115 | page_id_t first_page_id_{}; 116 | }; 117 | 118 | } // namespace bustub 119 | -------------------------------------------------------------------------------- /src/include/catalog/column.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // column.h 6 | // 7 | // Identification: src/include/catalog/column.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "common/exception.h" 20 | #include "common/macros.h" 21 | #include "type/type.h" 22 | 23 | namespace bustub { 24 | class AbstractExpression; 25 | 26 | class Column { 27 | friend class Schema; 28 | 29 | public: 30 | /** 31 | * Non-variable-length constructor for creating a Column. 32 | * @param column_name name of the column 33 | * @param type type of the column 34 | * @param expr expression used to create this column 35 | */ 36 | Column(std::string column_name, TypeId type, const AbstractExpression *expr = nullptr) 37 | : column_name_(std::move(column_name)), column_type_(type), fixed_length_(TypeSize(type)), expr_{expr} { 38 | BUSTUB_ASSERT(type != TypeId::VARCHAR, "Wrong constructor for VARCHAR type."); 39 | } 40 | 41 | /** 42 | * Variable-length constructor for creating a Column. 43 | * @param column_name name of the column 44 | * @param type type of column 45 | * @param length length of the varlen 46 | * @param expr expression used to create this column 47 | */ 48 | Column(std::string column_name, TypeId type, uint32_t length, const AbstractExpression *expr = nullptr) 49 | : column_name_(std::move(column_name)), column_type_(type), fixed_length_(TypeSize(type)), expr_{expr} { 50 | BUSTUB_ASSERT(type == TypeId::VARCHAR, "Wrong constructor for non-VARCHAR type."); 51 | } 52 | 53 | /** @return column name */ 54 | std::string GetName() const { return column_name_; } 55 | 56 | /** @return column length */ 57 | uint32_t GetLength() const { 58 | if (IsInlined()) { 59 | return fixed_length_; 60 | } 61 | return variable_length_; 62 | } 63 | 64 | /** @return column fixed length */ 65 | uint32_t GetFixedLength() const { return fixed_length_; } 66 | 67 | /** @return column variable length */ 68 | uint32_t GetVariableLength() const { return variable_length_; } 69 | 70 | /** @return column's offset in the tuple */ 71 | uint32_t GetOffset() const { return column_offset_; } 72 | 73 | /** @return column type */ 74 | TypeId GetType() const { return column_type_; } 75 | 76 | /** @return true if column is inlined, false otherwise */ 77 | bool IsInlined() const { return column_type_ != TypeId::VARCHAR; } 78 | 79 | /** @return a string representation of this column */ 80 | std::string ToString() const; 81 | 82 | /** @return the expression used to create this column */ 83 | const AbstractExpression *GetExpr() const { return expr_; } 84 | 85 | private: 86 | /** 87 | * Return the size in bytes of the type. 88 | * @param type type whose size is to be determined 89 | * @return size in bytes 90 | */ 91 | static uint8_t TypeSize(TypeId type) { 92 | switch (type) { 93 | case TypeId::BOOLEAN: 94 | return 1; 95 | case TypeId::TINYINT: 96 | return 1; 97 | case TypeId::SMALLINT: 98 | return 2; 99 | case TypeId::INTEGER: 100 | return 4; 101 | case TypeId::BIGINT: 102 | case TypeId::DECIMAL: 103 | case TypeId::TIMESTAMP: 104 | return 8; 105 | case TypeId::VARCHAR: 106 | // TODO(Amadou): Confirm this. 107 | return 12; 108 | default: { 109 | UNREACHABLE("Cannot get size of invalid type"); 110 | } 111 | } 112 | } 113 | 114 | /** Column name. */ 115 | std::string column_name_; 116 | 117 | /** Column value's type. */ 118 | TypeId column_type_; 119 | 120 | /** For a non-inlined column, this is the size of a pointer. Otherwise, the size of the fixed length column. */ 121 | uint32_t fixed_length_; 122 | 123 | /** For an inlined column, 0. Otherwise, the length of the variable length column. */ 124 | uint32_t variable_length_{0}; 125 | 126 | /** Column offset in the tuple. */ 127 | uint32_t column_offset_{0}; 128 | 129 | /** Expression used to create this column **/ 130 | const AbstractExpression *expr_; 131 | }; 132 | 133 | } // namespace bustub 134 | --------------------------------------------------------------------------------