├── .gitignore ├── Homework#2-Index ├── 2018Fall │ ├── 2018Fall Homework 2 Index-Q3-BTree.pdf │ ├── 2018Fall Homework 2 Index-Q4-RadixTree.pdf │ └── hw2-sols.pdf ├── 2019Fall │ ├── Homework 2 Index-Q1-CuckooHashing.pdf │ ├── Homework 2 Index-Q2-BplusTree.pdf │ ├── Homework 2 Index-Q3-ExtendibleHashing.pdf │ ├── Homework 2 Index-Q4-SuffixTrees.pdf │ ├── hw2-clean.pdf │ └── hw2-sols.pdf ├── 2020Fall │ ├── 2020Fall Homework 2 Index-Q2-BTree.pdf │ └── hw2-sols.pdf └── README.md ├── Homework#3-JoinAlgorithms ├── Homework3 Q1 SortingAlgorithms.pdf ├── Homework3 Q2 JoinAlgorthms.pdf └── hw3-sols.pdf ├── Homewrok#1-SQL ├── Homework#1-SQL.md ├── tmpQ10.sql ├── tmpQ8.sql └── tmpQ9.sql ├── LICENSE ├── Lecture02-AdvancedSQL ├── 02-advancedsql-notes.pdf └── 02-advancedsql-ppt.pdf ├── Lecture03-DatabaseStorage_I ├── 03-storage1-notes.pdf └── 03-storage1-ppt.pdf ├── Lecture04-DatabaseStorage_II ├── 04-storage2-notes.pdf └── 04-storage2-ppt.pdf ├── Lecture05-BufferPools ├── 05-bufferpool-notes.pdf └── 05-bufferpool-ppt.pdf ├── Lecture06-HashTables ├── 06-hashtables-notes.pdf └── 06-hashtables-ppt.pdf ├── Lecture07-TreeIndexes_I ├── 07-trees1-notes.pdf └── 07-trees1-ppt.pdf ├── Lecture08-TreeIndexes_II ├── 08-trees2-notes.pdf ├── 08-trees2-ppt.pdf └── BplusTree_algorithm.pdf ├── Lecture09-IndexConcurrency ├── 09-indexconcurrency-notes.pdf └── 09-indexconcurrency-ppt.pdf ├── Lecture10- Sorting&AggregationAlgorithms ├── 10-sorting-notes.pdf └── 10-sorting-ppt.pdf ├── Lecture11-JoinsAlgorithms ├── 11-joins-notes.pdf └── 11-joins-ppt.pdf ├── Lecture12-QueryExecution_I ├── 12-queryexecution1-notes.pdf └── 12-queryexecution1-ppt.pdf ├── Lecture13-QueryExecution_II ├── 13-queryexecution2-notes.pdf └── 13-queryexecution2-ppt.pdf ├── Lecture14-QueryPlanning&Optimization_I ├── 14-optimization1-notes.pdf └── 14-optimization1-ppt.pdf ├── Lecture15-QueryPlanning&Optimization_II ├── 15-optimization2-notes.pdf └── 15-optimization2-ppt.pdf ├── Lecture16-ConcurrencyControlTheory ├── 16-concurrencycontrol-notes.pdf └── 16-concurrencycontrol-ppt.pdf ├── Lecture17-TwoPhaseLocking ├── 17-twophaselocking-notes.pdf └── 17-twophaselocking-ppt.pdf ├── Lecture18-TimeStampOrdering ├── 18-timestampordering-notes.pdf └── 18-timestampordering-ppt.pdf ├── Project#1-BufferPoolManager ├── README.md ├── src │ ├── buffer │ │ ├── buffer_pool_manager.cpp │ │ └── lru_replacer.cpp │ └── include │ │ └── buffer │ │ ├── buffer_pool_manager.h │ │ └── lru_replacer.h └── test │ └── buffer │ ├── buffer_pool_manager_test.cpp │ ├── clock_replacer_test.cpp │ ├── counter.h │ ├── lru_replacer_test.cpp │ └── mock_buffer_pool_manager.h ├── Project#2-BplusTreeIndex ├── README.md ├── src │ ├── buffer │ │ ├── buffer_pool_manager.cpp │ │ └── lru_replacer.cpp │ ├── include │ │ ├── buffer │ │ │ ├── buffer_pool_manager.h │ │ │ └── lru_replacer.h │ │ └── storage │ │ │ ├── index │ │ │ ├── b_plus_tree.h │ │ │ └── index_iterator.h │ │ │ └── page │ │ │ ├── b_plus_tree_internal_page.h │ │ │ ├── b_plus_tree_leaf_page.h │ │ │ └── b_plus_tree_page.h │ └── storage │ │ ├── index │ │ ├── b_plus_tree.cpp │ │ └── index_iterator.cpp │ │ └── page │ │ ├── b_plus_tree_internal_page.cpp │ │ ├── b_plus_tree_leaf_page.cpp │ │ └── b_plus_tree_page.cpp └── test │ ├── buffer │ ├── buffer_pool_manager_test.cpp │ ├── clock_replacer_test.cpp │ ├── counter.h │ ├── lru_replacer_test.cpp │ └── mock_buffer_pool_manager.h │ └── storage │ ├── b_plus_tree_concurrent_test.cpp │ ├── b_plus_tree_delete_test.cpp │ ├── b_plus_tree_insert_test.cpp │ ├── b_plus_tree_print_test.cpp │ ├── b_plus_tree_test_util.h │ ├── disk_manager_test.cpp │ └── tmp_tuple_page_test.cpp ├── Project#3-QueryExecution └── src │ ├── buffer │ ├── buffer_pool_manager.cpp │ └── lru_replacer.cpp │ ├── execution │ ├── aggregation_executor.cpp │ ├── delete_executor.cpp │ ├── executor_factory.cpp │ ├── index_scan_executor.cpp │ ├── insert_executor.cpp │ ├── limit_executor.cpp │ ├── nested_index_join_executor.cpp │ ├── nested_loop_join_executor.cpp │ ├── seq_scan_executor.cpp │ └── update_executor.cpp │ ├── include │ ├── buffer │ │ ├── buffer_pool_manager.h │ │ └── lru_replacer.h │ ├── catalog │ │ └── catalog.h │ ├── execution │ │ ├── execution_engine.h │ │ ├── executor_factory.h │ │ └── executors │ │ │ ├── aggregation_executor.h │ │ │ ├── delete_executor.h │ │ │ ├── index_scan_executor.h │ │ │ ├── insert_executor.h │ │ │ ├── limit_executor.h │ │ │ ├── nested_index_join_executor.h │ │ │ ├── nested_loop_join_executor.h │ │ │ ├── seq_scan_executor.h │ │ │ └── update_executor.h │ └── storage │ │ ├── index │ │ ├── b_plus_tree.h │ │ ├── b_plus_tree_index.h │ │ ├── index.h │ │ └── index_iterator.h │ │ └── page │ │ ├── b_plus_tree_internal_page.h │ │ ├── b_plus_tree_leaf_page.h │ │ └── b_plus_tree_page.h │ └── storage │ ├── index │ ├── b_plus_tree.cpp │ ├── b_plus_tree_index.cpp │ └── index_iterator.cpp │ └── page │ ├── b_plus_tree_internal_page.cpp │ ├── b_plus_tree_leaf_page.cpp │ └── b_plus_tree_page.cpp └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | assets 35 | .vscode -------------------------------------------------------------------------------- /Homework#2-Index/2018Fall/2018Fall Homework 2 Index-Q3-BTree.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#2-Index/2018Fall/2018Fall Homework 2 Index-Q3-BTree.pdf -------------------------------------------------------------------------------- /Homework#2-Index/2018Fall/2018Fall Homework 2 Index-Q4-RadixTree.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#2-Index/2018Fall/2018Fall Homework 2 Index-Q4-RadixTree.pdf -------------------------------------------------------------------------------- /Homework#2-Index/2018Fall/hw2-sols.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#2-Index/2018Fall/hw2-sols.pdf -------------------------------------------------------------------------------- /Homework#2-Index/2019Fall/Homework 2 Index-Q1-CuckooHashing.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#2-Index/2019Fall/Homework 2 Index-Q1-CuckooHashing.pdf -------------------------------------------------------------------------------- /Homework#2-Index/2019Fall/Homework 2 Index-Q2-BplusTree.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#2-Index/2019Fall/Homework 2 Index-Q2-BplusTree.pdf -------------------------------------------------------------------------------- /Homework#2-Index/2019Fall/Homework 2 Index-Q3-ExtendibleHashing.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#2-Index/2019Fall/Homework 2 Index-Q3-ExtendibleHashing.pdf -------------------------------------------------------------------------------- /Homework#2-Index/2019Fall/Homework 2 Index-Q4-SuffixTrees.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#2-Index/2019Fall/Homework 2 Index-Q4-SuffixTrees.pdf -------------------------------------------------------------------------------- /Homework#2-Index/2019Fall/hw2-clean.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#2-Index/2019Fall/hw2-clean.pdf -------------------------------------------------------------------------------- /Homework#2-Index/2019Fall/hw2-sols.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#2-Index/2019Fall/hw2-sols.pdf -------------------------------------------------------------------------------- /Homework#2-Index/2020Fall/2020Fall Homework 2 Index-Q2-BTree.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#2-Index/2020Fall/2020Fall Homework 2 Index-Q2-BTree.pdf -------------------------------------------------------------------------------- /Homework#2-Index/2020Fall/hw2-sols.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#2-Index/2020Fall/hw2-sols.pdf -------------------------------------------------------------------------------- /Homework#2-Index/README.md: -------------------------------------------------------------------------------- 1 | ## 2018 Fall 2 | 3 | - [x] Q3 B-plus Tree 4 | - [x] Q5 Skip List and Radix Tree 5 | 6 | ## 2019 Fall 7 | 8 | - [x] Q1 Cuckoo Hashing 9 | - [x] Q2 B-plus Tree 10 | - [x] Q3 Extendible Hashing 11 | - [x] Q4 Suffix Tree 12 | 13 | ## 2020 Fall 14 | 15 | - [x] Q2 B-plus Tree -------------------------------------------------------------------------------- /Homework#3-JoinAlgorithms/Homework3 Q1 SortingAlgorithms.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#3-JoinAlgorithms/Homework3 Q1 SortingAlgorithms.pdf -------------------------------------------------------------------------------- /Homework#3-JoinAlgorithms/Homework3 Q2 JoinAlgorthms.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#3-JoinAlgorithms/Homework3 Q2 JoinAlgorthms.pdf -------------------------------------------------------------------------------- /Homework#3-JoinAlgorithms/hw3-sols.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Homework#3-JoinAlgorithms/hw3-sols.pdf -------------------------------------------------------------------------------- /Homewrok#1-SQL/tmpQ10.sql: -------------------------------------------------------------------------------- 1 | with storm_count as ( 2 | select 3 | s.zip_code, 4 | s.station_id, 5 | s.station_name, 6 | count(*) as cnt 7 | from 8 | weather as w, 9 | station as s, 10 | trip as t 11 | where 12 | date(t.start_time) = w.date 13 | and t.start_station_id = s.station_id 14 | and s.zip_code = w.zip_code 15 | and events = 'Rain-Thunderstorm' 16 | group by 17 | s.zip_code, 18 | s.station_id 19 | ) 20 | select 21 | zip_code, 22 | station_name, 23 | cnt 24 | from 25 | storm_count 26 | where 27 | cnt = ( 28 | select 29 | max(max_s_c.cnt) 30 | from 31 | storm_count as max_s_c 32 | where 33 | storm_count.zip_code = max_s_c.zip_code 34 | ) 35 | order by 36 | zip_code asc; -------------------------------------------------------------------------------- /Homewrok#1-SQL/tmpQ8.sql: -------------------------------------------------------------------------------- 1 | with event_cnt (events, cnt) as ( 2 | select 3 | events, 4 | count(distinct date) as cnt 5 | from 6 | weather 7 | group by 8 | events 9 | ) 10 | select 11 | weather.events, 12 | round(1.0 * count(distinct trip.id) / event_cnt.cnt, 4) as avg_num 13 | from 14 | trip, 15 | station, 16 | weather, 17 | event_cnt 18 | where 19 | start_station_id = station_id 20 | and date(trip.start_time) = weather.date 21 | and station.zip_code = weather.zip_code 22 | and weather.events = event_cnt.events 23 | group by 24 | weather.events 25 | order by 26 | avg_num desc, 27 | weather.events asc; 28 | 29 | with event_cnt (events, cnt) as ( 30 | select 31 | events, 32 | count(distinct date) as cnt 33 | from 34 | weather 35 | group by 36 | events 37 | ) 38 | select 39 | w.events, 40 | round(1.0 * count(distinct t.id) / event_cnt.cnt, 4) as avg_num 41 | from 42 | trip as t, 43 | station as s, 44 | weather as w, 45 | event_cnt 46 | where 47 | t.start_station_id = s.station_id 48 | and date(t.start_time) = w.date 49 | and s.zip_code = w.zip_code 50 | and w.events = event_cnt.events 51 | group by 52 | w.events 53 | order by 54 | avg_num desc, 55 | w.events asc -------------------------------------------------------------------------------- /Homewrok#1-SQL/tmpQ9.sql: -------------------------------------------------------------------------------- 1 | select 2 | round(1.0 * sum(mean_temp) / count(*), 4) as temp 3 | from 4 | trip, 5 | station, 6 | weather 7 | where 8 | strftime("%s", end_time) - strftime("%s", start_time) <= 60 9 | and start_station_id = station_id 10 | and station.zip_code = weather.zip_code 11 | and date(start_time) = date; 12 | 13 | -- 14 | -- 15 | -- 16 | select 17 | round(1.0 * sum(mean_temp) / count(*), 4) as temp 18 | from 19 | trip, 20 | station, 21 | weather 22 | where 23 | strftime("%s", end_time) - strftime("%s", start_time) > 60 24 | and start_station_id = station_id 25 | and station.zip_code = weather.zip_code 26 | and date(start_time) = date; 27 | 28 | -- 29 | -- 30 | select 31 | short_trip.temp, 32 | long_trip.temp 33 | from 34 | ( 35 | select 36 | round(1.0 * sum(mean_temp) / count(*), 4) as temp 37 | from 38 | trip, 39 | station, 40 | weather 41 | where 42 | strftime("%s", end_time) - strftime("%s", start_time) <= 60 43 | and start_station_id = station_id 44 | and station.zip_code = weather.zip_code 45 | and date(start_time) = date 46 | ) as short_trip, 47 | ( 48 | select 49 | round(1.0 * sum(mean_temp) / count(*), 4) as temp 50 | from 51 | trip, 52 | station, 53 | weather 54 | where 55 | strftime("%s", end_time) - strftime("%s", start_time) > 60 56 | and start_station_id = station_id 57 | and station.zip_code = weather.zip_code 58 | and date(start_time) = date 59 | ) as long_trip; 60 | 61 | -- 62 | select 63 | short_trip.temp, 64 | long_trip.temp 65 | from 66 | ( 67 | select 68 | round(1.0 * sum(mean_temp) / count(*), 4) as temp 69 | from 70 | trip, 71 | station, 72 | weather 73 | where 74 | strftime("%s", end_time) - strftime("%s", start_time) <= 60 75 | and start_station_id = station_id 76 | and station.zip_code = weather.zip_code 77 | and date(start_time) = weather.date 78 | ) as short_trip, 79 | ( 80 | select 81 | round(1.0 * sum(mean_temp) / count(*), 4) as temp 82 | from 83 | trip, 84 | station, 85 | weather 86 | where 87 | strftime("%s", end_time) - strftime("%s", start_time) > 60 88 | and start_station_id = station_id 89 | and station.zip_code = weather.zip_code 90 | and date(start_time) = weather.date 91 | ) as long_trip; -------------------------------------------------------------------------------- /Lecture02-AdvancedSQL/02-advancedsql-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture02-AdvancedSQL/02-advancedsql-notes.pdf -------------------------------------------------------------------------------- /Lecture02-AdvancedSQL/02-advancedsql-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture02-AdvancedSQL/02-advancedsql-ppt.pdf -------------------------------------------------------------------------------- /Lecture03-DatabaseStorage_I/03-storage1-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture03-DatabaseStorage_I/03-storage1-notes.pdf -------------------------------------------------------------------------------- /Lecture03-DatabaseStorage_I/03-storage1-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture03-DatabaseStorage_I/03-storage1-ppt.pdf -------------------------------------------------------------------------------- /Lecture04-DatabaseStorage_II/04-storage2-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture04-DatabaseStorage_II/04-storage2-notes.pdf -------------------------------------------------------------------------------- /Lecture04-DatabaseStorage_II/04-storage2-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture04-DatabaseStorage_II/04-storage2-ppt.pdf -------------------------------------------------------------------------------- /Lecture05-BufferPools/05-bufferpool-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture05-BufferPools/05-bufferpool-notes.pdf -------------------------------------------------------------------------------- /Lecture05-BufferPools/05-bufferpool-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture05-BufferPools/05-bufferpool-ppt.pdf -------------------------------------------------------------------------------- /Lecture06-HashTables/06-hashtables-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture06-HashTables/06-hashtables-notes.pdf -------------------------------------------------------------------------------- /Lecture06-HashTables/06-hashtables-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture06-HashTables/06-hashtables-ppt.pdf -------------------------------------------------------------------------------- /Lecture07-TreeIndexes_I/07-trees1-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture07-TreeIndexes_I/07-trees1-notes.pdf -------------------------------------------------------------------------------- /Lecture07-TreeIndexes_I/07-trees1-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture07-TreeIndexes_I/07-trees1-ppt.pdf -------------------------------------------------------------------------------- /Lecture08-TreeIndexes_II/08-trees2-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture08-TreeIndexes_II/08-trees2-notes.pdf -------------------------------------------------------------------------------- /Lecture08-TreeIndexes_II/08-trees2-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture08-TreeIndexes_II/08-trees2-ppt.pdf -------------------------------------------------------------------------------- /Lecture08-TreeIndexes_II/BplusTree_algorithm.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture08-TreeIndexes_II/BplusTree_algorithm.pdf -------------------------------------------------------------------------------- /Lecture09-IndexConcurrency/09-indexconcurrency-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture09-IndexConcurrency/09-indexconcurrency-notes.pdf -------------------------------------------------------------------------------- /Lecture09-IndexConcurrency/09-indexconcurrency-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture09-IndexConcurrency/09-indexconcurrency-ppt.pdf -------------------------------------------------------------------------------- /Lecture10- Sorting&AggregationAlgorithms/10-sorting-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture10- Sorting&AggregationAlgorithms/10-sorting-notes.pdf -------------------------------------------------------------------------------- /Lecture10- Sorting&AggregationAlgorithms/10-sorting-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture10- Sorting&AggregationAlgorithms/10-sorting-ppt.pdf -------------------------------------------------------------------------------- /Lecture11-JoinsAlgorithms/11-joins-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture11-JoinsAlgorithms/11-joins-notes.pdf -------------------------------------------------------------------------------- /Lecture11-JoinsAlgorithms/11-joins-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture11-JoinsAlgorithms/11-joins-ppt.pdf -------------------------------------------------------------------------------- /Lecture12-QueryExecution_I/12-queryexecution1-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture12-QueryExecution_I/12-queryexecution1-notes.pdf -------------------------------------------------------------------------------- /Lecture12-QueryExecution_I/12-queryexecution1-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture12-QueryExecution_I/12-queryexecution1-ppt.pdf -------------------------------------------------------------------------------- /Lecture13-QueryExecution_II/13-queryexecution2-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture13-QueryExecution_II/13-queryexecution2-notes.pdf -------------------------------------------------------------------------------- /Lecture13-QueryExecution_II/13-queryexecution2-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture13-QueryExecution_II/13-queryexecution2-ppt.pdf -------------------------------------------------------------------------------- /Lecture14-QueryPlanning&Optimization_I/14-optimization1-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture14-QueryPlanning&Optimization_I/14-optimization1-notes.pdf -------------------------------------------------------------------------------- /Lecture14-QueryPlanning&Optimization_I/14-optimization1-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture14-QueryPlanning&Optimization_I/14-optimization1-ppt.pdf -------------------------------------------------------------------------------- /Lecture15-QueryPlanning&Optimization_II/15-optimization2-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture15-QueryPlanning&Optimization_II/15-optimization2-notes.pdf -------------------------------------------------------------------------------- /Lecture15-QueryPlanning&Optimization_II/15-optimization2-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture15-QueryPlanning&Optimization_II/15-optimization2-ppt.pdf -------------------------------------------------------------------------------- /Lecture16-ConcurrencyControlTheory/16-concurrencycontrol-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture16-ConcurrencyControlTheory/16-concurrencycontrol-notes.pdf -------------------------------------------------------------------------------- /Lecture16-ConcurrencyControlTheory/16-concurrencycontrol-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture16-ConcurrencyControlTheory/16-concurrencycontrol-ppt.pdf -------------------------------------------------------------------------------- /Lecture17-TwoPhaseLocking/17-twophaselocking-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture17-TwoPhaseLocking/17-twophaselocking-notes.pdf -------------------------------------------------------------------------------- /Lecture17-TwoPhaseLocking/17-twophaselocking-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture17-TwoPhaseLocking/17-twophaselocking-ppt.pdf -------------------------------------------------------------------------------- /Lecture18-TimeStampOrdering/18-timestampordering-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture18-TimeStampOrdering/18-timestampordering-notes.pdf -------------------------------------------------------------------------------- /Lecture18-TimeStampOrdering/18-timestampordering-ppt.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Waldenth/CMU15-445-IntroToDatabaseSystems/521e9de847019fe9e06d3531016d2e5d05ad1ab7/Lecture18-TimeStampOrdering/18-timestampordering-ppt.pdf -------------------------------------------------------------------------------- /Project#1-BufferPoolManager/README.md: -------------------------------------------------------------------------------- 1 | 所有`*_test.cpp`都要把`DISABLED_SampleTest`改成`SampleTest`,删除前缀`DISABLED_` 2 | 3 | 切到2020-Fall commit下,2021有的类设计改了(DiskManager) 4 | 5 | # 坑死我了!!!! 6 | 7 | - [x] TASK #1 - LRU REPLACEMENT POLICY 8 | - [x] TASK #2 - BUFFER POOL MANAGER 9 | - [x] TASK ADDITIONAL CLOCK POLICY 10 | 11 | ```bash 12 | aaron@ubuntu:~/CMU15-445/Lab1BUSTUB/bustub$ sudo su 13 | root@ubuntu:/home/aaron/CMU15-445/Lab1BUSTUB/bustub# cd build 14 | root@ubuntu:/home/aaron/CMU15-445/Lab1BUSTUB/bustub/build# make lru_replacer_test 15 | [ 3%] Built target thirdparty_murmur3 16 | [ 86%] Built target bustub_shared 17 | [ 90%] Built target gtest 18 | [ 93%] Built target gmock 19 | [ 96%] Built target gmock_main 20 | [ 98%] Linking CXX executable lru_replacer_test 21 | [100%] Built target lru_replacer_test 22 | root@ubuntu:/home/aaron/CMU15-445/Lab1BUSTUB/bustub/build# ./test/lru_replacer_test 23 | Running main() from gmock_main.cc 24 | [==========] Running 1 test from 1 test suite. 25 | [----------] Global test environment set-up. 26 | [----------] 1 test from LRUReplacerTest 27 | [ RUN ] LRUReplacerTest.SampleTest 28 | [ OK ] LRUReplacerTest.SampleTest (0 ms) 29 | [----------] 1 test from LRUReplacerTest (0 ms total) 30 | 31 | [----------] Global test environment tear-down 32 | [==========] 1 test from 1 test suite ran. (0 ms total) 33 | [ PASSED ] 1 test. 34 | root@ubuntu:/home/aaron/CMU15-445/Lab1BUSTUB/bustub/build# make clock_replacer_test 35 | [ 3%] Built target thirdparty_murmur3 36 | [ 86%] Built target bustub_shared 37 | [ 90%] Built target gtest 38 | [ 93%] Built target gmock 39 | [ 96%] Built target gmock_main 40 | [100%] Built target clock_replacer_test 41 | root@ubuntu:/home/aaron/CMU15-445/Lab1BUSTUB/bustub/build# ./test/clock_replacer_test 42 | Running main() from gmock_main.cc 43 | [==========] Running 1 test from 1 test suite. 44 | [----------] Global test environment set-up. 45 | [----------] 1 test from ClockReplacerTest 46 | [ RUN ] ClockReplacerTest.SampleTest 47 | [ OK ] ClockReplacerTest.SampleTest (0 ms) 48 | [----------] 1 test from ClockReplacerTest (0 ms total) 49 | 50 | [----------] Global test environment tear-down 51 | [==========] 1 test from 1 test suite ran. (0 ms total) 52 | [ PASSED ] 1 test. 53 | root@ubuntu:/home/aaron/CMU15-445/Lab1BUSTUB/bustub/build# make buffer_pool_manager_test 54 | [ 3%] Built target thirdparty_murmur3 55 | [ 86%] Built target bustub_shared 56 | [ 90%] Built target gtest 57 | [ 93%] Built target gmock 58 | [ 96%] Built target gmock_main 59 | [ 98%] Linking CXX executable buffer_pool_manager_test 60 | [100%] Built target buffer_pool_manager_test 61 | root@ubuntu:/home/aaron/CMU15-445/Lab1BUSTUB/bustub/build# ./test/buffer_pool_manager_test 62 | Running main() from gmock_main.cc 63 | [==========] Running 2 tests from 1 test suite. 64 | [----------] Global test environment set-up. 65 | [----------] 2 tests from BufferPoolManagerTest 66 | [ RUN ] BufferPoolManagerTest.BinaryDataTest 67 | [ OK ] BufferPoolManagerTest.BinaryDataTest (1 ms) 68 | [ RUN ] BufferPoolManagerTest.SampleTest 69 | [ OK ] BufferPoolManagerTest.SampleTest (0 ms) 70 | [----------] 2 tests from BufferPoolManagerTest (2 ms total) 71 | 72 | [----------] Global test environment tear-down 73 | [==========] 2 tests from 1 test suite ran. (2 ms total) 74 | [ PASSED ] 2 tests. 75 | ``` 76 | 77 | -------------------------------------------------------------------------------- /Project#1-BufferPoolManager/src/buffer/lru_replacer.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // lru_replacer.cpp 6 | // 7 | // Identification: src/buffer/lru_replacer.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "buffer/lru_replacer.h" 14 | 15 | namespace bustub { 16 | 17 | LRUReplacer::LRUReplacer(size_t num_pages) : capacity{num_pages} {} 18 | 19 | LRUReplacer::~LRUReplacer() = default; 20 | 21 | /** 22 | * 根据LRU策略从LRU lst中找到牺牲页,(lst 最前面的元素是最早加进来的) 23 | * 1.如果没有可以牺牲的page直接返回false 24 | * 2.如果有的话选择在链表尾部的page, remove它即可. 这里的删除涉及链表和hash表两个数据结构的删除 25 | * 3.为了防止并发错误,以下操作均需要加锁 26 | */ 27 | bool LRUReplacer::Victim(frame_id_t *frame_id) { 28 | // 在lock_guard对象构造时,传入的mutex对象会被当前线程锁住 29 | const std::lock_guard guard(mutex); 30 | 31 | if (lst.empty()) { 32 | return false; 33 | } 34 | 35 | auto f = lst.front(); 36 | lst.pop_front(); 37 | 38 | // map.find()如果未找到则返回引用map.end()的迭代器 39 | auto hash_it = hash.find(f); 40 | 41 | if (hash_it != hash.end()) { // 如果不是没有找到元素 42 | hash.erase(hash_it); 43 | *frame_id = f; 44 | return true; 45 | } 46 | 47 | return false; 48 | } 49 | 50 | /** 51 | * 在将某page固定到BufferPoolManager中的某一frame之后,应调用此方法Pin() 52 | * 此方法应该从LRUReplacer中删除包含这个已经固定的page的某一frame,表示该frame不能成为LRU牺牲的对象 53 | * 54 | * 1.pin函数表示这个frame被某个进程引用了 55 | * 2.被引用的frame不能成为LRU算法的牺牲目标.所以这里把它从我们的数据结构中删除 56 | * 57 | */ 58 | void LRUReplacer::Pin(frame_id_t frame_id) { 59 | const std::lock_guard guard(mutex); 60 | 61 | // hash是一个unordered_map; key=frame_id_t , value=list lst的迭代器 62 | // hash_it尝试找到hash中Key=frame_id的键值对,返回指向该KV的迭代器 63 | auto hash_it = hash.find(frame_id); 64 | if (hash_it != hash.end()) { 65 | // erase()方法是删除iterator指定的节点 66 | lst.erase(hash_it->second); // 从lst中删除该页 (hash_it->second是指向该页的迭代器) 67 | hash.erase(hash_it); 68 | } 69 | } 70 | 71 | void LRUReplacer::Unpin(frame_id_t frame_id) { 72 | const std::lock_guard guard(mutex); 73 | 74 | if (hash.size() >= capacity) { 75 | return; 76 | } 77 | 78 | // This step of logical processing is very IMPORTANT 79 | // BUT I DO NOT KNOW THE REASON 80 | auto hash_it = hash.find(frame_id); 81 | 82 | if (hash_it != hash.end()) { 83 | return; 84 | } 85 | 86 | /* 87 | if (hash_it == hash.end()) { 88 | while (hash.size() >= capacity) { 89 | frame_id_t need_del = lst.back(); 90 | lst.pop_back(); 91 | if (hash.find(need_del) != hash.end()) { 92 | hash.erase(need_del); 93 | } 94 | } 95 | } 96 | */ 97 | 98 | lst.push_back(frame_id); 99 | // std::prev(lst.end(),1) 返回lst.end()的前面的距离它为1的元素的迭代器 100 | // 即指向lst的最后一个实际元素的迭代器,也就是lst中指向末尾这个新插入的帧id的迭代器 101 | hash.emplace(frame_id, std::prev(lst.end(), 1)); 102 | } 103 | 104 | size_t LRUReplacer::Size() { 105 | const std::lock_guard guard(mutex); 106 | 107 | return hash.size(); 108 | } 109 | 110 | } // namespace bustub 111 | -------------------------------------------------------------------------------- /Project#1-BufferPoolManager/src/include/buffer/buffer_pool_manager.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // buffer_pool_manager.h 6 | // 7 | // Identification: src/include/buffer/buffer_pool_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 18 | 19 | #include "buffer/lru_replacer.h" 20 | #include "recovery/log_manager.h" 21 | #include "storage/disk/disk_manager.h" 22 | #include "storage/page/page.h" 23 | 24 | namespace bustub { 25 | 26 | /** 27 | * BufferPoolManager reads disk pages to and from its internal buffer pool. 28 | */ 29 | class BufferPoolManager { 30 | public: 31 | enum class CallbackType { BEFORE, AFTER }; 32 | using bufferpool_callback_fn = void (*)(enum CallbackType, const page_id_t page_id); 33 | 34 | /** 35 | * Creates a new BufferPoolManager. 36 | * @param pool_size the size of the buffer pool 37 | * @param disk_manager the disk manager 38 | * @param log_manager the log manager (for testing only: nullptr = disable logging) 39 | */ 40 | BufferPoolManager(size_t pool_size, DiskManager *disk_manager, LogManager *log_manager = nullptr); 41 | 42 | /** 43 | * Destroys an existing BufferPoolManager. 44 | */ 45 | ~BufferPoolManager(); 46 | 47 | /** Grading function. Do not modify! */ 48 | Page *FetchPage(page_id_t page_id, bufferpool_callback_fn callback = nullptr) { 49 | GradingCallback(callback, CallbackType::BEFORE, page_id); 50 | auto *result = FetchPageImpl(page_id); 51 | GradingCallback(callback, CallbackType::AFTER, page_id); 52 | return result; 53 | } 54 | 55 | /** Grading function. Do not modify! */ 56 | bool UnpinPage(page_id_t page_id, bool is_dirty, bufferpool_callback_fn callback = nullptr) { 57 | GradingCallback(callback, CallbackType::BEFORE, page_id); 58 | auto result = UnpinPageImpl(page_id, is_dirty); 59 | GradingCallback(callback, CallbackType::AFTER, page_id); 60 | return result; 61 | } 62 | 63 | /** Grading function. Do not modify! */ 64 | bool FlushPage(page_id_t page_id, bufferpool_callback_fn callback = nullptr) { 65 | GradingCallback(callback, CallbackType::BEFORE, page_id); 66 | auto result = FlushPageImpl(page_id); 67 | GradingCallback(callback, CallbackType::AFTER, page_id); 68 | return result; 69 | } 70 | 71 | /** Grading function. Do not modify! */ 72 | Page *NewPage(page_id_t *page_id, bufferpool_callback_fn callback = nullptr) { 73 | GradingCallback(callback, CallbackType::BEFORE, INVALID_PAGE_ID); 74 | auto *result = NewPageImpl(page_id); 75 | GradingCallback(callback, CallbackType::AFTER, *page_id); 76 | return result; 77 | } 78 | 79 | /** Grading function. Do not modify! */ 80 | bool DeletePage(page_id_t page_id, bufferpool_callback_fn callback = nullptr) { 81 | GradingCallback(callback, CallbackType::BEFORE, page_id); 82 | auto result = DeletePageImpl(page_id); 83 | GradingCallback(callback, CallbackType::AFTER, page_id); 84 | return result; 85 | } 86 | 87 | /** Grading function. Do not modify! */ 88 | void FlushAllPages(bufferpool_callback_fn callback = nullptr) { 89 | GradingCallback(callback, CallbackType::BEFORE, INVALID_PAGE_ID); 90 | FlushAllPagesImpl(); 91 | GradingCallback(callback, CallbackType::AFTER, INVALID_PAGE_ID); 92 | } 93 | 94 | /** @return pointer to all the pages in the buffer pool */ 95 | Page *GetPages() { return pages_; } 96 | 97 | /** @return size of the buffer pool */ 98 | size_t GetPoolSize() { return pool_size_; } 99 | 100 | protected: 101 | /** 102 | * Grading function. Do not modify! 103 | * Invokes the callback function if it is not null. 104 | * @param callback callback function to be invoked 105 | * @param callback_type BEFORE or AFTER 106 | * @param page_id the page id to invoke the callback with 107 | */ 108 | void GradingCallback(bufferpool_callback_fn callback, CallbackType callback_type, page_id_t page_id) { 109 | if (callback != nullptr) { 110 | callback(callback_type, page_id); 111 | } 112 | } 113 | 114 | /** 115 | * Fetch the requested page from the buffer pool. 116 | * @param page_id id of page to be fetched 117 | * @return the requested page 118 | */ 119 | Page *FetchPageImpl(page_id_t page_id); 120 | 121 | /** 122 | * Unpin the target page from the buffer pool. 123 | * @param page_id id of page to be unpinned 124 | * @param is_dirty true if the page should be marked as dirty, false otherwise 125 | * @return false if the page pin count is <= 0 before this call, true otherwise 126 | */ 127 | bool UnpinPageImpl(page_id_t page_id, bool is_dirty); 128 | 129 | /** 130 | * Flushes the target page to disk. 131 | * @param page_id id of page to be flushed, cannot be INVALID_PAGE_ID 132 | * @return false if the page could not be found in the page table, true otherwise 133 | */ 134 | bool FlushPageImpl(page_id_t page_id); 135 | 136 | /** 137 | * Creates a new page in the buffer pool. 138 | * @param[out] page_id id of created page 139 | * @return nullptr if no new pages could be created, otherwise pointer to new page 140 | */ 141 | Page *NewPageImpl(page_id_t *page_id); 142 | 143 | /** 144 | * Deletes a page from the buffer pool. 145 | * @param page_id id of page to be deleted 146 | * @return false if the page exists but could not be deleted, true if the page didn't exist or 147 | * deletion succeeded 148 | */ 149 | bool DeletePageImpl(page_id_t page_id); 150 | 151 | /** 152 | * Flushes all the pages in the buffer pool to disk. 153 | */ 154 | void FlushAllPagesImpl(); 155 | 156 | /** Number of pages in the buffer pool. */ 157 | size_t pool_size_; 158 | /** Array of buffer pool pages. */ 159 | Page *pages_; 160 | /** Pointer to the disk manager. */ 161 | DiskManager *disk_manager_ __attribute__((__unused__)); 162 | /** Pointer to the log manager. */ 163 | LogManager *log_manager_ __attribute__((__unused__)); 164 | /** Page table for keeping track of buffer pool pages. */ 165 | std::unordered_map page_table_; 166 | /** Replacer to find unpinned pages for replacement. */ 167 | Replacer *replacer_; 168 | /** List of free pages. */ 169 | std::list free_list_; 170 | /** 171 | * This latch protects shared data structures. 172 | * We recommend updating this comment to describe what it protects. 173 | * 174 | * latch protects: 175 | * - page_table_ 176 | * - free_list_ 177 | */ 178 | std::mutex latch_; 179 | }; 180 | } // namespace bustub 181 | -------------------------------------------------------------------------------- /Project#1-BufferPoolManager/src/include/buffer/lru_replacer.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // lru_replacer.h 6 | // 7 | // Identification: src/include/buffer/lru_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 | * LRUReplacer implements the lru replacement policy, which approximates the Least Recently Used 26 | * policy. 27 | */ 28 | class LRUReplacer : public Replacer { 29 | using mutex_t = std::mutex; 30 | 31 | public: 32 | /** 33 | * Create a new LRUReplacer. 34 | * @param num_pages the maximum number of pages the LRUReplacer will be required to store 35 | */ 36 | explicit LRUReplacer(size_t num_pages); 37 | 38 | /** 39 | * Destroys the LRUReplacer. 40 | */ 41 | ~LRUReplacer() override; 42 | 43 | bool Victim(frame_id_t *frame_id) override; 44 | 45 | void Pin(frame_id_t frame_id) override; 46 | 47 | void Unpin(frame_id_t frame_id) override; 48 | 49 | size_t Size() override; 50 | 51 | private: 52 | // TODO(student): implement me! 53 | mutex_t mutex; 54 | size_t capacity; 55 | std::list lst; 56 | std::unordered_map::iterator> hash; 57 | }; 58 | 59 | } // namespace bustub 60 | -------------------------------------------------------------------------------- /Project#1-BufferPoolManager/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 "buffer/buffer_pool_manager.h" 14 | #include 15 | #include 16 | #include 17 | #include "gtest/gtest.h" 18 | 19 | namespace bustub { 20 | 21 | // NOLINTNEXTLINE 22 | // Check whether pages containing terminal characters can be recovered 23 | TEST(BufferPoolManagerTest, BinaryDataTest) { 24 | const std::string db_name = "test.db"; 25 | const size_t buffer_pool_size = 10; 26 | 27 | std::random_device r; 28 | std::default_random_engine rng(r()); 29 | std::uniform_int_distribution uniform_dist(0); 30 | 31 | auto* disk_manager = new DiskManager(db_name); 32 | auto* bpm = new BufferPoolManager(buffer_pool_size, disk_manager); 33 | 34 | page_id_t page_id_temp; 35 | auto* page0 = bpm->NewPage(&page_id_temp); 36 | 37 | // Scenario: The buffer pool is empty. We should be able to create a new page. 38 | ASSERT_NE(nullptr, page0); 39 | EXPECT_EQ(0, page_id_temp); 40 | 41 | char random_binary_data[PAGE_SIZE]; 42 | // Generate random binary data 43 | for (char& i : random_binary_data) { 44 | i = uniform_dist(rng); 45 | } 46 | 47 | // Insert terminal characters both in the middle and at end 48 | random_binary_data[PAGE_SIZE / 2] = '\0'; 49 | random_binary_data[PAGE_SIZE - 1] = '\0'; 50 | 51 | // Scenario: Once we have a page, we should be able to read and write content. 52 | std::memcpy(page0->GetData(), random_binary_data, PAGE_SIZE); 53 | EXPECT_EQ(0, std::memcmp(page0->GetData(), random_binary_data, PAGE_SIZE)); 54 | 55 | // Scenario: We should be able to create new pages until we fill up the buffer pool. 56 | for (size_t i = 1; i < buffer_pool_size; ++i) { 57 | EXPECT_NE(nullptr, bpm->NewPage(&page_id_temp)); 58 | } 59 | 60 | // Scenario: Once the buffer pool is full, we should not be able to create any new pages. 61 | for (size_t i = buffer_pool_size; i < buffer_pool_size * 2; ++i) { 62 | EXPECT_EQ(nullptr, bpm->NewPage(&page_id_temp)); 63 | } 64 | 65 | // Scenario: After unpinning pages {0, 1, 2, 3, 4} and pinning another 4 new pages, 66 | // there would still be one cache frame left for reading page 0. 67 | for (int i = 0; i < 5; ++i) { 68 | EXPECT_EQ(true, bpm->UnpinPage(i, true)); 69 | bpm->FlushPage(i); 70 | } 71 | for (int i = 0; i < 5; ++i) { 72 | EXPECT_NE(nullptr, bpm->NewPage(&page_id_temp)); 73 | bpm->UnpinPage(page_id_temp, false); 74 | } 75 | // Scenario: We should be able to fetch the data we wrote a while ago. 76 | page0 = bpm->FetchPage(0); 77 | EXPECT_EQ(0, memcmp(page0->GetData(), random_binary_data, PAGE_SIZE)); 78 | EXPECT_EQ(true, bpm->UnpinPage(0, true)); 79 | 80 | // Shutdown the disk manager and remove the temporary file we created. 81 | disk_manager->ShutDown(); 82 | remove("test.db"); 83 | remove("test.log"); 84 | 85 | delete bpm; 86 | delete disk_manager; 87 | } 88 | 89 | // NOLINTNEXTLINE 90 | TEST(BufferPoolManagerTest, SampleTest) { 91 | const std::string db_name = "test.db"; 92 | const size_t buffer_pool_size = 10; 93 | 94 | auto* disk_manager = new DiskManager(db_name); 95 | auto* bpm = new BufferPoolManager(buffer_pool_size, disk_manager); 96 | 97 | page_id_t page_id_temp; 98 | auto* page0 = bpm->NewPage(&page_id_temp); 99 | 100 | // Scenario: The buffer pool is empty. We should be able to create a new page. 101 | ASSERT_NE(nullptr, page0); 102 | EXPECT_EQ(0, page_id_temp); 103 | 104 | // Scenario: Once we have a page, we should be able to read and write content. 105 | snprintf(page0->GetData(), PAGE_SIZE, "Hello"); 106 | EXPECT_EQ(0, strcmp(page0->GetData(), "Hello")); 107 | 108 | // Scenario: We should be able to create new pages until we fill up the buffer pool. 109 | for (size_t i = 1; i < buffer_pool_size; ++i) { 110 | EXPECT_NE(nullptr, bpm->NewPage(&page_id_temp)); 111 | } 112 | 113 | // Scenario: Once the buffer pool is full, we should not be able to create any new pages. 114 | for (size_t i = buffer_pool_size; i < buffer_pool_size * 2; ++i) { 115 | EXPECT_EQ(nullptr, bpm->NewPage(&page_id_temp)); 116 | } 117 | 118 | // Scenario: After unpinning pages {0, 1, 2, 3, 4} and pinning another 4 new pages, 119 | // there would still be one buffer page left for reading page 0. 120 | for (int i = 0; i < 5; ++i) { 121 | EXPECT_EQ(true, bpm->UnpinPage(i, true)); 122 | } 123 | for (int i = 0; i < 4; ++i) { 124 | EXPECT_NE(nullptr, bpm->NewPage(&page_id_temp)); 125 | } 126 | 127 | // Scenario: We should be able to fetch the data we wrote a while ago. 128 | page0 = bpm->FetchPage(0); 129 | EXPECT_EQ(0, strcmp(page0->GetData(), "Hello")); 130 | 131 | // Scenario: If we unpin page 0 and then make a new page, all the buffer pages should 132 | // now be pinned. Fetching page 0 should fail. 133 | EXPECT_EQ(true, bpm->UnpinPage(0, true)); 134 | EXPECT_NE(nullptr, bpm->NewPage(&page_id_temp)); 135 | EXPECT_EQ(nullptr, bpm->FetchPage(0)); 136 | 137 | // Shutdown the disk manager and remove the temporary file we created. 138 | disk_manager->ShutDown(); 139 | remove("test.db"); 140 | remove("test.log"); 141 | 142 | delete bpm; 143 | delete disk_manager; 144 | } 145 | 146 | } // namespace bustub 147 | -------------------------------------------------------------------------------- /Project#1-BufferPoolManager/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 | TEST(ClockReplacerTest, CornerCaseTest) { 63 | ClockReplacer clock_replacer(4); 64 | int value; 65 | bool result = clock_replacer.Victim(&value); 66 | EXPECT_FALSE(result); 67 | 68 | clock_replacer.Unpin(3); 69 | clock_replacer.Unpin(2); 70 | EXPECT_EQ(2, clock_replacer.Size()); 71 | clock_replacer.Victim(&value); 72 | EXPECT_EQ(2, value); 73 | clock_replacer.Unpin(1); 74 | EXPECT_EQ(2, clock_replacer.Size()); 75 | clock_replacer.Victim(&value); 76 | EXPECT_EQ(3, value); 77 | clock_replacer.Victim(&value); 78 | EXPECT_EQ(1, value); 79 | EXPECT_FALSE(clock_replacer.Victim(&value)); 80 | EXPECT_EQ(0, clock_replacer.Size()); 81 | } 82 | 83 | } // namespace bustub 84 | -------------------------------------------------------------------------------- /Project#1-BufferPoolManager/test/buffer/counter.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // counter.h 6 | // 7 | // Identification: test/buffer/counter.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include "gtest/gtest.h" 17 | 18 | namespace bustub { 19 | 20 | enum FuncType { FetchPage, UnpinPage, FlushPage, NewPage, DeletePage, FlushAllPages }; 21 | 22 | struct Counter { 23 | // 0-FetchPage 1-UnpinPage 2-FlushPage 3-NewPage 4-DeletePage 24 | // 5-FlushAllPages 25 | static const int num_types = 6; 26 | std::atomic_int counts[num_types]; 27 | 28 | void Reset() { 29 | for (auto& count : counts) { 30 | count = 0; 31 | } 32 | } 33 | 34 | void AddCount(FuncType func_type) { ++counts[func_type]; } 35 | 36 | // Make sure fetch page function only calls fetch page once and 37 | // does not call other functions 38 | void CheckFetchPage() { 39 | EXPECT_EQ(counts[0], 1) << "has to call FetchPage once"; 40 | for (int i = 1; i < num_types; ++i) { 41 | EXPECT_EQ(counts[i], 0) << "FetchPage Should not call other functions"; 42 | } 43 | } 44 | 45 | void CheckUnpinPage() { 46 | EXPECT_EQ(counts[1], 1) << "has to call UnpinPage once"; 47 | for (int i = 0; i < num_types; ++i) { 48 | if (i != 1) { 49 | EXPECT_EQ(counts[i], 0) << "UnPinPage Should not call other functions"; 50 | } 51 | } 52 | } 53 | 54 | void CheckFlushPage() { 55 | EXPECT_EQ(counts[2], 1) << "has to call FlushPage once"; 56 | for (int i = 0; i < num_types; ++i) { 57 | if (i != 2) { 58 | EXPECT_EQ(counts[i], 0) << "FlushPage Should not call other functions"; 59 | } 60 | } 61 | } 62 | 63 | void CheckNewPage() { 64 | EXPECT_EQ(counts[3], 1) << "has to call NewPage once"; 65 | for (int i = 0; i < num_types; ++i) { 66 | if (i != 3) { 67 | EXPECT_EQ(counts[i], 0) << "NewPage Should not call other functions"; 68 | } 69 | } 70 | } 71 | 72 | void CheckDeletePage() { 73 | EXPECT_EQ(counts[4], 1) << "has to call DeletePage once"; 74 | for (int i = 0; i < num_types; ++i) { 75 | if (i != 4) { 76 | EXPECT_EQ(counts[i], 0) << "DeletePage Should not call other functions"; 77 | } 78 | } 79 | } 80 | 81 | void CheckFlushAllPages() { 82 | for (int i = 1; i < 5; ++i) { 83 | EXPECT_EQ(counts[i], 0) << "FlushAllPage Should not call other functions"; 84 | } 85 | EXPECT_EQ(counts[5], 1) << "has to call FlushAllPage once"; 86 | } 87 | }; 88 | 89 | } // namespace bustub 90 | -------------------------------------------------------------------------------- /Project#1-BufferPoolManager/test/buffer/lru_replacer_test.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // lru_replacer_test.cpp 6 | // 7 | // Identification: test/buffer/lru_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/lru_replacer.h" 18 | #include "gtest/gtest.h" 19 | 20 | namespace bustub { 21 | 22 | TEST(LRUReplacerTest, SampleTest) { 23 | LRUReplacer lru_replacer(7); 24 | 25 | // Scenario: unpin six elements, i.e. add them to the replacer. 26 | lru_replacer.Unpin(1); 27 | lru_replacer.Unpin(2); 28 | lru_replacer.Unpin(3); 29 | lru_replacer.Unpin(4); 30 | lru_replacer.Unpin(5); 31 | lru_replacer.Unpin(6); 32 | lru_replacer.Unpin(1); 33 | EXPECT_EQ(6, lru_replacer.Size()); 34 | 35 | // Scenario: get three victims from the lru. 36 | int value; 37 | lru_replacer.Victim(&value); 38 | EXPECT_EQ(1, value); 39 | lru_replacer.Victim(&value); 40 | EXPECT_EQ(2, value); 41 | lru_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 | lru_replacer.Pin(3); 47 | lru_replacer.Pin(4); 48 | EXPECT_EQ(2, lru_replacer.Size()); 49 | 50 | // Scenario: unpin 4. We expect that the reference bit of 4 will be set to 1. 51 | lru_replacer.Unpin(4); 52 | 53 | // Scenario: continue looking for victims. We expect these victims. 54 | lru_replacer.Victim(&value); 55 | EXPECT_EQ(5, value); 56 | lru_replacer.Victim(&value); 57 | EXPECT_EQ(6, value); 58 | lru_replacer.Victim(&value); 59 | EXPECT_EQ(4, value); 60 | } 61 | 62 | } // namespace bustub 63 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/README.md: -------------------------------------------------------------------------------- 1 | ### CHECKPOINT #1 2 | 3 | - [x] TASK #1 - B+TREE PAGES 4 | - [x] TASK #2.A - B+TREE DATA STRUCTURE (INSERTION & POINT SEARCH) 5 | 6 | ### CHECKPOINT #2 7 | 8 | - [x] TASK #2.B - B+TREE DATA STRUCTURE (DELETION) 9 | - [x] TASK #3 - INDEX ITERATOR 10 | - [x] TASK #4 - CONCURRENT INDEX 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/src/buffer/lru_replacer.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // lru_replacer.cpp 6 | // 7 | // Identification: src/buffer/lru_replacer.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "buffer/lru_replacer.h" 14 | 15 | namespace bustub { 16 | 17 | LRUReplacer::LRUReplacer(size_t num_pages) : capacity{num_pages} {} 18 | 19 | LRUReplacer::~LRUReplacer() = default; 20 | 21 | /** 22 | * 根据LRU策略从LRU lst中找到牺牲页,(lst 最前面的元素是最早加进来的) 23 | * 1.如果没有可以牺牲的page直接返回false 24 | * 2.如果有的话选择在链表尾部的page, remove它即可. 这里的删除涉及链表和hash表两个数据结构的删除 25 | * 3.为了防止并发错误,以下操作均需要加锁 26 | */ 27 | bool LRUReplacer::Victim(frame_id_t *frame_id) { 28 | // 在lock_guard对象构造时,传入的mutex对象会被当前线程锁住 29 | const std::lock_guard guard(mutex); 30 | 31 | if (lst.empty()) { 32 | return false; 33 | } 34 | 35 | auto f = lst.front(); 36 | lst.pop_front(); 37 | 38 | // map.find()如果未找到则返回引用map.end()的迭代器 39 | auto hash_it = hash.find(f); 40 | 41 | if (hash_it != hash.end()) { // 如果不是没有找到元素 42 | hash.erase(hash_it); 43 | *frame_id = f; 44 | return true; 45 | } 46 | 47 | return false; 48 | } 49 | 50 | /** 51 | * 在将某page固定到BufferPoolManager中的某一frame之后,应调用此方法Pin() 52 | * 此方法应该从LRUReplacer中删除包含这个已经固定的page的某一frame,表示该frame不能成为LRU牺牲的对象 53 | * 54 | * 1.pin函数表示这个frame被某个进程引用了 55 | * 2.被引用的frame不能成为LRU算法的牺牲目标.所以这里把它从我们的数据结构中删除 56 | * 57 | */ 58 | void LRUReplacer::Pin(frame_id_t frame_id) { 59 | const std::lock_guard guard(mutex); 60 | 61 | // hash是一个unordered_map; key=frame_id_t , value=list lst的迭代器 62 | // hash_it尝试找到hash中Key=frame_id的键值对,返回指向该KV的迭代器 63 | auto hash_it = hash.find(frame_id); 64 | if (hash_it != hash.end()) { 65 | // erase()方法是删除iterator指定的节点 66 | lst.erase(hash_it->second); // 从lst中删除该页 (hash_it->second是指向该页的迭代器) 67 | hash.erase(hash_it); 68 | } 69 | } 70 | 71 | void LRUReplacer::Unpin(frame_id_t frame_id) { 72 | const std::lock_guard guard(mutex); 73 | 74 | if (hash.size() >= capacity) { 75 | return; 76 | } 77 | 78 | // This step of logical processing is very IMPORTANT 79 | // BUT I DO NOT KNOW THE REASON 80 | auto hash_it = hash.find(frame_id); 81 | 82 | if (hash_it != hash.end()) { 83 | return; 84 | } 85 | 86 | /* 87 | if (hash_it == hash.end()) { 88 | while (hash.size() >= capacity) { 89 | frame_id_t need_del = lst.back(); 90 | lst.pop_back(); 91 | if (hash.find(need_del) != hash.end()) { 92 | hash.erase(need_del); 93 | } 94 | } 95 | } 96 | */ 97 | 98 | lst.push_back(frame_id); 99 | // std::prev(lst.end(),1) 返回lst.end()的前面的距离它为1的元素的迭代器 100 | // 即指向lst的最后一个实际元素的迭代器,也就是lst中指向末尾这个新插入的帧id的迭代器 101 | hash.emplace(frame_id, std::prev(lst.end(), 1)); 102 | } 103 | 104 | size_t LRUReplacer::Size() { 105 | const std::lock_guard guard(mutex); 106 | 107 | return hash.size(); 108 | } 109 | 110 | } // namespace bustub 111 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/src/include/buffer/buffer_pool_manager.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // buffer_pool_manager.h 6 | // 7 | // Identification: src/include/buffer/buffer_pool_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 18 | 19 | #include "buffer/lru_replacer.h" 20 | #include "recovery/log_manager.h" 21 | #include "storage/disk/disk_manager.h" 22 | #include "storage/page/page.h" 23 | 24 | namespace bustub { 25 | 26 | /** 27 | * BufferPoolManager reads disk pages to and from its internal buffer pool. 28 | */ 29 | class BufferPoolManager { 30 | public: 31 | enum class CallbackType { BEFORE, AFTER }; 32 | using bufferpool_callback_fn = void (*)(enum CallbackType, const page_id_t page_id); 33 | 34 | /** 35 | * Creates a new BufferPoolManager. 36 | * @param pool_size the size of the buffer pool 37 | * @param disk_manager the disk manager 38 | * @param log_manager the log manager (for testing only: nullptr = disable logging) 39 | */ 40 | BufferPoolManager(size_t pool_size, DiskManager *disk_manager, LogManager *log_manager = nullptr); 41 | 42 | /** 43 | * Destroys an existing BufferPoolManager. 44 | */ 45 | ~BufferPoolManager(); 46 | 47 | /** Grading function. Do not modify! */ 48 | Page *FetchPage(page_id_t page_id, bufferpool_callback_fn callback = nullptr) { 49 | GradingCallback(callback, CallbackType::BEFORE, page_id); 50 | auto *result = FetchPageImpl(page_id); 51 | GradingCallback(callback, CallbackType::AFTER, page_id); 52 | return result; 53 | } 54 | 55 | /** Grading function. Do not modify! */ 56 | bool UnpinPage(page_id_t page_id, bool is_dirty, bufferpool_callback_fn callback = nullptr) { 57 | GradingCallback(callback, CallbackType::BEFORE, page_id); 58 | auto result = UnpinPageImpl(page_id, is_dirty); 59 | GradingCallback(callback, CallbackType::AFTER, page_id); 60 | return result; 61 | } 62 | 63 | /** Grading function. Do not modify! */ 64 | bool FlushPage(page_id_t page_id, bufferpool_callback_fn callback = nullptr) { 65 | GradingCallback(callback, CallbackType::BEFORE, page_id); 66 | auto result = FlushPageImpl(page_id); 67 | GradingCallback(callback, CallbackType::AFTER, page_id); 68 | return result; 69 | } 70 | 71 | /** Grading function. Do not modify! */ 72 | Page *NewPage(page_id_t *page_id, bufferpool_callback_fn callback = nullptr) { 73 | GradingCallback(callback, CallbackType::BEFORE, INVALID_PAGE_ID); 74 | auto *result = NewPageImpl(page_id); 75 | GradingCallback(callback, CallbackType::AFTER, *page_id); 76 | return result; 77 | } 78 | 79 | /** Grading function. Do not modify! */ 80 | bool DeletePage(page_id_t page_id, bufferpool_callback_fn callback = nullptr) { 81 | GradingCallback(callback, CallbackType::BEFORE, page_id); 82 | auto result = DeletePageImpl(page_id); 83 | GradingCallback(callback, CallbackType::AFTER, page_id); 84 | return result; 85 | } 86 | 87 | /** Grading function. Do not modify! */ 88 | void FlushAllPages(bufferpool_callback_fn callback = nullptr) { 89 | GradingCallback(callback, CallbackType::BEFORE, INVALID_PAGE_ID); 90 | FlushAllPagesImpl(); 91 | GradingCallback(callback, CallbackType::AFTER, INVALID_PAGE_ID); 92 | } 93 | 94 | /** @return pointer to all the pages in the buffer pool */ 95 | Page *GetPages() { return pages_; } 96 | 97 | /** @return size of the buffer pool */ 98 | size_t GetPoolSize() { return pool_size_; } 99 | 100 | protected: 101 | /** 102 | * Grading function. Do not modify! 103 | * Invokes the callback function if it is not null. 104 | * @param callback callback function to be invoked 105 | * @param callback_type BEFORE or AFTER 106 | * @param page_id the page id to invoke the callback with 107 | */ 108 | void GradingCallback(bufferpool_callback_fn callback, CallbackType callback_type, page_id_t page_id) { 109 | if (callback != nullptr) { 110 | callback(callback_type, page_id); 111 | } 112 | } 113 | 114 | /** 115 | * Fetch the requested page from the buffer pool. 116 | * @param page_id id of page to be fetched 117 | * @return the requested page 118 | */ 119 | Page *FetchPageImpl(page_id_t page_id); 120 | 121 | /** 122 | * Unpin the target page from the buffer pool. 123 | * @param page_id id of page to be unpinned 124 | * @param is_dirty true if the page should be marked as dirty, false otherwise 125 | * @return false if the page pin count is <= 0 before this call, true otherwise 126 | */ 127 | bool UnpinPageImpl(page_id_t page_id, bool is_dirty); 128 | 129 | /** 130 | * Flushes the target page to disk. 131 | * @param page_id id of page to be flushed, cannot be INVALID_PAGE_ID 132 | * @return false if the page could not be found in the page table, true otherwise 133 | */ 134 | bool FlushPageImpl(page_id_t page_id); 135 | 136 | /** 137 | * Creates a new page in the buffer pool. 138 | * @param[out] page_id id of created page 139 | * @return nullptr if no new pages could be created, otherwise pointer to new page 140 | */ 141 | Page *NewPageImpl(page_id_t *page_id); 142 | 143 | /** 144 | * Deletes a page from the buffer pool. 145 | * @param page_id id of page to be deleted 146 | * @return false if the page exists but could not be deleted, true if the page didn't exist or 147 | * deletion succeeded 148 | */ 149 | bool DeletePageImpl(page_id_t page_id); 150 | 151 | /** 152 | * Flushes all the pages in the buffer pool to disk. 153 | */ 154 | void FlushAllPagesImpl(); 155 | 156 | /** Number of pages in the buffer pool. */ 157 | size_t pool_size_; 158 | /** Array of buffer pool pages. */ 159 | Page *pages_; 160 | /** Pointer to the disk manager. */ 161 | DiskManager *disk_manager_ __attribute__((__unused__)); 162 | /** Pointer to the log manager. */ 163 | LogManager *log_manager_ __attribute__((__unused__)); 164 | /** Page table for keeping track of buffer pool pages. */ 165 | std::unordered_map page_table_; 166 | /** Replacer to find unpinned pages for replacement. */ 167 | Replacer *replacer_; 168 | /** List of free pages. */ 169 | std::list free_list_; 170 | /** 171 | * This latch protects shared data structures. 172 | * We recommend updating this comment to describe what it protects. 173 | * 174 | * latch protects: 175 | * - page_table_ 176 | * - free_list_ 177 | */ 178 | std::mutex latch_; 179 | }; 180 | } // namespace bustub 181 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/src/include/buffer/lru_replacer.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // lru_replacer.h 6 | // 7 | // Identification: src/include/buffer/lru_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 | * LRUReplacer implements the lru replacement policy, which approximates the Least Recently Used 26 | * policy. 27 | */ 28 | class LRUReplacer : public Replacer { 29 | using mutex_t = std::mutex; 30 | 31 | public: 32 | /** 33 | * Create a new LRUReplacer. 34 | * @param num_pages the maximum number of pages the LRUReplacer will be required to store 35 | */ 36 | explicit LRUReplacer(size_t num_pages); 37 | 38 | /** 39 | * Destroys the LRUReplacer. 40 | */ 41 | ~LRUReplacer() override; 42 | 43 | bool Victim(frame_id_t *frame_id) override; 44 | 45 | void Pin(frame_id_t frame_id) override; 46 | 47 | void Unpin(frame_id_t frame_id) override; 48 | 49 | size_t Size() override; 50 | 51 | private: 52 | // TODO(student): implement me! 53 | mutex_t mutex; 54 | size_t capacity; 55 | std::list lst; 56 | std::unordered_map::iterator> hash; 57 | }; 58 | 59 | } // namespace bustub 60 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/src/include/storage/index/b_plus_tree.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/include/index/b_plus_tree.h 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | #pragma once 12 | 13 | #include // NOLINT 14 | #include 15 | #include 16 | #include 17 | 18 | #include "concurrency/transaction.h" 19 | #include "storage/index/index_iterator.h" 20 | #include "storage/page/b_plus_tree_internal_page.h" 21 | #include "storage/page/b_plus_tree_leaf_page.h" 22 | 23 | namespace bustub { 24 | 25 | #define BPLUSTREE_TYPE BPlusTree 26 | 27 | enum class Operation { SEARCH, INSERT, DELETE }; 28 | 29 | /** 30 | * Main class providing the API for the Interactive B+ Tree. 31 | * 32 | * Implementation of simple b+ tree data structure where internal pages direct 33 | * the search and leaf pages contain actual data. 34 | * (1) We only support unique key 35 | * (2) support insert & remove 36 | * (3) The structure should shrink and grow dynamically 37 | * (4) Implement index iterator for range scan 38 | */ 39 | INDEX_TEMPLATE_ARGUMENTS 40 | class BPlusTree { 41 | using InternalPage = BPlusTreeInternalPage; 42 | using LeafPage = BPlusTreeLeafPage; 43 | 44 | public: 45 | explicit BPlusTree(std::string name, BufferPoolManager *buffer_pool_manager, const KeyComparator &comparator, 46 | int leaf_max_size = LEAF_PAGE_SIZE, int internal_max_size = INTERNAL_PAGE_SIZE); 47 | 48 | // Returns true if this B+ tree has no keys and values. 49 | bool IsEmpty() const; 50 | 51 | // Insert a key-value pair into this B+ tree. 52 | bool Insert(const KeyType &key, const ValueType &value, Transaction *transaction = nullptr); 53 | 54 | // Remove a key and its value from this B+ tree. 55 | void Remove(const KeyType &key, Transaction *transaction = nullptr); 56 | 57 | // return the value associated with a given key 58 | bool GetValue(const KeyType &key, std::vector *result, Transaction *transaction = nullptr); 59 | 60 | // index iterator 61 | INDEXITERATOR_TYPE begin(); 62 | INDEXITERATOR_TYPE Begin(const KeyType &key); 63 | INDEXITERATOR_TYPE end(); 64 | 65 | void Print(BufferPoolManager *bpm) { 66 | ToString(reinterpret_cast(bpm->FetchPage(root_page_id_)->GetData()), bpm); 67 | } 68 | 69 | void Draw(BufferPoolManager *bpm, const std::string &outf) { 70 | std::ofstream out(outf); 71 | out << "digraph G {" << std::endl; 72 | ToGraph(reinterpret_cast(bpm->FetchPage(root_page_id_)->GetData()), bpm, out); 73 | out << "}" << std::endl; 74 | out.close(); 75 | } 76 | 77 | // read data from file and insert one by one 78 | void InsertFromFile(const std::string &file_name, Transaction *transaction = nullptr); 79 | 80 | // read data from file and remove one by one 81 | void RemoveFromFile(const std::string &file_name, Transaction *transaction = nullptr); 82 | // expose for test purpose 83 | Page *FindLeafPage(const KeyType &key, bool leftMost = false); 84 | 85 | private: 86 | void StartNewTree(const KeyType &key, const ValueType &value); 87 | 88 | bool InsertIntoLeaf(const KeyType &key, const ValueType &value, Transaction *transaction = nullptr); 89 | 90 | void InsertIntoParent(BPlusTreePage *old_node, const KeyType &key, BPlusTreePage *new_node, 91 | Transaction *transaction = nullptr); 92 | 93 | template 94 | N *Split(N *node); 95 | 96 | template 97 | bool CoalesceOrRedistribute(N *node, Transaction *transaction = nullptr, bool is_root_page_id_latched = false); 98 | 99 | template 100 | bool Coalesce(N **neighbor_node, N **node, BPlusTreeInternalPage **parent, 101 | int index, Transaction *transaction = nullptr, bool is_root_page_id_latched = false); 102 | 103 | template 104 | void Redistribute(N *neighbor_node, N *node, BPlusTreeInternalPage *parent, 105 | int index, bool is_root_page_id_latched = false); 106 | 107 | bool AdjustRoot(BPlusTreePage *node, bool is_root_page_id_latched = false); 108 | 109 | void UpdateRootPageId(int insert_record = 0); 110 | 111 | /* Debug Routines for FREE!! */ 112 | void ToGraph(BPlusTreePage *page, BufferPoolManager *bpm, std::ofstream &out) const; 113 | 114 | void ToString(BPlusTreePage *page, BufferPoolManager *bpm) const; 115 | 116 | void ClearTransactionPageSetAndUnpinEach(Transaction *transaction) const; 117 | 118 | void ClearTransactionPageSet(Transaction *transaction) const; 119 | 120 | std::pair FindLeafPageByOperation(const KeyType &key, Operation operation = Operation::SEARCH, 121 | Transaction *transaction = nullptr, bool leftMost = false, 122 | bool rightMost = false); 123 | 124 | // member variable 125 | std::string index_name_; 126 | std::mutex root_page_id_latch; 127 | page_id_t root_page_id_; 128 | BufferPoolManager *buffer_pool_manager_; 129 | KeyComparator comparator_; 130 | int leaf_max_size_; 131 | int internal_max_size_; 132 | }; 133 | 134 | } // namespace bustub 135 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/src/include/storage/index/index_iterator.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/include/index/index_iterator.h 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | /** 12 | * index_iterator.h 13 | * For range scan of b+ tree 14 | */ 15 | #pragma once 16 | #include "buffer/buffer_pool_manager.h" 17 | #include "storage/page/b_plus_tree_leaf_page.h" 18 | #include "storage/page/page.h" 19 | 20 | namespace bustub { 21 | 22 | #define INDEXITERATOR_TYPE IndexIterator 23 | 24 | INDEX_TEMPLATE_ARGUMENTS 25 | class IndexIterator { 26 | using LeafPage = BPlusTreeLeafPage; 27 | 28 | public: 29 | // you may define your own constructor based on your member variables 30 | IndexIterator(BufferPoolManager *bpm, Page *page, int idx = 0); 31 | ~IndexIterator(); 32 | 33 | bool isEnd(); 34 | 35 | const MappingType &operator*(); 36 | 37 | IndexIterator &operator++(); 38 | 39 | bool operator==(const IndexIterator &itr) const; 40 | 41 | bool operator!=(const IndexIterator &itr) const; 42 | 43 | private: 44 | // add your own private member variables here 45 | BufferPoolManager *buffer_pool_manager_; 46 | Page *page; 47 | LeafPage *leaf = nullptr; 48 | int idx = 0; 49 | }; 50 | 51 | } // namespace bustub 52 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/src/include/storage/page/b_plus_tree_internal_page.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/include/page/b_plus_tree_internal_page.h 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | #pragma once 12 | 13 | #include 14 | 15 | #include "storage/page/b_plus_tree_page.h" 16 | 17 | namespace bustub { 18 | 19 | #define B_PLUS_TREE_INTERNAL_PAGE_TYPE BPlusTreeInternalPage 20 | #define INTERNAL_PAGE_HEADER_SIZE 24 21 | #define INTERNAL_PAGE_SIZE ((PAGE_SIZE - INTERNAL_PAGE_HEADER_SIZE) / (sizeof(MappingType))) 22 | /** 23 | * Store n indexed keys and n+1 child pointers (page_id) within internal page. 24 | * Pointer PAGE_ID(i) points to a subtree in which all keys K satisfy: 25 | * K(i) <= K < K(i+1). 26 | * NOTE: since the number of keys does not equal to number of child pointers, 27 | * the first key always remains invalid. That is to say, any search/lookup 28 | * should ignore the first key. 29 | * 30 | * Internal page format (keys are stored in increasing order): 31 | * -------------------------------------------------------------------------- 32 | * | HEADER | KEY(1)+PAGE_ID(1) | KEY(2)+PAGE_ID(2) | ... | KEY(n)+PAGE_ID(n) | 33 | * -------------------------------------------------------------------------- 34 | */ 35 | INDEX_TEMPLATE_ARGUMENTS 36 | class BPlusTreeInternalPage : public BPlusTreePage { 37 | public: 38 | // must call initialize method after "create" a new node 39 | void Init(page_id_t page_id, page_id_t parent_id = INVALID_PAGE_ID, int max_size = INTERNAL_PAGE_SIZE); 40 | 41 | KeyType KeyAt(int index) const; 42 | void SetKeyAt(int index, const KeyType &key); 43 | int ValueIndex(const ValueType &value) const; 44 | ValueType ValueAt(int index) const; 45 | 46 | ValueType Lookup(const KeyType &key, const KeyComparator &comparator) const; 47 | void PopulateNewRoot(const ValueType &old_value, const KeyType &new_key, const ValueType &new_value); 48 | int InsertNodeAfter(const ValueType &old_value, const KeyType &new_key, const ValueType &new_value); 49 | void Remove(int index); 50 | ValueType RemoveAndReturnOnlyChild(); 51 | 52 | // Split and Merge utility methods 53 | void MoveAllTo(BPlusTreeInternalPage *recipient, const KeyType &middle_key, BufferPoolManager *buffer_pool_manager); 54 | void MoveHalfTo(BPlusTreeInternalPage *recipient, BufferPoolManager *buffer_pool_manager); 55 | void MoveFirstToEndOf(BPlusTreeInternalPage *recipient, const KeyType &middle_key, 56 | BufferPoolManager *buffer_pool_manager); 57 | void MoveLastToFrontOf(BPlusTreeInternalPage *recipient, const KeyType &middle_key, 58 | BufferPoolManager *buffer_pool_manager); 59 | 60 | private: 61 | void CopyNFrom(MappingType *items, int size, BufferPoolManager *buffer_pool_manager); 62 | void CopyLastFrom(const MappingType &pair, BufferPoolManager *buffer_pool_manager); 63 | void CopyFirstFrom(const MappingType &pair, BufferPoolManager *buffer_pool_manager); 64 | MappingType array[0]; 65 | }; 66 | } // namespace bustub 67 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/src/include/storage/page/b_plus_tree_leaf_page.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/include/page/b_plus_tree_leaf_page.h 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | #pragma once 12 | 13 | #include 14 | #include 15 | 16 | #include "storage/page/b_plus_tree_page.h" 17 | 18 | namespace bustub { 19 | 20 | #define B_PLUS_TREE_LEAF_PAGE_TYPE BPlusTreeLeafPage 21 | #define LEAF_PAGE_HEADER_SIZE 28 22 | #define LEAF_PAGE_SIZE ((PAGE_SIZE - LEAF_PAGE_HEADER_SIZE) / sizeof(MappingType)) 23 | 24 | /** 25 | * Store indexed key and record id(record id = page id combined with slot id, 26 | * see include/common/rid.h for detailed implementation) together within leaf 27 | * page. Only support unique key. 28 | * 29 | * Leaf page format (keys are stored in order): 30 | * ---------------------------------------------------------------------- 31 | * | HEADER | KEY(1) + RID(1) | KEY(2) + RID(2) | ... | KEY(n) + RID(n) 32 | * ---------------------------------------------------------------------- 33 | * 34 | * Header format (size in byte, 28 bytes in total): 35 | * --------------------------------------------------------------------- 36 | * | PageType (4) | LSN (4) | CurrentSize (4) | MaxSize (4) | 37 | * --------------------------------------------------------------------- 38 | * ----------------------------------------------- 39 | * | ParentPageId (4) | PageId (4) | NextPageId (4) 40 | * ----------------------------------------------- 41 | */ 42 | INDEX_TEMPLATE_ARGUMENTS 43 | class BPlusTreeLeafPage : public BPlusTreePage { 44 | public: 45 | // After creating a new leaf page from buffer pool, must call initialize 46 | // method to set default values 47 | void Init(page_id_t page_id, page_id_t parent_id = INVALID_PAGE_ID, int max_size = LEAF_PAGE_SIZE); 48 | // helper methods 49 | page_id_t GetNextPageId() const; 50 | void SetNextPageId(page_id_t next_page_id); 51 | KeyType KeyAt(int index) const; 52 | int KeyIndex(const KeyType &key, const KeyComparator &comparator) const; 53 | const MappingType &GetItem(int index); 54 | 55 | // insert and delete methods 56 | int Insert(const KeyType &key, const ValueType &value, const KeyComparator &comparator); 57 | bool Lookup(const KeyType &key, ValueType *value, const KeyComparator &comparator) const; 58 | int RemoveAndDeleteRecord(const KeyType &key, const KeyComparator &comparator); 59 | 60 | // Split and Merge utility methods 61 | void MoveHalfTo(BPlusTreeLeafPage *recipient); 62 | void MoveAllTo(BPlusTreeLeafPage *recipient); 63 | void MoveFirstToEndOf(BPlusTreeLeafPage *recipient); 64 | void MoveLastToFrontOf(BPlusTreeLeafPage *recipient); 65 | 66 | private: 67 | void CopyNFrom(MappingType *items, int size); 68 | void CopyLastFrom(const MappingType &item); 69 | void CopyFirstFrom(const MappingType &item); 70 | page_id_t next_page_id_; 71 | MappingType array[0]; 72 | }; 73 | } // namespace bustub 74 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/src/include/storage/page/b_plus_tree_page.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/include/page/b_plus_tree_page.h 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | #pragma once 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "buffer/buffer_pool_manager.h" 19 | #include "storage/index/generic_key.h" 20 | 21 | namespace bustub { 22 | 23 | #define MappingType std::pair 24 | 25 | #define INDEX_TEMPLATE_ARGUMENTS template 26 | 27 | // define page type enum 28 | enum class IndexPageType { INVALID_INDEX_PAGE = 0, LEAF_PAGE, INTERNAL_PAGE }; 29 | 30 | /** 31 | * Both internal and leaf page are inherited from this page. 32 | * 33 | * It actually serves as a header part for each B+ tree page and 34 | * contains information shared by both leaf page and internal page. 35 | * 36 | * Header format (size in byte, 24 bytes in total): 37 | * ---------------------------------------------------------------------------- 38 | * | PageType (4) | LSN (4) | CurrentSize (4) | MaxSize (4) | 39 | * ---------------------------------------------------------------------------- 40 | * | ParentPageId (4) | PageId(4) | 41 | * ---------------------------------------------------------------------------- 42 | */ 43 | class BPlusTreePage { 44 | public: 45 | bool IsLeafPage() const; 46 | bool IsRootPage() const; 47 | void SetPageType(IndexPageType page_type); 48 | IndexPageType GetPageType() const; 49 | 50 | int GetSize() const; 51 | void SetSize(int size); 52 | void IncreaseSize(int amount); 53 | 54 | int GetMaxSize() const; 55 | void SetMaxSize(int max_size); 56 | int GetMinSize() const; 57 | 58 | page_id_t GetParentPageId() const; 59 | void SetParentPageId(page_id_t parent_page_id); 60 | 61 | page_id_t GetPageId() const; 62 | void SetPageId(page_id_t page_id); 63 | 64 | void SetLSN(lsn_t lsn = INVALID_LSN); 65 | 66 | private: 67 | // member variable, attributes that both internal and leaf page share 68 | IndexPageType page_type_ __attribute__((__unused__)); 69 | lsn_t lsn_ __attribute__((__unused__)); 70 | int size_ __attribute__((__unused__)); 71 | int max_size_ __attribute__((__unused__)); 72 | page_id_t parent_page_id_ __attribute__((__unused__)); 73 | page_id_t page_id_ __attribute__((__unused__)); 74 | }; 75 | 76 | } // namespace bustub 77 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/src/storage/index/index_iterator.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * index_iterator.cpp 3 | */ 4 | #include 5 | 6 | #include "storage/index/index_iterator.h" 7 | 8 | namespace bustub { 9 | 10 | /* 11 | * NOTE: you can change the destructor/constructor method here 12 | * set your own input parameters 13 | */ 14 | INDEX_TEMPLATE_ARGUMENTS 15 | INDEXITERATOR_TYPE::IndexIterator(BufferPoolManager *bpm, Page *page, int idx) 16 | : buffer_pool_manager_(bpm), page(page), idx(idx) { 17 | leaf = reinterpret_cast(page->GetData()); 18 | } 19 | 20 | INDEX_TEMPLATE_ARGUMENTS 21 | INDEXITERATOR_TYPE::~IndexIterator() { 22 | page->RUnlatch(); 23 | buffer_pool_manager_->UnpinPage(page->GetPageId(), false); 24 | } 25 | 26 | INDEX_TEMPLATE_ARGUMENTS 27 | bool INDEXITERATOR_TYPE::isEnd() { return leaf->GetNextPageId() == INVALID_PAGE_ID && idx == leaf->GetSize(); } 28 | 29 | INDEX_TEMPLATE_ARGUMENTS 30 | const MappingType &INDEXITERATOR_TYPE::operator*() { return leaf->GetItem(idx); } 31 | 32 | INDEX_TEMPLATE_ARGUMENTS 33 | INDEXITERATOR_TYPE &INDEXITERATOR_TYPE::operator++() { 34 | if (idx == leaf->GetSize() - 1 && leaf->GetNextPageId() != INVALID_PAGE_ID) { 35 | auto next_page = buffer_pool_manager_->FetchPage(leaf->GetNextPageId()); 36 | 37 | next_page->RLatch(); 38 | page->RUnlatch(); 39 | buffer_pool_manager_->UnpinPage(page->GetPageId(), false); 40 | 41 | page = next_page; 42 | leaf = reinterpret_cast(page->GetData()); 43 | idx = 0; 44 | } else { 45 | idx++; 46 | } 47 | 48 | return *this; 49 | } 50 | 51 | INDEX_TEMPLATE_ARGUMENTS 52 | bool INDEXITERATOR_TYPE::operator==(const IndexIterator &itr) const { 53 | return leaf->GetPageId() == itr.leaf->GetPageId() && idx == itr.idx; 54 | } 55 | 56 | INDEX_TEMPLATE_ARGUMENTS 57 | bool INDEXITERATOR_TYPE::operator!=(const IndexIterator &itr) const { 58 | return !(leaf->GetPageId() == itr.leaf->GetPageId() && idx == itr.idx); 59 | } 60 | 61 | template class IndexIterator, RID, GenericComparator<4>>; 62 | 63 | template class IndexIterator, RID, GenericComparator<8>>; 64 | 65 | template class IndexIterator, RID, GenericComparator<16>>; 66 | 67 | template class IndexIterator, RID, GenericComparator<32>>; 68 | 69 | template class IndexIterator, RID, GenericComparator<64>>; 70 | 71 | } // namespace bustub 72 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/src/storage/page/b_plus_tree_page.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/page/b_plus_tree_page.cpp 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | 12 | #include "storage/page/b_plus_tree_page.h" 13 | 14 | namespace bustub { 15 | 16 | /* 17 | * Helper methods to get/set page type 18 | * Page type enum class is defined in b_plus_tree_page.h 19 | */ 20 | bool BPlusTreePage::IsLeafPage() const { return page_type_ == IndexPageType::LEAF_PAGE; } 21 | bool BPlusTreePage::IsRootPage() const { return parent_page_id_ == INVALID_PAGE_ID; } 22 | void BPlusTreePage::SetPageType(IndexPageType page_type) { page_type_ = page_type; } 23 | IndexPageType BPlusTreePage::GetPageType() const { return page_type_; } 24 | 25 | /* 26 | * Helper methods to get/set size (number of key/value pairs stored in that 27 | * page) 28 | */ 29 | int BPlusTreePage::GetSize() const { return size_; } 30 | void BPlusTreePage::SetSize(int size) { size_ = size; } 31 | void BPlusTreePage::IncreaseSize(int amount) { size_ += amount; } 32 | 33 | /* 34 | * Helper methods to get/set max size (capacity) of the page 35 | */ 36 | int BPlusTreePage::GetMaxSize() const { return max_size_; } 37 | void BPlusTreePage::SetMaxSize(int size) { max_size_ = size; } 38 | 39 | /* 40 | * Helper method to get min page size 41 | * Generally, min page size == max page size / 2 42 | */ 43 | int BPlusTreePage::GetMinSize() const { return max_size_ / 2; } 44 | 45 | /* 46 | * Helper methods to get/set parent page id 47 | */ 48 | page_id_t BPlusTreePage::GetParentPageId() const { return parent_page_id_; } 49 | void BPlusTreePage::SetParentPageId(page_id_t parent_page_id) { parent_page_id_ = parent_page_id; } 50 | 51 | /* 52 | * Helper methods to get/set self page id 53 | */ 54 | page_id_t BPlusTreePage::GetPageId() const { return page_id_; } 55 | void BPlusTreePage::SetPageId(page_id_t page_id) { page_id_ = page_id; } 56 | 57 | /* 58 | * Helper methods to set lsn 59 | */ 60 | void BPlusTreePage::SetLSN(lsn_t lsn) { lsn_ = lsn; } 61 | 62 | } // namespace bustub 63 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/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 "buffer/buffer_pool_manager.h" 14 | #include 15 | #include 16 | #include 17 | #include "gtest/gtest.h" 18 | 19 | namespace bustub { 20 | 21 | // NOLINTNEXTLINE 22 | // Check whether pages containing terminal characters can be recovered 23 | TEST(BufferPoolManagerTest, BinaryDataTest) { 24 | const std::string db_name = "test.db"; 25 | const size_t buffer_pool_size = 10; 26 | 27 | std::random_device r; 28 | std::default_random_engine rng(r()); 29 | std::uniform_int_distribution uniform_dist(0); 30 | 31 | auto* disk_manager = new DiskManager(db_name); 32 | auto* bpm = new BufferPoolManager(buffer_pool_size, disk_manager); 33 | 34 | page_id_t page_id_temp; 35 | auto* page0 = bpm->NewPage(&page_id_temp); 36 | 37 | // Scenario: The buffer pool is empty. We should be able to create a new page. 38 | ASSERT_NE(nullptr, page0); 39 | EXPECT_EQ(0, page_id_temp); 40 | 41 | char random_binary_data[PAGE_SIZE]; 42 | // Generate random binary data 43 | for (char& i : random_binary_data) { 44 | i = uniform_dist(rng); 45 | } 46 | 47 | // Insert terminal characters both in the middle and at end 48 | random_binary_data[PAGE_SIZE / 2] = '\0'; 49 | random_binary_data[PAGE_SIZE - 1] = '\0'; 50 | 51 | // Scenario: Once we have a page, we should be able to read and write content. 52 | std::memcpy(page0->GetData(), random_binary_data, PAGE_SIZE); 53 | EXPECT_EQ(0, std::memcmp(page0->GetData(), random_binary_data, PAGE_SIZE)); 54 | 55 | // Scenario: We should be able to create new pages until we fill up the buffer pool. 56 | for (size_t i = 1; i < buffer_pool_size; ++i) { 57 | EXPECT_NE(nullptr, bpm->NewPage(&page_id_temp)); 58 | } 59 | 60 | // Scenario: Once the buffer pool is full, we should not be able to create any new pages. 61 | for (size_t i = buffer_pool_size; i < buffer_pool_size * 2; ++i) { 62 | EXPECT_EQ(nullptr, bpm->NewPage(&page_id_temp)); 63 | } 64 | 65 | // Scenario: After unpinning pages {0, 1, 2, 3, 4} and pinning another 4 new pages, 66 | // there would still be one cache frame left for reading page 0. 67 | for (int i = 0; i < 5; ++i) { 68 | EXPECT_EQ(true, bpm->UnpinPage(i, true)); 69 | bpm->FlushPage(i); 70 | } 71 | for (int i = 0; i < 5; ++i) { 72 | EXPECT_NE(nullptr, bpm->NewPage(&page_id_temp)); 73 | bpm->UnpinPage(page_id_temp, false); 74 | } 75 | // Scenario: We should be able to fetch the data we wrote a while ago. 76 | page0 = bpm->FetchPage(0); 77 | EXPECT_EQ(0, memcmp(page0->GetData(), random_binary_data, PAGE_SIZE)); 78 | EXPECT_EQ(true, bpm->UnpinPage(0, true)); 79 | 80 | // Shutdown the disk manager and remove the temporary file we created. 81 | disk_manager->ShutDown(); 82 | remove("test.db"); 83 | remove("test.log"); 84 | 85 | delete bpm; 86 | delete disk_manager; 87 | } 88 | 89 | // NOLINTNEXTLINE 90 | TEST(BufferPoolManagerTest, SampleTest) { 91 | const std::string db_name = "test.db"; 92 | const size_t buffer_pool_size = 10; 93 | 94 | auto* disk_manager = new DiskManager(db_name); 95 | auto* bpm = new BufferPoolManager(buffer_pool_size, disk_manager); 96 | 97 | page_id_t page_id_temp; 98 | auto* page0 = bpm->NewPage(&page_id_temp); 99 | 100 | // Scenario: The buffer pool is empty. We should be able to create a new page. 101 | ASSERT_NE(nullptr, page0); 102 | EXPECT_EQ(0, page_id_temp); 103 | 104 | // Scenario: Once we have a page, we should be able to read and write content. 105 | snprintf(page0->GetData(), PAGE_SIZE, "Hello"); 106 | EXPECT_EQ(0, strcmp(page0->GetData(), "Hello")); 107 | 108 | // Scenario: We should be able to create new pages until we fill up the buffer pool. 109 | for (size_t i = 1; i < buffer_pool_size; ++i) { 110 | EXPECT_NE(nullptr, bpm->NewPage(&page_id_temp)); 111 | } 112 | 113 | // Scenario: Once the buffer pool is full, we should not be able to create any new pages. 114 | for (size_t i = buffer_pool_size; i < buffer_pool_size * 2; ++i) { 115 | EXPECT_EQ(nullptr, bpm->NewPage(&page_id_temp)); 116 | } 117 | 118 | // Scenario: After unpinning pages {0, 1, 2, 3, 4} and pinning another 4 new pages, 119 | // there would still be one buffer page left for reading page 0. 120 | for (int i = 0; i < 5; ++i) { 121 | EXPECT_EQ(true, bpm->UnpinPage(i, true)); 122 | } 123 | for (int i = 0; i < 4; ++i) { 124 | EXPECT_NE(nullptr, bpm->NewPage(&page_id_temp)); 125 | } 126 | 127 | // Scenario: We should be able to fetch the data we wrote a while ago. 128 | page0 = bpm->FetchPage(0); 129 | EXPECT_EQ(0, strcmp(page0->GetData(), "Hello")); 130 | 131 | // Scenario: If we unpin page 0 and then make a new page, all the buffer pages should 132 | // now be pinned. Fetching page 0 should fail. 133 | EXPECT_EQ(true, bpm->UnpinPage(0, true)); 134 | EXPECT_NE(nullptr, bpm->NewPage(&page_id_temp)); 135 | EXPECT_EQ(nullptr, bpm->FetchPage(0)); 136 | 137 | // Shutdown the disk manager and remove the temporary file we created. 138 | disk_manager->ShutDown(); 139 | remove("test.db"); 140 | remove("test.log"); 141 | 142 | delete bpm; 143 | delete disk_manager; 144 | } 145 | 146 | } // namespace bustub 147 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/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 | TEST(ClockReplacerTest, CornerCaseTest) { 63 | ClockReplacer clock_replacer(4); 64 | int value; 65 | bool result = clock_replacer.Victim(&value); 66 | EXPECT_FALSE(result); 67 | 68 | clock_replacer.Unpin(3); 69 | clock_replacer.Unpin(2); 70 | EXPECT_EQ(2, clock_replacer.Size()); 71 | clock_replacer.Victim(&value); 72 | EXPECT_EQ(2, value); 73 | clock_replacer.Unpin(1); 74 | EXPECT_EQ(2, clock_replacer.Size()); 75 | clock_replacer.Victim(&value); 76 | EXPECT_EQ(3, value); 77 | clock_replacer.Victim(&value); 78 | EXPECT_EQ(1, value); 79 | EXPECT_FALSE(clock_replacer.Victim(&value)); 80 | EXPECT_EQ(0, clock_replacer.Size()); 81 | } 82 | 83 | } // namespace bustub 84 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/test/buffer/counter.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // counter.h 6 | // 7 | // Identification: test/buffer/counter.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include "gtest/gtest.h" 17 | 18 | namespace bustub { 19 | 20 | enum FuncType { FetchPage, UnpinPage, FlushPage, NewPage, DeletePage, FlushAllPages }; 21 | 22 | struct Counter { 23 | // 0-FetchPage 1-UnpinPage 2-FlushPage 3-NewPage 4-DeletePage 24 | // 5-FlushAllPages 25 | static const int num_types = 6; 26 | std::atomic_int counts[num_types]; 27 | 28 | void Reset() { 29 | for (auto& count : counts) { 30 | count = 0; 31 | } 32 | } 33 | 34 | void AddCount(FuncType func_type) { ++counts[func_type]; } 35 | 36 | // Make sure fetch page function only calls fetch page once and 37 | // does not call other functions 38 | void CheckFetchPage() { 39 | EXPECT_EQ(counts[0], 1) << "has to call FetchPage once"; 40 | for (int i = 1; i < num_types; ++i) { 41 | EXPECT_EQ(counts[i], 0) << "FetchPage Should not call other functions"; 42 | } 43 | } 44 | 45 | void CheckUnpinPage() { 46 | EXPECT_EQ(counts[1], 1) << "has to call UnpinPage once"; 47 | for (int i = 0; i < num_types; ++i) { 48 | if (i != 1) { 49 | EXPECT_EQ(counts[i], 0) << "UnPinPage Should not call other functions"; 50 | } 51 | } 52 | } 53 | 54 | void CheckFlushPage() { 55 | EXPECT_EQ(counts[2], 1) << "has to call FlushPage once"; 56 | for (int i = 0; i < num_types; ++i) { 57 | if (i != 2) { 58 | EXPECT_EQ(counts[i], 0) << "FlushPage Should not call other functions"; 59 | } 60 | } 61 | } 62 | 63 | void CheckNewPage() { 64 | EXPECT_EQ(counts[3], 1) << "has to call NewPage once"; 65 | for (int i = 0; i < num_types; ++i) { 66 | if (i != 3) { 67 | EXPECT_EQ(counts[i], 0) << "NewPage Should not call other functions"; 68 | } 69 | } 70 | } 71 | 72 | void CheckDeletePage() { 73 | EXPECT_EQ(counts[4], 1) << "has to call DeletePage once"; 74 | for (int i = 0; i < num_types; ++i) { 75 | if (i != 4) { 76 | EXPECT_EQ(counts[i], 0) << "DeletePage Should not call other functions"; 77 | } 78 | } 79 | } 80 | 81 | void CheckFlushAllPages() { 82 | for (int i = 1; i < 5; ++i) { 83 | EXPECT_EQ(counts[i], 0) << "FlushAllPage Should not call other functions"; 84 | } 85 | EXPECT_EQ(counts[5], 1) << "has to call FlushAllPage once"; 86 | } 87 | }; 88 | 89 | } // namespace bustub 90 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/test/buffer/lru_replacer_test.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // lru_replacer_test.cpp 6 | // 7 | // Identification: test/buffer/lru_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/lru_replacer.h" 18 | #include "gtest/gtest.h" 19 | 20 | namespace bustub { 21 | 22 | TEST(LRUReplacerTest, SampleTest) { 23 | LRUReplacer lru_replacer(7); 24 | 25 | // Scenario: unpin six elements, i.e. add them to the replacer. 26 | lru_replacer.Unpin(1); 27 | lru_replacer.Unpin(2); 28 | lru_replacer.Unpin(3); 29 | lru_replacer.Unpin(4); 30 | lru_replacer.Unpin(5); 31 | lru_replacer.Unpin(6); 32 | lru_replacer.Unpin(1); 33 | EXPECT_EQ(6, lru_replacer.Size()); 34 | 35 | // Scenario: get three victims from the lru. 36 | int value; 37 | lru_replacer.Victim(&value); 38 | EXPECT_EQ(1, value); 39 | lru_replacer.Victim(&value); 40 | EXPECT_EQ(2, value); 41 | lru_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 | lru_replacer.Pin(3); 47 | lru_replacer.Pin(4); 48 | EXPECT_EQ(2, lru_replacer.Size()); 49 | 50 | // Scenario: unpin 4. We expect that the reference bit of 4 will be set to 1. 51 | lru_replacer.Unpin(4); 52 | 53 | // Scenario: continue looking for victims. We expect these victims. 54 | lru_replacer.Victim(&value); 55 | EXPECT_EQ(5, value); 56 | lru_replacer.Victim(&value); 57 | EXPECT_EQ(6, value); 58 | lru_replacer.Victim(&value); 59 | EXPECT_EQ(4, value); 60 | } 61 | 62 | } // namespace bustub 63 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/test/storage/b_plus_tree_delete_test.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * b_plus_tree_delete_test.cpp 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "b_plus_tree_test_util.h" // NOLINT 9 | #include "buffer/buffer_pool_manager.h" 10 | #include "gtest/gtest.h" 11 | #include "storage/index/b_plus_tree.h" 12 | 13 | namespace bustub { 14 | 15 | TEST(BPlusTreeTests, DeleteTest1) { 16 | // create KeyComparator and index schema 17 | std::string createStmt = "a bigint"; 18 | Schema *key_schema = ParseCreateStatement(createStmt); 19 | GenericComparator<8> comparator(key_schema); 20 | 21 | DiskManager *disk_manager = new DiskManager("test.db"); 22 | BufferPoolManager *bpm = new BufferPoolManager(50, disk_manager); 23 | // create b+ tree 24 | BPlusTree, RID, GenericComparator<8>> tree("foo_pk", bpm, comparator); 25 | GenericKey<8> index_key; 26 | RID rid; 27 | // create transaction 28 | Transaction *transaction = new Transaction(0); 29 | 30 | // create and fetch header_page 31 | page_id_t page_id; 32 | auto header_page = bpm->NewPage(&page_id); 33 | (void)header_page; 34 | 35 | std::vector keys = {1, 2, 3, 4, 5}; 36 | for (auto key : keys) { 37 | int64_t value = key & 0xFFFFFFFF; 38 | rid.Set(static_cast(key >> 32), value); 39 | index_key.SetFromInteger(key); 40 | tree.Insert(index_key, rid, transaction); 41 | } 42 | 43 | std::vector rids; 44 | for (auto key : keys) { 45 | rids.clear(); 46 | index_key.SetFromInteger(key); 47 | tree.GetValue(index_key, &rids); 48 | EXPECT_EQ(rids.size(), 1); 49 | 50 | int64_t value = key & 0xFFFFFFFF; 51 | EXPECT_EQ(rids[0].GetSlotNum(), value); 52 | } 53 | 54 | int64_t start_key = 1; 55 | int64_t current_key = start_key; 56 | index_key.SetFromInteger(start_key); 57 | for (auto iterator = tree.Begin(index_key); iterator != tree.end(); ++iterator) { 58 | auto location = (*iterator).second; 59 | EXPECT_EQ(location.GetPageId(), 0); 60 | EXPECT_EQ(location.GetSlotNum(), current_key); 61 | current_key = current_key + 1; 62 | } 63 | 64 | EXPECT_EQ(current_key, keys.size() + 1); 65 | 66 | std::vector remove_keys = {1, 5}; 67 | for (auto key : remove_keys) { 68 | index_key.SetFromInteger(key); 69 | tree.Remove(index_key, transaction); 70 | } 71 | 72 | start_key = 2; 73 | current_key = start_key; 74 | int64_t size = 0; 75 | index_key.SetFromInteger(start_key); 76 | for (auto iterator = tree.Begin(index_key); iterator != tree.end(); ++iterator) { 77 | auto location = (*iterator).second; 78 | EXPECT_EQ(location.GetPageId(), 0); 79 | EXPECT_EQ(location.GetSlotNum(), current_key); 80 | current_key = current_key + 1; 81 | size = size + 1; 82 | } 83 | 84 | EXPECT_EQ(size, 3); 85 | 86 | bpm->UnpinPage(HEADER_PAGE_ID, true); 87 | delete key_schema; 88 | delete transaction; 89 | delete disk_manager; 90 | delete bpm; 91 | remove("test.db"); 92 | remove("test.log"); 93 | } 94 | 95 | TEST(BPlusTreeTests, DeleteTest2) { 96 | // create KeyComparator and index schema 97 | Schema *key_schema = ParseCreateStatement("a bigint"); 98 | GenericComparator<8> comparator(key_schema); 99 | 100 | DiskManager *disk_manager = new DiskManager("test.db"); 101 | BufferPoolManager *bpm = new BufferPoolManager(50, disk_manager); 102 | // create b+ tree 103 | BPlusTree, RID, GenericComparator<8>> tree("foo_pk", bpm, comparator); 104 | GenericKey<8> index_key; 105 | RID rid; 106 | // create transaction 107 | Transaction *transaction = new Transaction(0); 108 | 109 | // create and fetch header_page 110 | page_id_t page_id; 111 | auto header_page = bpm->NewPage(&page_id); 112 | (void)header_page; 113 | 114 | std::vector keys = {1, 2, 3, 4, 5}; 115 | for (auto key : keys) { 116 | int64_t value = key & 0xFFFFFFFF; 117 | rid.Set(static_cast(key >> 32), value); 118 | index_key.SetFromInteger(key); 119 | tree.Insert(index_key, rid, transaction); 120 | } 121 | 122 | std::vector rids; 123 | for (auto key : keys) { 124 | rids.clear(); 125 | index_key.SetFromInteger(key); 126 | tree.GetValue(index_key, &rids); 127 | EXPECT_EQ(rids.size(), 1); 128 | 129 | int64_t value = key & 0xFFFFFFFF; 130 | EXPECT_EQ(rids[0].GetSlotNum(), value); 131 | } 132 | 133 | int64_t start_key = 1; 134 | int64_t current_key = start_key; 135 | index_key.SetFromInteger(start_key); 136 | for (auto iterator = tree.Begin(index_key); iterator != tree.end(); ++iterator) { 137 | auto location = (*iterator).second; 138 | EXPECT_EQ(location.GetPageId(), 0); 139 | EXPECT_EQ(location.GetSlotNum(), current_key); 140 | current_key = current_key + 1; 141 | } 142 | 143 | EXPECT_EQ(current_key, keys.size() + 1); 144 | 145 | std::vector remove_keys = {1, 5, 3, 4}; 146 | for (auto key : remove_keys) { 147 | index_key.SetFromInteger(key); 148 | tree.Remove(index_key, transaction); 149 | } 150 | 151 | start_key = 2; 152 | current_key = start_key; 153 | int64_t size = 0; 154 | index_key.SetFromInteger(start_key); 155 | for (auto iterator = tree.Begin(index_key); iterator != tree.end(); ++iterator) { 156 | auto location = (*iterator).second; 157 | EXPECT_EQ(location.GetPageId(), 0); 158 | EXPECT_EQ(location.GetSlotNum(), current_key); 159 | current_key = current_key + 1; 160 | size = size + 1; 161 | } 162 | 163 | EXPECT_EQ(size, 1); 164 | 165 | bpm->UnpinPage(HEADER_PAGE_ID, true); 166 | delete key_schema; 167 | delete transaction; 168 | delete disk_manager; 169 | delete bpm; 170 | remove("test.db"); 171 | remove("test.log"); 172 | } 173 | } // namespace bustub 174 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/test/storage/b_plus_tree_insert_test.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * b_plus_tree_insert_test.cpp 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #include "b_plus_tree_test_util.h" // NOLINT 9 | #include "buffer/buffer_pool_manager.h" 10 | #include "gtest/gtest.h" 11 | #include "storage/index/b_plus_tree.h" 12 | 13 | namespace bustub { 14 | 15 | TEST(BPlusTreeTests, InsertTest1) { 16 | // create KeyComparator and index schema 17 | Schema *key_schema = ParseCreateStatement("a bigint"); 18 | GenericComparator<8> comparator(key_schema); 19 | 20 | DiskManager *disk_manager = new DiskManager("test.db"); 21 | BufferPoolManager *bpm = new BufferPoolManager(50, disk_manager); 22 | // create b+ tree 23 | BPlusTree, RID, GenericComparator<8>> tree("foo_pk", bpm, comparator, 2, 3); 24 | GenericKey<8> index_key; 25 | RID rid; 26 | // create transaction 27 | Transaction *transaction = new Transaction(0); 28 | 29 | // create and fetch header_page 30 | page_id_t page_id; 31 | auto header_page = bpm->NewPage(&page_id); 32 | (void)header_page; 33 | 34 | std::vector keys = {1, 2, 3, 4, 5}; 35 | for (auto key : keys) { 36 | int64_t value = key & 0xFFFFFFFF; 37 | rid.Set(static_cast(key >> 32), value); 38 | index_key.SetFromInteger(key); 39 | tree.Insert(index_key, rid, transaction); 40 | } 41 | 42 | std::vector rids; 43 | for (auto key : keys) { 44 | rids.clear(); 45 | index_key.SetFromInteger(key); 46 | tree.GetValue(index_key, &rids); 47 | EXPECT_EQ(rids.size(), 1); 48 | 49 | int64_t value = key & 0xFFFFFFFF; 50 | EXPECT_EQ(rids[0].GetSlotNum(), value); 51 | } 52 | 53 | int64_t start_key = 1; 54 | int64_t current_key = start_key; 55 | index_key.SetFromInteger(start_key); 56 | for (auto iterator = tree.Begin(index_key); iterator != tree.end(); ++iterator) { 57 | auto location = (*iterator).second; 58 | EXPECT_EQ(location.GetPageId(), 0); 59 | EXPECT_EQ(location.GetSlotNum(), current_key); 60 | current_key = current_key + 1; 61 | } 62 | 63 | EXPECT_EQ(current_key, keys.size() + 1); 64 | 65 | bpm->UnpinPage(HEADER_PAGE_ID, true); 66 | delete key_schema; 67 | delete transaction; 68 | delete disk_manager; 69 | delete bpm; 70 | remove("test.db"); 71 | remove("test.log"); 72 | } 73 | 74 | TEST(BPlusTreeTests, InsertTest2) { 75 | // create KeyComparator and index schema 76 | Schema *key_schema = ParseCreateStatement("a bigint"); 77 | GenericComparator<8> comparator(key_schema); 78 | 79 | DiskManager *disk_manager = new DiskManager("test.db"); 80 | BufferPoolManager *bpm = new BufferPoolManager(50, disk_manager); 81 | // create b+ tree 82 | BPlusTree, RID, GenericComparator<8>> tree("foo_pk", bpm, comparator); 83 | GenericKey<8> index_key; 84 | RID rid; 85 | // create transaction 86 | Transaction *transaction = new Transaction(0); 87 | 88 | // create and fetch header_page 89 | page_id_t page_id; 90 | auto header_page = bpm->NewPage(&page_id); 91 | (void)header_page; 92 | 93 | std::vector keys = {5, 4, 3, 2, 1}; 94 | for (auto key : keys) { 95 | int64_t value = key & 0xFFFFFFFF; 96 | rid.Set(static_cast(key >> 32), value); 97 | index_key.SetFromInteger(key); 98 | tree.Insert(index_key, rid, transaction); 99 | } 100 | 101 | std::vector rids; 102 | for (auto key : keys) { 103 | rids.clear(); 104 | index_key.SetFromInteger(key); 105 | tree.GetValue(index_key, &rids); 106 | EXPECT_EQ(rids.size(), 1); 107 | 108 | int64_t value = key & 0xFFFFFFFF; 109 | EXPECT_EQ(rids[0].GetSlotNum(), value); 110 | } 111 | 112 | int64_t start_key = 1; 113 | int64_t current_key = start_key; 114 | index_key.SetFromInteger(start_key); 115 | for (auto iterator = tree.Begin(index_key); iterator != tree.end(); ++iterator) { 116 | auto location = (*iterator).second; 117 | EXPECT_EQ(location.GetPageId(), 0); 118 | EXPECT_EQ(location.GetSlotNum(), current_key); 119 | current_key = current_key + 1; 120 | } 121 | 122 | EXPECT_EQ(current_key, keys.size() + 1); 123 | 124 | start_key = 3; 125 | current_key = start_key; 126 | index_key.SetFromInteger(start_key); 127 | for (auto iterator = tree.Begin(index_key); iterator != tree.end(); ++iterator) { 128 | auto location = (*iterator).second; 129 | EXPECT_EQ(location.GetPageId(), 0); 130 | EXPECT_EQ(location.GetSlotNum(), current_key); 131 | current_key = current_key + 1; 132 | } 133 | 134 | bpm->UnpinPage(HEADER_PAGE_ID, true); 135 | delete key_schema; 136 | delete transaction; 137 | delete disk_manager; 138 | delete bpm; 139 | remove("test.db"); 140 | remove("test.log"); 141 | } 142 | } // namespace bustub 143 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/test/storage/b_plus_tree_print_test.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * b_plus_tree_test.cpp 3 | * 4 | * This ia a local Debug test. 5 | * Feel free to change this file for your own testing purpose. 6 | * 7 | * THIS TEST WILL NOT BE RUN ON GRADESCOPE 8 | * THIS TEST WILL NOT BE RUN ON GRADESCOPE 9 | * THIS TEST WILL NOT BE RUN ON GRADESCOPE 10 | * THIS TEST WILL NOT BE RUN ON GRADESCOPE 11 | * THIS TEST WILL NOT BE RUN ON GRADESCOPE 12 | * THIS TEST WILL NOT BE RUN ON GRADESCOPE 13 | * 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | #include "b_plus_tree_test_util.h" // NOLINT 20 | #include "buffer/buffer_pool_manager.h" 21 | #include "common/logger.h" 22 | #include "gtest/gtest.h" 23 | #include "storage/index/b_plus_tree.h" 24 | 25 | namespace bustub { 26 | 27 | std::string usageMessage() { 28 | std::string message = 29 | "Enter any of the following commands after the prompt > :\n" 30 | "\ti -- Insert (int64_t) as both key and value).\n" 31 | "\tf -- insert multiple keys from reading file.\n" 32 | "\tc -- delete multiple keys from reading file.\n" 33 | "\td -- Delete key and its associated value.\n" 34 | "\tg .dot -- Output the tree in graph format to a dot file\n" 35 | "\tp -- Print the B+ tree.\n" 36 | "\tq -- Quit. (Or use Ctl-D.)\n" 37 | "\t? -- Print this help message.\n\n" 38 | "Please Enter Leaf node max size and Internal node max size:\n" 39 | "Example: 5 5\n>"; 40 | return message; 41 | } 42 | 43 | // Remove 'DISABLED_' when you are ready 44 | TEST(BptTreeTest, UnitTest) { 45 | int64_t key = 0; 46 | GenericKey<8> index_key; 47 | RID rid; 48 | std::string filename; 49 | char instruction; 50 | bool quit = false; 51 | int leaf_max_size; 52 | int internal_max_size; 53 | 54 | std::cout << usageMessage(); 55 | std::cin >> leaf_max_size; 56 | std::cin >> internal_max_size; 57 | 58 | // create KeyComparator and index schema 59 | std::string createStmt = "a bigint"; 60 | Schema *key_schema = ParseCreateStatement(createStmt); 61 | GenericComparator<8> comparator(key_schema); 62 | 63 | DiskManager *disk_manager = new DiskManager("test.db"); 64 | BufferPoolManager *bpm = new BufferPoolManager(100, disk_manager); 65 | // create and fetch header_page 66 | page_id_t page_id; 67 | auto header_page = bpm->NewPage(&page_id); 68 | // create b+ tree 69 | BPlusTree, RID, GenericComparator<8>> tree("foo_pk", bpm, comparator, leaf_max_size, internal_max_size); 70 | // create transaction 71 | Transaction *transaction = new Transaction(0); 72 | while (!quit) { 73 | std::cout << "> "; 74 | std::cin >> instruction; 75 | switch (instruction) { 76 | case 'c': 77 | std::cin >> filename; 78 | tree.RemoveFromFile(filename, transaction); 79 | break; 80 | case 'd': 81 | std::cin >> key; 82 | index_key.SetFromInteger(key); 83 | tree.Remove(index_key, transaction); 84 | break; 85 | case 'i': 86 | std::cin >> key; 87 | rid.Set(static_cast(key >> 32), static_cast(key & 0xFFFFFFFF)); 88 | index_key.SetFromInteger(key); 89 | tree.Insert(index_key, rid, transaction); 90 | break; 91 | case 'f': 92 | std::cin >> filename; 93 | tree.InsertFromFile(filename, transaction); 94 | break; 95 | case 'q': 96 | quit = true; 97 | break; 98 | case 'p': 99 | tree.Print(bpm); 100 | break; 101 | case 'g': 102 | std::cin >> filename; 103 | tree.Draw(bpm, filename); 104 | break; 105 | case '?': 106 | std::cout << usageMessage(); 107 | break; 108 | default: 109 | std::cin.ignore(256, '\n'); 110 | std::cout << usageMessage(); 111 | break; 112 | } 113 | } 114 | bpm->UnpinPage(header_page->GetPageId(), true); 115 | delete key_schema; 116 | delete bpm; 117 | delete transaction; 118 | delete disk_manager; 119 | remove("test.db"); 120 | remove("test.log"); 121 | } 122 | } // namespace bustub 123 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/test/storage/b_plus_tree_test_util.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 | #include 19 | #include 20 | #include 21 | 22 | #include "catalog/schema.h" 23 | #include "common/exception.h" 24 | #include "common/logger.h" 25 | #include "common/util/string_util.h" 26 | #include "storage/page/header_page.h" 27 | 28 | namespace bustub { 29 | 30 | /* Helpers */ 31 | Schema *ParseCreateStatement(const std::string &sql_base) { 32 | std::string::size_type n; 33 | std::vector v; 34 | std::string column_name; 35 | std::string column_type; 36 | int column_length = 0; 37 | TypeId type = INVALID; 38 | // create a copy of the sql query 39 | std::string sql = sql_base; 40 | // prepocess, transform sql string into lower case 41 | std::transform(sql.begin(), sql.end(), sql.begin(), ::tolower); 42 | std::vector tok = StringUtil::Split(sql, ','); 43 | // iterate through returned result 44 | for (std::string &t : tok) { 45 | type = INVALID; 46 | column_length = 0; 47 | // whitespace seperate column name and type 48 | n = t.find_first_of(' '); 49 | column_name = t.substr(0, n); 50 | column_type = t.substr(n + 1); 51 | // deal with varchar(size) situation 52 | n = column_type.find_first_of('('); 53 | if (n != std::string::npos) { 54 | column_length = std::stoi(column_type.substr(n + 1)); 55 | column_type = column_type.substr(0, n); 56 | } 57 | if (column_type == "bool" || column_type == "boolean") { 58 | type = BOOLEAN; 59 | } else if (column_type == "tinyint") { 60 | type = TINYINT; 61 | } else if (column_type == "smallint") { 62 | type = SMALLINT; 63 | } else if (column_type == "int" || column_type == "integer") { 64 | type = INTEGER; 65 | } else if (column_type == "bigint") { 66 | type = BIGINT; 67 | } else if (column_type == "double" || column_type == "float") { 68 | type = DECIMAL; 69 | } else if (column_type == "varchar" || column_type == "char") { 70 | type = VARCHAR; 71 | column_length = (column_length == 0) ? 32 : column_length; 72 | } 73 | // construct each column 74 | if (type == INVALID) { 75 | throw Exception(ExceptionType::UNKNOWN_TYPE, "unknown type for create table"); 76 | } else if (type == VARCHAR) { 77 | Column col(column_name, type, column_length); 78 | v.emplace_back(col); 79 | } else { 80 | Column col(column_name, type); 81 | v.emplace_back(col); 82 | } 83 | } 84 | Schema *schema = new Schema(v); 85 | // LOG_DEBUG("%s", schema->ToString().c_str()); 86 | 87 | return schema; 88 | } 89 | 90 | } // namespace bustub 91 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/test/storage/disk_manager_test.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // disk_manager_test.cpp 6 | // 7 | // Identification: test/storage/disk/disk_manager_test.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include 14 | 15 | #include "common/exception.h" 16 | #include "gtest/gtest.h" 17 | #include "storage/disk/disk_manager.h" 18 | 19 | namespace bustub { 20 | 21 | class DiskManagerTest : public ::testing::Test { 22 | protected: 23 | // This function is called before every test. 24 | void SetUp() override { 25 | remove("test.db"); 26 | remove("test.log"); 27 | } 28 | 29 | // This function is called after every test. 30 | void TearDown() override { 31 | remove("test.db"); 32 | remove("test.log"); 33 | }; 34 | }; 35 | 36 | // NOLINTNEXTLINE 37 | TEST_F(DiskManagerTest, ReadWritePageTest) { 38 | char buf[PAGE_SIZE] = {0}; 39 | char data[PAGE_SIZE] = {0}; 40 | std::string db_file("test.db"); 41 | auto dm = DiskManager(db_file); 42 | std::strncpy(data, "A test string.", sizeof(data)); 43 | 44 | dm.ReadPage(0, buf); // tolerate empty read 45 | 46 | dm.WritePage(0, data); 47 | dm.ReadPage(0, buf); 48 | EXPECT_EQ(std::memcmp(buf, data, sizeof(buf)), 0); 49 | 50 | std::memset(buf, 0, sizeof(buf)); 51 | dm.WritePage(5, data); 52 | dm.ReadPage(5, buf); 53 | EXPECT_EQ(std::memcmp(buf, data, sizeof(buf)), 0); 54 | 55 | dm.ShutDown(); 56 | } 57 | 58 | // NOLINTNEXTLINE 59 | TEST_F(DiskManagerTest, ReadWriteLogTest) { 60 | char buf[16] = {0}; 61 | char data[16] = {0}; 62 | std::string db_file("test.db"); 63 | auto dm = DiskManager(db_file); 64 | std::strncpy(data, "A test string.", sizeof(data)); 65 | 66 | dm.ReadLog(buf, sizeof(buf), 0); // tolerate empty read 67 | 68 | dm.WriteLog(data, sizeof(data)); 69 | dm.ReadLog(buf, sizeof(buf), 0); 70 | EXPECT_EQ(std::memcmp(buf, data, sizeof(buf)), 0); 71 | 72 | dm.ShutDown(); 73 | } 74 | 75 | // NOLINTNEXTLINE 76 | TEST_F(DiskManagerTest, ThrowBadFileTest) { EXPECT_THROW(DiskManager("dev/null\\/foo/bar/baz/test.db"), Exception); } 77 | 78 | } // namespace bustub 79 | -------------------------------------------------------------------------------- /Project#2-BplusTreeIndex/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 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/buffer/lru_replacer.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // lru_replacer.cpp 6 | // 7 | // Identification: src/buffer/lru_replacer.cpp 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "buffer/lru_replacer.h" 14 | 15 | namespace bustub { 16 | 17 | LRUReplacer::LRUReplacer(size_t num_pages) : capacity{num_pages} {} 18 | 19 | LRUReplacer::~LRUReplacer() = default; 20 | 21 | /** 22 | * 根据LRU策略从LRU lru_list中找到牺牲页,(lru_list 最前面的元素是最早加进来的) 23 | * 1.如果没有可以牺牲的page直接返回false 24 | * 2.如果有的话选择在链表尾部的page, remove它即可. 这里的删除涉及链表和lru_map表两个数据结构的删除 25 | * 3.为了防止并发错误,以下操作均需要加锁 26 | */ 27 | bool LRUReplacer::Victim(frame_id_t *frame_id) { 28 | // 在lock_guard对象构造时,传入的mutex对象会被当前线程锁住 29 | const std::lock_guard guard(mutex); 30 | 31 | if (lru_list.empty()) { 32 | return false; 33 | } 34 | 35 | auto f = lru_list.front(); 36 | lru_list.pop_front(); 37 | 38 | // map.find()如果未找到则返回引用map.end()的迭代器 39 | auto lru_map_it = lru_map.find(f); 40 | 41 | if (lru_map_it != lru_map.end()) { // 如果不是没有找到元素 42 | lru_map.erase(lru_map_it); 43 | *frame_id = f; 44 | return true; 45 | } 46 | 47 | return false; 48 | } 49 | 50 | /** 51 | * 在将某page固定到BufferPoolManager中的某一frame之后,应调用此方法Pin() 52 | * 此方法应该从LRUReplacer中删除包含这个已经固定的page的某一frame,表示该frame不能成为LRU牺牲的对象 53 | * 54 | * 1.pin函数表示这个frame被某个进程引用了 55 | * 2.被引用的frame不能成为LRU算法的牺牲目标.所以这里把它从我们的数据结构中删除 56 | * 57 | */ 58 | void LRUReplacer::Pin(frame_id_t frame_id) { 59 | const std::lock_guard guard(mutex); 60 | 61 | // lru_map是一个unordered_map; key=frame_id_t , value=list lst的迭代器 62 | // lru_map_it尝试找到lru_map中Key=frame_id的键值对,返回指向该KV的迭代器 63 | auto lru_map_it = lru_map.find(frame_id); 64 | if (lru_map_it != lru_map.end()) { 65 | // erase()方法是删除iterator指定的节点 66 | lru_list.erase(lru_map_it->second); // 从lru_list中删除该页 (lru_map_it->second是指向该页的迭代器) 67 | lru_map.erase(lru_map_it); 68 | } 69 | } 70 | 71 | void LRUReplacer::Unpin(frame_id_t frame_id) { 72 | const std::lock_guard guard(mutex); 73 | 74 | if (lru_map.size() >= capacity) { 75 | return; 76 | } 77 | 78 | // This step of logical processing is very IMPORTANT 79 | // BUT I DO NOT KNOW THE REASON 80 | auto lru_map_it = lru_map.find(frame_id); 81 | 82 | if (lru_map_it != lru_map.end()) { 83 | return; 84 | } 85 | 86 | if (lru_map_it == lru_map.end()) { 87 | while (lru_map.size() >= capacity) { 88 | frame_id_t need_del = lru_list.back(); 89 | lru_list.pop_back(); 90 | if (lru_map.find(need_del) != lru_map.end()) { 91 | lru_map.erase(need_del); 92 | } 93 | } 94 | } 95 | 96 | lru_list.push_back(frame_id); 97 | // std::prev(lru_list.end(),1) 返回lru_list.end()的前面的距离它为1的元素的迭代器 98 | // 即指向lst的最后一个实际元素的迭代器,也就是lst中指向末尾这个新插入的帧id的迭代器 99 | lru_map.emplace(frame_id, std::prev(lru_list.end(), 1)); 100 | } 101 | 102 | size_t LRUReplacer::Size() { 103 | const std::lock_guard guard(mutex); 104 | 105 | return lru_map.size(); 106 | } 107 | 108 | } // namespace bustub 109 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/execution/aggregation_executor.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // aggregation_executor.cpp 6 | // 7 | // Identification: src/execution/aggregation_executor.cpp 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | #include "execution/executors/aggregation_executor.h" 13 | 14 | #include 15 | #include 16 | 17 | namespace bustub { 18 | 19 | // lab3 task2 modify 20 | AggregationExecutor::AggregationExecutor(ExecutorContext *exec_ctx, const AggregationPlanNode *plan, 21 | std::unique_ptr &&child) 22 | : AbstractExecutor(exec_ctx), 23 | plan_{plan}, 24 | child_{std::move(child)}, 25 | aht_{plan_->GetAggregates(), plan_->GetAggregateTypes()}, 26 | aht_iterator_{aht_.Begin()} {} 27 | 28 | const AbstractExecutor *AggregationExecutor::GetChildExecutor() const { return child_.get(); } 29 | 30 | // lab3 tesk2 modify 31 | void AggregationExecutor::Init() { 32 | child_->Init(); 33 | 34 | Tuple tuple; 35 | RID rid; 36 | 37 | while (child_->Next(&tuple, &rid)) { 38 | // lock on to-read rid 39 | // ... 40 | // ... 41 | 42 | aht_.InsertCombine(MakeKey(&tuple), MakeVal(&tuple)); 43 | } 44 | 45 | aht_iterator_ = aht_.Begin(); 46 | } 47 | 48 | // lab3 task2 modify 49 | bool AggregationExecutor::Next(Tuple *tuple, RID *rid) { 50 | // fetch qualified group_bys and aggregates 51 | std::vector group_bys; 52 | std::vector aggregates; 53 | 54 | do { 55 | if (aht_iterator_ == aht_.End()) { 56 | return false; 57 | } 58 | 59 | group_bys = aht_iterator_.Key().group_bys_; 60 | aggregates = aht_iterator_.Val().aggregates_; 61 | 62 | ++aht_iterator_; 63 | 64 | } while (plan_->GetHaving() != nullptr && 65 | !plan_->GetHaving()->EvaluateAggregate(group_bys, aggregates).GetAs()); 66 | 67 | // 生成输出元组 68 | std::vector values; 69 | 70 | std::transform( 71 | plan_->OutputSchema()->GetColumns().begin(), plan_->OutputSchema()->GetColumns().end(), 72 | std::back_inserter(values), 73 | [&group_bys, &aggregates](const Column &col) { return col.GetExpr()->EvaluateAggregate(group_bys, aggregates); } 74 | 75 | ); 76 | 77 | *tuple = Tuple{values, plan_->OutputSchema()}; 78 | 79 | return true; 80 | } 81 | 82 | } // namespace bustub 83 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/execution/delete_executor.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // delete_executor.cpp 6 | // 7 | // Identification: src/execution/delete_executor.cpp 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | #include "execution/executors/delete_executor.h" 13 | 14 | #include 15 | 16 | namespace bustub { 17 | 18 | DeleteExecutor::DeleteExecutor(ExecutorContext *exec_ctx, const DeletePlanNode *plan, 19 | std::unique_ptr &&child_executor) 20 | : AbstractExecutor(exec_ctx), plan_{plan}, child_executor_{std::move(child_executor)} { 21 | table_info_ = exec_ctx_->GetCatalog()->GetTable(plan_->TableOid()); 22 | } 23 | 24 | void DeleteExecutor::Init() { 25 | child_executor_->Init(); 26 | 27 | table_indexes = exec_ctx_->GetCatalog()->GetTableIndexes(table_info_->name_); 28 | } 29 | 30 | bool DeleteExecutor::Next([[maybe_unused]] Tuple *tuple, RID *rid) { 31 | Tuple to_delete_tuple; 32 | RID emit_rid; 33 | 34 | if (!child_executor_->Next(&to_delete_tuple, &emit_rid)) { 35 | return false; 36 | } 37 | 38 | // lock on to-delete rid 39 | // ... 40 | // ... 41 | 42 | bool marked = table_info_->table_->MarkDelete(emit_rid, exec_ctx_->GetTransaction()); 43 | 44 | if (marked) { 45 | std::for_each(table_indexes.begin(), table_indexes.end(), 46 | [&to_delete_tuple, &emit_rid, &table_info = table_info_, &ctx = exec_ctx_](IndexInfo *index) { 47 | // 删除对应索引 48 | index->index_->DeleteEntry(to_delete_tuple.KeyFromTuple(table_info->schema_, index->key_schema_, 49 | index->index_->GetKeyAttrs()), 50 | emit_rid, ctx->GetTransaction()); 51 | // 在此事务的索引写入记录列表尾部加入新记录 52 | ctx->GetTransaction()->GetIndexWriteSet()->emplace_back(emit_rid, table_info->oid_, WType::DELETE, 53 | to_delete_tuple, Tuple{}, index->index_oid_, 54 | ctx->GetCatalog()); 55 | }); 56 | } 57 | 58 | return marked; 59 | } 60 | 61 | } // namespace bustub 62 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/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 | #include "execution/executors/abstract_executor.h" 18 | #include "execution/executors/aggregation_executor.h" 19 | #include "execution/executors/delete_executor.h" 20 | #include "execution/executors/index_scan_executor.h" 21 | #include "execution/executors/insert_executor.h" 22 | #include "execution/executors/limit_executor.h" 23 | #include "execution/executors/nested_index_join_executor.h" 24 | #include "execution/executors/nested_loop_join_executor.h" 25 | #include "execution/executors/seq_scan_executor.h" 26 | #include "execution/executors/update_executor.h" 27 | #include "storage/index/generic_key.h" 28 | 29 | namespace bustub { 30 | 31 | std::unique_ptr ExecutorFactory::CreateExecutor(ExecutorContext *exec_ctx, 32 | const AbstractPlanNode *plan) { 33 | switch (plan->GetType()) { 34 | // Create a new sequential scan executor. 35 | case PlanType::SeqScan: { 36 | return std::make_unique(exec_ctx, dynamic_cast(plan)); 37 | } 38 | 39 | case PlanType::IndexScan: { 40 | return std::make_unique(exec_ctx, dynamic_cast(plan)); 41 | } 42 | 43 | // Create a new insert executor. 44 | case PlanType::Insert: { 45 | auto insert_plan = dynamic_cast(plan); 46 | auto child_executor = 47 | insert_plan->IsRawInsert() ? nullptr : ExecutorFactory::CreateExecutor(exec_ctx, insert_plan->GetChildPlan()); 48 | return std::make_unique(exec_ctx, insert_plan, std::move(child_executor)); 49 | } 50 | 51 | case PlanType::Update: { 52 | auto update_plan = dynamic_cast(plan); 53 | auto child_executor = ExecutorFactory::CreateExecutor(exec_ctx, update_plan->GetChildPlan()); 54 | return std::make_unique(exec_ctx, update_plan, std::move(child_executor)); 55 | } 56 | 57 | case PlanType::Delete: { 58 | auto delete_plan = dynamic_cast(plan); 59 | auto child_executor = ExecutorFactory::CreateExecutor(exec_ctx, delete_plan->GetChildPlan()); 60 | return std::make_unique(exec_ctx, delete_plan, std::move(child_executor)); 61 | } 62 | 63 | case PlanType::Limit: { 64 | auto limit_plan = dynamic_cast(plan); 65 | auto child_executor = ExecutorFactory::CreateExecutor(exec_ctx, limit_plan->GetChildPlan()); 66 | return std::make_unique(exec_ctx, limit_plan, std::move(child_executor)); 67 | } 68 | 69 | // Create a new aggregation executor. 70 | case PlanType::Aggregation: { 71 | auto agg_plan = dynamic_cast(plan); 72 | auto child_executor = ExecutorFactory::CreateExecutor(exec_ctx, agg_plan->GetChildPlan()); 73 | return std::make_unique(exec_ctx, agg_plan, std::move(child_executor)); 74 | } 75 | 76 | case PlanType::NestedLoopJoin: { 77 | auto nested_loop_join_plan = dynamic_cast(plan); 78 | auto left = ExecutorFactory::CreateExecutor(exec_ctx, nested_loop_join_plan->GetLeftPlan()); 79 | auto right = ExecutorFactory::CreateExecutor(exec_ctx, nested_loop_join_plan->GetRightPlan()); 80 | return std::make_unique(exec_ctx, nested_loop_join_plan, std::move(left), 81 | std::move(right)); 82 | } 83 | 84 | case PlanType::NestedIndexJoin: { 85 | auto nested_index_join_plan = dynamic_cast(plan); 86 | auto left = ExecutorFactory::CreateExecutor(exec_ctx, nested_index_join_plan->GetChildPlan()); 87 | return std::make_unique(exec_ctx, nested_index_join_plan, std::move(left)); 88 | } 89 | 90 | default: { 91 | BUSTUB_ASSERT(false, "Unsupported plan type."); 92 | } 93 | } 94 | } 95 | 96 | } // namespace bustub 97 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/execution/index_scan_executor.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // index_scan_executor.cpp 6 | // 7 | // Identification: src/execution/index_scan_executor.cpp 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | #include "execution/executors/index_scan_executor.h" 13 | 14 | namespace bustub { 15 | 16 | // lab3 task2 modify 17 | IndexScanExecutor::IndexScanExecutor(ExecutorContext *exec_ctx, const IndexScanPlanNode *plan) 18 | : AbstractExecutor(exec_ctx), plan_{plan} { 19 | index_info_ = exec_ctx_->GetCatalog()->GetIndex(plan_->GetIndexOid()); 20 | table_info_ = exec_ctx_->GetCatalog()->GetTable(index_info_->table_name_); 21 | } 22 | // lab3 task2 modify 23 | void IndexScanExecutor::Init() { 24 | index_iter = std::make_unique(GetBPlusTreeIndex()->GetBeginIterator()); 25 | } 26 | // lab3 task2 modify 27 | bool IndexScanExecutor::Next(Tuple *tuple, RID *rid) { 28 | // fetch raw tuple from table 29 | Tuple raw_tuple; 30 | 31 | do { 32 | if (*index_iter == GetBPlusTreeIndex()->GetEndIterator()) { 33 | return false; 34 | } 35 | 36 | bool fetched = table_info_->table_->GetTuple((*(*index_iter)).second, &raw_tuple, exec_ctx_->GetTransaction()); 37 | 38 | if (!fetched) { 39 | return false; 40 | } 41 | 42 | ++(*index_iter); 43 | } while (plan_->GetPredicate() != nullptr && 44 | !plan_->GetPredicate()->Evaluate(&raw_tuple, &(table_info_->schema_)).GetAs()); 45 | 46 | // 生成输出tuple 47 | std::vector values; 48 | std::transform(plan_->OutputSchema()->GetColumns().begin(), 49 | plan_->OutputSchema()->GetColumns().end(), // range 50 | std::back_inserter(values), // tranform storager 51 | [&raw_tuple, &table_info = table_info_](const Column &col) { 52 | return col.GetExpr()->Evaluate(&raw_tuple, &(table_info->schema_)); 53 | }); 54 | 55 | *tuple = Tuple{values, plan_->OutputSchema()}; 56 | *rid = raw_tuple.GetRid(); 57 | 58 | return true; 59 | } 60 | 61 | } // namespace bustub 62 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/execution/insert_executor.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // insert_executor.cpp 6 | // 7 | // Identification: src/execution/insert_executor.cpp 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | #include "execution/executors/insert_executor.h" 13 | 14 | #include 15 | #include 16 | 17 | namespace bustub { 18 | 19 | // lab3 task2 modify 20 | InsertExecutor::InsertExecutor(ExecutorContext *exec_ctx, const InsertPlanNode *plan, 21 | std::unique_ptr &&child_executor) 22 | : AbstractExecutor(exec_ctx), plan_{plan}, child_executor_{std::move(child_executor)} { 23 | table_info_ = exec_ctx_->GetCatalog()->GetTable(plan_->TableOid()); 24 | } 25 | 26 | // lab3 task2 modify 27 | void InsertExecutor::Init() { 28 | if (child_executor_ != nullptr) { 29 | child_executor_->Init(); 30 | } 31 | 32 | table_indexes = exec_ctx_->GetCatalog()->GetTableIndexes(table_info_->name_); 33 | } 34 | 35 | // lab3 task2 modify 36 | bool InsertExecutor::Next([[maybe_unused]] Tuple *tuple, RID *rid) { 37 | Tuple to_insert_tuple; 38 | 39 | // 如果将insert值直接嵌入到计划中,则为true;如果是child plan提供tuple,则为false 40 | if (plan_->IsRawInsert()) { 41 | if (next_insert >= plan_->RawValues().size()) { 42 | return false; 43 | } 44 | to_insert_tuple = Tuple(plan_->RawValuesAt(next_insert), &(table_info_->schema_)); 45 | ++next_insert; 46 | } else { 47 | RID emit_rid; 48 | if (!child_executor_->Next(&to_insert_tuple, &emit_rid)) { 49 | return false; 50 | } 51 | } 52 | 53 | bool inserted = table_info_->table_->InsertTuple(to_insert_tuple, rid, exec_ctx_->GetTransaction()); 54 | 55 | if (inserted) { 56 | // lock on new rid 57 | // exec_ctx_->GetLockManager()->LockExclusive(exec_ctx_->GetTransaction(), *rid); 58 | 59 | // maintain each index on inserted tuple 60 | std::for_each(table_indexes.begin(), table_indexes.end(), 61 | [&to_insert_tuple, &rid, &table_info = table_info_, &exec_ctx = exec_ctx_](IndexInfo *index) { 62 | index->index_->InsertEntry(to_insert_tuple.KeyFromTuple(table_info->schema_, index->key_schema_, 63 | index->index_->GetKeyAttrs()), 64 | *rid, exec_ctx->GetTransaction()); 65 | // 添加一个新的IndexWriteRecord到list of index write records of this transaction队尾 66 | // IndexWriteRecord由emplace_back参数直接构造(push_back无这个功能) 67 | exec_ctx->GetTransaction()->GetIndexWriteSet()->emplace_back( 68 | *rid, table_info->oid_, WType::INSERT, to_insert_tuple, Tuple{}, index->index_oid_, 69 | exec_ctx->GetCatalog()); 70 | }); 71 | } 72 | 73 | return inserted; 74 | } 75 | 76 | } // namespace bustub 77 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/execution/limit_executor.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // limit_executor.cpp 6 | // 7 | // Identification: src/execution/limit_executor.cpp 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "execution/executors/limit_executor.h" 14 | 15 | namespace bustub { 16 | 17 | // lab3 task2 modify 18 | LimitExecutor::LimitExecutor(ExecutorContext *exec_ctx, const LimitPlanNode *plan, 19 | std::unique_ptr &&child_executor) 20 | : AbstractExecutor(exec_ctx), plan_{plan}, child_executor_{std::move(child_executor)} {} 21 | 22 | // lab3 task2 modify 23 | void LimitExecutor::Init() { 24 | child_executor_->Init(); 25 | skipped = 0; 26 | emitted = 0; 27 | } 28 | 29 | // lab3 task2 modify 30 | bool LimitExecutor::Next(Tuple *tuple, RID *rid) { 31 | do { 32 | if (!child_executor_->Next(tuple, rid) || emitted >= plan_->GetLimit()) { 33 | return false; 34 | } 35 | } while (skipped++ < plan_->GetOffset()); 36 | 37 | ++emitted; 38 | 39 | return true; 40 | } 41 | 42 | } // namespace bustub 43 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/execution/nested_index_join_executor.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // nested_index_join_executor.cpp 6 | // 7 | // Identification: src/execution/nested_index_join_executor.cpp 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | #include "execution/executors/nested_index_join_executor.h" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace bustub { 19 | 20 | // lab3 task2 modify 21 | NestIndexJoinExecutor::NestIndexJoinExecutor(ExecutorContext *exec_ctx, const NestedIndexJoinPlanNode *plan, 22 | std::unique_ptr &&child_executor) 23 | : AbstractExecutor(exec_ctx), plan_{plan}, child_executor_{std::move(child_executor)} { 24 | inner_table_info_ = exec_ctx_->GetCatalog()->GetTable(plan_->GetInnerTableOid()); 25 | inner_index_info_ = exec_ctx_->GetCatalog()->GetIndex(plan_->GetIndexName(), inner_table_info_->name_); 26 | } 27 | 28 | // lab3 task2 modify 29 | void NestIndexJoinExecutor::Init() { child_executor_->Init(); } 30 | 31 | // lab3 task2 modify 32 | bool NestIndexJoinExecutor::Next(Tuple *tuple, RID *rid) { 33 | Tuple left_tuple; 34 | RID left_rid; 35 | Tuple right_raw_tuple; 36 | 37 | // fetch next qualified left tuple and right tuple pair 38 | // 获取下一个符合条件的的 (左元组,右元组) pair 39 | // 循环终止条件: Probe探测成功 且 谓词为空(无条件约束)或者满足谓词条件 40 | do { 41 | if (!child_executor_->Next(&left_tuple, &left_rid)) { 42 | return false; 43 | } 44 | } while (!Probe(&left_tuple, &right_raw_tuple) || 45 | (plan_->Predicate() != nullptr && 46 | !plan_->Predicate() 47 | ->EvaluateJoin(&left_tuple, plan_->OuterTableSchema(), &right_raw_tuple, &(inner_table_info_->schema_)) 48 | .GetAs())); 49 | // lock on to-read left and right rid 50 | // ... 51 | // ... 52 | 53 | // 生成输出元组 54 | std::vector values; 55 | std::transform(plan_->OutputSchema()->GetColumns().begin(), plan_->OutputSchema()->GetColumns().end(), 56 | std::back_inserter(values), 57 | [&left_tuple = left_tuple, &right_raw_tuple, &plan = plan_, 58 | &inner_table_schema = inner_table_info_->schema_](const Column &col) { 59 | return col.GetExpr()->EvaluateJoin(&left_tuple, plan->OuterTableSchema(), &right_raw_tuple, 60 | &inner_table_schema); 61 | }); 62 | 63 | *tuple = Tuple(values, plan_->OutputSchema()); 64 | 65 | return true; 66 | } 67 | 68 | // 利用innerTable的索引查找符合 JOIN 条件的 right_tuple 存入right_raw_tuple 69 | bool NestIndexJoinExecutor::Probe(Tuple *left_tuple, Tuple *right_raw_tuple) { 70 | Value key_value = plan_->Predicate()->GetChildAt(0)->EvaluateJoin(left_tuple, plan_->OuterTableSchema(), 71 | right_raw_tuple, &(inner_table_info_->schema_)); 72 | Tuple probe_key = Tuple{{key_value}, inner_index_info_->index_->GetKeySchema()}; 73 | 74 | std::vector result_set; 75 | GetBPlusTreeIndex()->ScanKey(probe_key, &result_set, exec_ctx_->GetTransaction()); 76 | 77 | if (result_set.empty()) { 78 | return false; 79 | } 80 | 81 | return inner_table_info_->table_->GetTuple(result_set[0], right_raw_tuple, exec_ctx_->GetTransaction()); 82 | } 83 | 84 | } // namespace bustub 85 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/execution/nested_loop_join_executor.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // nested_loop_join_executor.cpp 6 | // 7 | // Identification: src/execution/nested_loop_join_executor.cpp 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #include "execution/executors/nested_loop_join_executor.h" 14 | 15 | namespace bustub { 16 | 17 | // lab3 task2 modify 18 | NestedLoopJoinExecutor::NestedLoopJoinExecutor(ExecutorContext *exec_ctx, const NestedLoopJoinPlanNode *plan, 19 | std::unique_ptr &&left_executor, 20 | std::unique_ptr &&right_executor) 21 | : AbstractExecutor(exec_ctx), 22 | plan_{plan}, 23 | left_executor_{std::move(left_executor)}, 24 | right_executor_{std::move(right_executor)} {} 25 | 26 | // lab3 task2 modify 27 | void NestedLoopJoinExecutor::Init() { 28 | left_executor_->Init(); 29 | right_executor_->Init(); 30 | } 31 | 32 | // lab3 task2 modify 33 | bool NestedLoopJoinExecutor::Next(Tuple *tuple, RID *rid) { 34 | RID left_rid; 35 | // check if left tuple is initialized 36 | 37 | // 如果JOIN算子的left_tuple空,先调用左子算子(Outer Table)Next获得left_tuple,left_rid 38 | if (left_tuple.GetLength() == 0 && !left_executor_->Next(&left_tuple, &left_rid)) { 39 | return false; 40 | } 41 | 42 | // lock on to-read left rid 43 | // ... 44 | // ... 45 | 46 | // fetch next qualified left tuple and right tuple pair 47 | Tuple right_tuple; 48 | RID right_rid; 49 | 50 | // 将当前的OuterTable.tuple(left_tuple)与each right_tuple进行谓词匹配计算 51 | // 直到之后第一个符合条件的right_tuple, right_rid 52 | do { 53 | // 循环调用右子算子(Inner Table)Next,获得 next right_tuple, right_rid(下一条tuple) 54 | if (!Advance(&left_rid, &right_tuple, &right_rid)) { 55 | return false; 56 | } 57 | } while (plan_->Predicate() != nullptr && !plan_->Predicate() 58 | ->EvaluateJoin(&left_tuple, left_executor_->GetOutputSchema(), 59 | &right_tuple, right_executor_->GetOutputSchema()) 60 | .GetAs()); 61 | 62 | // lock on to-read rid 63 | // ... 64 | // ... 65 | 66 | // 生成输出tuple 67 | std::vector values; 68 | std::transform(plan_->OutputSchema()->GetColumns().begin(), plan_->OutputSchema()->GetColumns().end(), 69 | std::back_inserter(values), 70 | [&left_tuple = left_tuple, &left_executor = left_executor_, &right_tuple, 71 | &right_executor = right_executor_](const Column &col) { 72 | return col.GetExpr()->EvaluateJoin(&left_tuple, left_executor->GetOutputSchema(), &right_tuple, 73 | right_executor->GetOutputSchema()); 74 | }); 75 | 76 | *tuple = Tuple(values, plan_->OutputSchema()); 77 | 78 | return true; 79 | } 80 | 81 | bool NestedLoopJoinExecutor::Advance(RID *left_rid, Tuple *right_tuple, RID *right_rid) { 82 | if (!right_executor_->Next(right_tuple, right_rid)) { 83 | // 右子算子Next调用失败(tuple遍历到末尾了), 调用左子算子获取 next left_tuple left_rid 84 | if (!left_executor_->Next(&left_tuple, left_rid)) { 85 | return false; 86 | } 87 | // 再初始化右子算子, 进行Next调用(从头开始遍历 右 tuple) 88 | right_executor_->Init(); 89 | right_executor_->Next(right_tuple, right_rid); 90 | } 91 | return true; 92 | } 93 | 94 | } // namespace bustub 95 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/execution/seq_scan_executor.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // seq_scan_executor.cpp 6 | // 7 | // Identification: src/execution/seq_scan_executor.cpp 8 | // 9 | // Copyright (c) 2015-19, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | #include "execution/executors/seq_scan_executor.h" 13 | 14 | #include 15 | #include 16 | 17 | namespace bustub { 18 | 19 | // lab3 task2 modify 20 | SeqScanExecutor::SeqScanExecutor(ExecutorContext *exec_ctx, const SeqScanPlanNode *plan) 21 | : AbstractExecutor(exec_ctx), plan_{plan} { 22 | // exec_ctx => ExecutorContext 23 | table_info_ = exec_ctx_->GetCatalog()->GetTable(plan_->GetTableOid()); 24 | } 25 | // lab3 task2 modify 26 | void SeqScanExecutor::Init() { 27 | table_iter = std::make_unique(table_info_->table_->Begin(exec_ctx_->GetTransaction())); 28 | } 29 | // lab3 task2 modify 30 | bool SeqScanExecutor::Next(Tuple *tuple, RID *rid) { 31 | // fetch raw tuple from table 32 | Tuple raw_tuple; 33 | 34 | // 利用迭代器顺序扫描table,直到SeqScanExecutor::table_iter指向遇到的第一个满足谓词条件的tuple 35 | do { 36 | if (*table_iter == table_info_->table_->End()) { 37 | return false; 38 | } 39 | // TableIterator重载了运算符*,获取TableIterator.tuple_,即迭代器指向的table.tuple 40 | raw_tuple = *(*table_iter); 41 | 42 | ++(*table_iter); 43 | } while (plan_->GetPredicate() != nullptr && 44 | !plan_->GetPredicate()->Evaluate(&raw_tuple, &(table_info_->schema_)).GetAs()); 45 | // GetPredicate() 获取测试元组的谓词(判断是否存在满足某种条件的记录,存在返回TRUE、不存在返回FALSE),SQL eg: 46 | // LIKE,IN,NOT NULL,EXISTS.. 47 | // Evaluate() 通过使用给定schema计算tuple而获得值,即判断raw_tuple是否满足table_info_指出的模式 48 | 49 | // lock on to-read RID 50 | // ... 51 | // ... 52 | 53 | // 生成输出tuple 54 | /** 55 | * @brief Value是一个抽象类,表示存储在中的SQL数据的视图 56 | * 一些物质化状态。所有Value都有一个类型和比较函数, 57 | * 但子类实现其他特定于类型的功能。 58 | */ 59 | std::vector values; 60 | 61 | std::transform(plan_->OutputSchema()->GetColumns().begin(), 62 | plan_->OutputSchema()->GetColumns().end(), // range 63 | std::back_inserter(values), // tranform storager 64 | [&raw_tuple, &table_info = table_info_](const Column &col) { 65 | // 返回通过使用给定schema计算tuple而获得的value 66 | return col.GetExpr()->Evaluate(&raw_tuple, &(table_info->schema_)); 67 | }); 68 | *tuple = Tuple{values, plan_->OutputSchema()}; 69 | *rid = raw_tuple.GetRid(); 70 | 71 | return true; 72 | } 73 | 74 | } // namespace bustub 75 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/execution/update_executor.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // update_executor.cpp 6 | // 7 | // Identification: src/execution/update_executor.cpp 8 | // 9 | // Copyright (c) 2015-20, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | #include "execution/executors/update_executor.h" 13 | 14 | #include 15 | #include 16 | 17 | namespace bustub { 18 | 19 | // lab3 task2 modify 20 | UpdateExecutor::UpdateExecutor(ExecutorContext *exec_ctx, const UpdatePlanNode *plan, 21 | std::unique_ptr &&child_executor) 22 | : AbstractExecutor(exec_ctx), plan_{plan}, child_executor_{std::move(child_executor)} { 23 | table_info_ = exec_ctx->GetCatalog()->GetTable(plan_->TableOid()); 24 | } 25 | 26 | // lab3 task2 modify 27 | void UpdateExecutor::Init() { 28 | child_executor_->Init(); 29 | 30 | table_indexes = exec_ctx_->GetCatalog()->GetTableIndexes(table_info_->name_); 31 | } 32 | 33 | // lab3 task2 modify 34 | bool UpdateExecutor::Next([[maybe_unused]] Tuple *tuple, RID *rid) { 35 | Tuple dummy_tuple; 36 | RID emit_rid; 37 | 38 | if (!child_executor_->Next(&dummy_tuple, &emit_rid)) { 39 | return false; 40 | } 41 | 42 | Tuple to_update_tuple; 43 | bool fetched = table_info_->table_->GetTuple(emit_rid, &to_update_tuple, exec_ctx_->GetTransaction()); 44 | 45 | if (!fetched) { 46 | return false; 47 | } 48 | 49 | // 给定一个旧tuple,根据plan中给定的updateinfo创建一个新的更新tuple 50 | Tuple updated_tuple = GenerateUpdatedTuple(to_update_tuple); 51 | 52 | // lcok on to-update RID 53 | // ... 54 | // ... 55 | 56 | bool updated = table_info_->table_->UpdateTuple(updated_tuple, emit_rid, exec_ctx_->GetTransaction()); 57 | 58 | if (updated) { 59 | std::for_each(table_indexes.begin(), table_indexes.end(), 60 | [&to_update_tuple, &updated_tuple, &emit_rid, &table_info = table_info_, 61 | exec_ctx = exec_ctx_](IndexInfo *index) { 62 | index->index_->DeleteEntry(to_update_tuple.KeyFromTuple(table_info->schema_, index->key_schema_, 63 | index->index_->GetKeyAttrs()), 64 | emit_rid, exec_ctx->GetTransaction()); 65 | index->index_->InsertEntry(updated_tuple.KeyFromTuple(table_info->schema_, index->key_schema_, 66 | index->index_->GetKeyAttrs()), 67 | emit_rid, exec_ctx->GetTransaction()); 68 | exec_ctx->GetTransaction()->GetIndexWriteSet()->emplace_back( 69 | emit_rid, table_info->oid_, WType::UPDATE, updated_tuple, to_update_tuple, index->index_oid_, 70 | exec_ctx->GetCatalog()); 71 | }); 72 | } 73 | 74 | return updated; 75 | } 76 | } // namespace bustub 77 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/buffer/buffer_pool_manager.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // buffer_pool_manager.h 6 | // 7 | // Identification: src/include/buffer/buffer_pool_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 18 | 19 | #include "buffer/lru_replacer.h" 20 | #include "recovery/log_manager.h" 21 | #include "storage/disk/disk_manager.h" 22 | #include "storage/page/page.h" 23 | 24 | namespace bustub { 25 | 26 | /** 27 | * BufferPoolManager reads disk pages to and from its internal buffer pool. 28 | */ 29 | class BufferPoolManager { 30 | public: 31 | enum class CallbackType { BEFORE, AFTER }; 32 | using bufferpool_callback_fn = void (*)(enum CallbackType, const page_id_t page_id); 33 | 34 | /** 35 | * Creates a new BufferPoolManager. 36 | * @param pool_size the size of the buffer pool 37 | * @param disk_manager the disk manager 38 | * @param log_manager the log manager (for testing only: nullptr = disable logging) 39 | */ 40 | BufferPoolManager(size_t pool_size, DiskManager *disk_manager, LogManager *log_manager = nullptr); 41 | 42 | /** 43 | * Destroys an existing BufferPoolManager. 44 | */ 45 | ~BufferPoolManager(); 46 | 47 | /** Grading function. Do not modify! */ 48 | Page *FetchPage(page_id_t page_id, bufferpool_callback_fn callback = nullptr) { 49 | GradingCallback(callback, CallbackType::BEFORE, page_id); 50 | auto *result = FetchPageImpl(page_id); 51 | GradingCallback(callback, CallbackType::AFTER, page_id); 52 | return result; 53 | } 54 | 55 | /** Grading function. Do not modify! */ 56 | bool UnpinPage(page_id_t page_id, bool is_dirty, bufferpool_callback_fn callback = nullptr) { 57 | GradingCallback(callback, CallbackType::BEFORE, page_id); 58 | auto result = UnpinPageImpl(page_id, is_dirty); 59 | GradingCallback(callback, CallbackType::AFTER, page_id); 60 | return result; 61 | } 62 | 63 | /** Grading function. Do not modify! */ 64 | bool FlushPage(page_id_t page_id, bufferpool_callback_fn callback = nullptr) { 65 | GradingCallback(callback, CallbackType::BEFORE, page_id); 66 | auto result = FlushPageImpl(page_id); 67 | GradingCallback(callback, CallbackType::AFTER, page_id); 68 | return result; 69 | } 70 | 71 | /** Grading function. Do not modify! */ 72 | Page *NewPage(page_id_t *page_id, bufferpool_callback_fn callback = nullptr) { 73 | GradingCallback(callback, CallbackType::BEFORE, INVALID_PAGE_ID); 74 | auto *result = NewPageImpl(page_id); 75 | GradingCallback(callback, CallbackType::AFTER, *page_id); 76 | return result; 77 | } 78 | 79 | /** Grading function. Do not modify! */ 80 | bool DeletePage(page_id_t page_id, bufferpool_callback_fn callback = nullptr) { 81 | GradingCallback(callback, CallbackType::BEFORE, page_id); 82 | auto result = DeletePageImpl(page_id); 83 | GradingCallback(callback, CallbackType::AFTER, page_id); 84 | return result; 85 | } 86 | 87 | /** Grading function. Do not modify! */ 88 | void FlushAllPages(bufferpool_callback_fn callback = nullptr) { 89 | GradingCallback(callback, CallbackType::BEFORE, INVALID_PAGE_ID); 90 | FlushAllPagesImpl(); 91 | GradingCallback(callback, CallbackType::AFTER, INVALID_PAGE_ID); 92 | } 93 | 94 | /** @return pointer to all the pages in the buffer pool */ 95 | Page *GetPages() { return pages_; } 96 | 97 | /** @return size of the buffer pool */ 98 | size_t GetPoolSize() { return pool_size_; } 99 | 100 | protected: 101 | /** 102 | * Grading function. Do not modify! 103 | * Invokes the callback function if it is not null. 104 | * @param callback callback function to be invoked 105 | * @param callback_type BEFORE or AFTER 106 | * @param page_id the page id to invoke the callback with 107 | */ 108 | void GradingCallback(bufferpool_callback_fn callback, CallbackType callback_type, page_id_t page_id) { 109 | if (callback != nullptr) { 110 | callback(callback_type, page_id); 111 | } 112 | } 113 | 114 | /** 115 | * Fetch the requested page from the buffer pool. 116 | * @param page_id id of page to be fetched 117 | * @return the requested page 118 | */ 119 | Page *FetchPageImpl(page_id_t page_id); 120 | 121 | /** 122 | * Unpin the target page from the buffer pool. 123 | * @param page_id id of page to be unpinned 124 | * @param is_dirty true if the page should be marked as dirty, false otherwise 125 | * @return false if the page pin count is <= 0 before this call, true otherwise 126 | */ 127 | bool UnpinPageImpl(page_id_t page_id, bool is_dirty); 128 | 129 | /** 130 | * Flushes the target page to disk. 131 | * @param page_id id of page to be flushed, cannot be INVALID_PAGE_ID 132 | * @return false if the page could not be found in the page table, true otherwise 133 | */ 134 | bool FlushPageImpl(page_id_t page_id); 135 | 136 | /** 137 | * Creates a new page in the buffer pool. 138 | * @param[out] page_id id of created page 139 | * @return nullptr if no new pages could be created, otherwise pointer to new page 140 | */ 141 | Page *NewPageImpl(page_id_t *page_id); 142 | 143 | /** 144 | * Deletes a page from the buffer pool. 145 | * @param page_id id of page to be deleted 146 | * @return false if the page exists but could not be deleted, true if the page didn't exist or 147 | * deletion succeeded 148 | */ 149 | bool DeletePageImpl(page_id_t page_id); 150 | 151 | /** 152 | * Flushes all the pages in the buffer pool to disk. 153 | */ 154 | void FlushAllPagesImpl(); 155 | 156 | /** Number of pages in the buffer pool. */ 157 | size_t pool_size_; 158 | /** Array of buffer pool pages. */ 159 | Page *pages_; 160 | /** Pointer to the disk manager. */ 161 | DiskManager *disk_manager_ __attribute__((__unused__)); 162 | /** Pointer to the log manager. */ 163 | LogManager *log_manager_ __attribute__((__unused__)); 164 | /** Page table for keeping track of buffer pool pages. */ 165 | std::unordered_map page_table_; 166 | /** Replacer to find unpinned pages for replacement. */ 167 | Replacer *replacer_; 168 | /** List of free pages. */ 169 | std::list free_list_; 170 | /** 171 | * This latch protects shared data structures. 172 | * We recommend updating this comment to describe what it protects. 173 | * 174 | * latch protects: 175 | * - page_table_ 176 | * - free_list_ 177 | */ 178 | std::mutex latch_; 179 | }; 180 | } // namespace bustub 181 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/buffer/lru_replacer.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // lru_replacer.h 6 | // 7 | // Identification: src/include/buffer/lru_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 | * LRUReplacer implements the lru replacement policy, which approximates the Least Recently Used 26 | * policy. 27 | */ 28 | class LRUReplacer : public Replacer { 29 | using mutex_t = std::mutex; 30 | 31 | public: 32 | /** 33 | * Create a new LRUReplacer. 34 | * @param num_pages the maximum number of pages the LRUReplacer will be required to store 35 | */ 36 | explicit LRUReplacer(size_t num_pages); 37 | 38 | /** 39 | * Destroys the LRUReplacer. 40 | */ 41 | ~LRUReplacer() override; 42 | 43 | bool Victim(frame_id_t *frame_id) override; 44 | 45 | void Pin(frame_id_t frame_id) override; 46 | 47 | void Unpin(frame_id_t frame_id) override; 48 | 49 | size_t Size() override; 50 | 51 | private: 52 | // TODO(student): implement me! 53 | // concurrent mutex 54 | mutex_t mutex; 55 | // 56 | size_t capacity; 57 | // 58 | std::list lru_list; 59 | // LRU可淘汰帧id为键,lru_list中指向对应frame_id_t的迭代器为值的unordered_map 60 | std::unordered_map::iterator> lru_map; 61 | }; 62 | 63 | } // namespace bustub 64 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/execution/execution_engine.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // execution_engine.h 6 | // 7 | // Identification: src/include/execution/execution_engine.h 8 | // 9 | // Copyright (c) 2015-2019, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | 17 | #include "buffer/buffer_pool_manager.h" 18 | #include "catalog/catalog.h" 19 | #include "concurrency/transaction_manager.h" 20 | #include "execution/executor_context.h" 21 | #include "execution/executor_factory.h" 22 | #include "execution/plans/abstract_plan.h" 23 | #include "storage/table/tuple.h" 24 | 25 | namespace bustub { 26 | class ExecutionEngine { 27 | public: 28 | ExecutionEngine(BufferPoolManager *bpm, TransactionManager *txn_mgr, Catalog *catalog) 29 | : bpm_(bpm), txn_mgr_(txn_mgr), catalog_(catalog) {} 30 | 31 | DISALLOW_COPY_AND_MOVE(ExecutionEngine); 32 | 33 | bool Execute(const AbstractPlanNode *plan, std::vector *result_set, Transaction *txn, 34 | ExecutorContext *exec_ctx) { 35 | // construct executor 36 | auto executor = ExecutorFactory::CreateExecutor(exec_ctx, plan); 37 | 38 | // prepare 39 | executor->Init(); 40 | 41 | // insert / update / delete execution should not add result to result set 42 | auto should_ignore_result_set = plan->GetType() == PlanType::Insert || plan->GetType() == PlanType::Update || 43 | plan->GetType() == PlanType::Delete; 44 | 45 | // execute 46 | try { 47 | Tuple tuple; 48 | RID rid; 49 | while (executor->Next(&tuple, &rid)) { 50 | if (result_set != nullptr) { 51 | result_set->push_back(tuple); 52 | } 53 | } 54 | } catch (TransactionAbortException &e) { 55 | txn_mgr_->Abort(txn); 56 | return false; 57 | } catch (Exception &e) { 58 | // TODO(student): handle exceptions 59 | txn_mgr_->Abort(txn); 60 | return false; 61 | } 62 | 63 | return true; 64 | } 65 | 66 | private: 67 | [[maybe_unused]] BufferPoolManager *bpm_; 68 | [[maybe_unused]] TransactionManager *txn_mgr_; 69 | [[maybe_unused]] Catalog *catalog_; 70 | }; 71 | 72 | } // namespace bustub 73 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/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 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/execution/executors/aggregation_executor.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // aggregation_executor.h 6 | // 7 | // Identification: src/include/execution/executors/aggregation_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 | #include 18 | #include 19 | 20 | #include "common/util/hash_util.h" 21 | #include "container/hash/hash_function.h" 22 | #include "execution/executor_context.h" 23 | #include "execution/executors/abstract_executor.h" 24 | #include "execution/expressions/abstract_expression.h" 25 | #include "execution/plans/aggregation_plan.h" 26 | #include "storage/table/tuple.h" 27 | #include "type/value_factory.h" 28 | 29 | namespace bustub { 30 | /** 31 | * A simplified hash table that has all the necessary functionality for aggregations. 32 | */ 33 | class SimpleAggregationHashTable { 34 | public: 35 | /** 36 | * Create a new simplified aggregation hash table. 37 | * @param agg_exprs the aggregation expressions 38 | * @param agg_types the types of aggregations 39 | */ 40 | SimpleAggregationHashTable(const std::vector &agg_exprs, 41 | const std::vector &agg_types) 42 | : agg_exprs_{agg_exprs}, agg_types_{agg_types} {} 43 | 44 | /** @return the initial aggregrate value for this aggregation executor */ 45 | AggregateValue GenerateInitialAggregateValue() { 46 | std::vector values; 47 | for (const auto &agg_type : agg_types_) { 48 | switch (agg_type) { 49 | case AggregationType::CountAggregate: 50 | // Count starts at zero. 51 | values.emplace_back(ValueFactory::GetIntegerValue(0)); 52 | break; 53 | case AggregationType::SumAggregate: 54 | // Sum starts at zero. 55 | values.emplace_back(ValueFactory::GetIntegerValue(0)); 56 | break; 57 | case AggregationType::MinAggregate: 58 | // Min starts at INT_MAX. 59 | values.emplace_back(ValueFactory::GetIntegerValue(BUSTUB_INT32_MAX)); 60 | break; 61 | case AggregationType::MaxAggregate: 62 | // Max starts at INT_MIN. 63 | values.emplace_back(ValueFactory::GetIntegerValue(BUSTUB_INT32_MIN)); 64 | break; 65 | } 66 | } 67 | return {values}; 68 | } 69 | 70 | /** Combines the input into the aggregation result. */ 71 | void CombineAggregateValues(AggregateValue *result, const AggregateValue &input) { 72 | for (uint32_t i = 0; i < agg_exprs_.size(); i++) { 73 | switch (agg_types_[i]) { 74 | case AggregationType::CountAggregate: 75 | // Count increases by one. 76 | result->aggregates_[i] = result->aggregates_[i].Add(ValueFactory::GetIntegerValue(1)); 77 | break; 78 | case AggregationType::SumAggregate: 79 | // Sum increases by addition. 80 | result->aggregates_[i] = result->aggregates_[i].Add(input.aggregates_[i]); 81 | break; 82 | case AggregationType::MinAggregate: 83 | // Min is just the min. 84 | result->aggregates_[i] = result->aggregates_[i].Min(input.aggregates_[i]); 85 | break; 86 | case AggregationType::MaxAggregate: 87 | // Max is just the max. 88 | result->aggregates_[i] = result->aggregates_[i].Max(input.aggregates_[i]); 89 | break; 90 | } 91 | } 92 | } 93 | 94 | /** 95 | * Inserts a value into the hash table and then combines it with the current aggregation. 96 | * @param agg_key the key to be inserted 97 | * @param agg_val the value to be inserted 98 | */ 99 | void InsertCombine(const AggregateKey &agg_key, const AggregateValue &agg_val) { 100 | if (ht.count(agg_key) == 0) { 101 | ht.insert({agg_key, GenerateInitialAggregateValue()}); 102 | } 103 | CombineAggregateValues(&ht[agg_key], agg_val); 104 | } 105 | 106 | /** 107 | * An iterator through the simplified aggregation hash table. 108 | */ 109 | class Iterator { 110 | public: 111 | /** Creates an iterator for the aggregate map. */ 112 | explicit Iterator(std::unordered_map::const_iterator iter) : iter_(iter) {} 113 | 114 | /** @return the key of the iterator */ 115 | const AggregateKey &Key() { return iter_->first; } 116 | 117 | /** @return the value of the iterator */ 118 | const AggregateValue &Val() { return iter_->second; } 119 | 120 | /** @return the iterator before it is incremented */ 121 | Iterator &operator++() { 122 | ++iter_; 123 | return *this; 124 | } 125 | 126 | /** @return true if both iterators are identical */ 127 | bool operator==(const Iterator &other) { return this->iter_ == other.iter_; } 128 | 129 | /** @return true if both iterators are different */ 130 | bool operator!=(const Iterator &other) { return this->iter_ != other.iter_; } 131 | 132 | private: 133 | /** Aggregates map. */ 134 | std::unordered_map::const_iterator iter_; 135 | }; 136 | 137 | /** @return iterator to the start of the hash table */ 138 | Iterator Begin() { return Iterator{ht.cbegin()}; } 139 | 140 | /** @return iterator to the end of the hash table */ 141 | Iterator End() { return Iterator{ht.cend()}; } 142 | 143 | private: 144 | /** The hash table is just a map from aggregate keys to aggregate values. */ 145 | std::unordered_map ht{}; 146 | /** The aggregate expressions that we have. */ 147 | const std::vector &agg_exprs_; 148 | /** The types of aggregations that we have. */ 149 | const std::vector &agg_types_; 150 | }; 151 | 152 | /** 153 | * AggregationExecutor executes an aggregation operation (e.g. COUNT, SUM, MIN, MAX) on the tuples of a child executor. 154 | */ 155 | class AggregationExecutor : public AbstractExecutor { 156 | public: 157 | /** 158 | * Creates a new aggregation executor. 159 | * @param exec_ctx the context that the aggregation should be performed in 160 | * @param plan the aggregation plan node 161 | * @param child the child executor 162 | */ 163 | AggregationExecutor(ExecutorContext *exec_ctx, const AggregationPlanNode *plan, 164 | std::unique_ptr &&child); 165 | 166 | /** Do not use or remove this function, otherwise you will get zero points. */ 167 | const AbstractExecutor *GetChildExecutor() const; 168 | 169 | const Schema *GetOutputSchema() override { return plan_->OutputSchema(); }; 170 | 171 | void Init() override; 172 | 173 | bool Next(Tuple *tuple, RID *rid) override; 174 | 175 | /** @return the tuple as an AggregateKey */ 176 | AggregateKey MakeKey(const Tuple *tuple) { 177 | std::vector keys; 178 | for (const auto &expr : plan_->GetGroupBys()) { 179 | keys.emplace_back(expr->Evaluate(tuple, child_->GetOutputSchema())); 180 | } 181 | return {keys}; 182 | } 183 | 184 | /** @return the tuple as an AggregateValue */ 185 | AggregateValue MakeVal(const Tuple *tuple) { 186 | std::vector vals; 187 | for (const auto &expr : plan_->GetAggregates()) { 188 | vals.emplace_back(expr->Evaluate(tuple, child_->GetOutputSchema())); 189 | } 190 | return {vals}; 191 | } 192 | 193 | private: 194 | /** The aggregation plan node. */ 195 | const AggregationPlanNode *plan_; 196 | /** The child executor whose tuples we are aggregating. */ 197 | std::unique_ptr child_; 198 | /** Simple aggregation hash table. */ 199 | // Uncomment me! SimpleAggregationHashTable aht_; 200 | SimpleAggregationHashTable aht_; 201 | /** Simple aggregation hash table iterator. */ 202 | // Uncomment me! SimpleAggregationHashTable::Iterator aht_iterator_; 203 | SimpleAggregationHashTable::Iterator aht_iterator_; 204 | }; 205 | } // namespace bustub 206 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/execution/executors/delete_executor.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // delete_executor.h 6 | // 7 | // Identification: src/include/execution/executors/delete_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 | #include 18 | 19 | #include "execution/executor_context.h" 20 | #include "execution/executors/abstract_executor.h" 21 | #include "execution/plans/delete_plan.h" 22 | #include "storage/table/tuple.h" 23 | 24 | namespace bustub { 25 | /** 26 | * Delete executes a delete from a table. 27 | * Deleted tuple info come from a child executor. 28 | */ 29 | class DeleteExecutor : public AbstractExecutor { 30 | public: 31 | /** 32 | * Creates a new delete executor. 33 | * @param exec_ctx the executor context 34 | * @param plan the delete plan to be executed 35 | * @param child_executor the child executor (either sequential scan or index scan) to obtain tuple info 36 | */ 37 | DeleteExecutor(ExecutorContext *exec_ctx, const DeletePlanNode *plan, 38 | std::unique_ptr &&child_executor); 39 | 40 | const Schema *GetOutputSchema() override { return plan_->OutputSchema(); }; 41 | 42 | void Init() override; 43 | 44 | // Note that Delete does not make use of the tuple pointer being passed in. 45 | // We throw exception if the delete failed for any reason, and return false if all delete succeeded. 46 | // Delete from indexes if necessary. 47 | bool Next([[maybe_unused]] Tuple *tuple, RID *rid) override; 48 | 49 | private: 50 | /** The delete plan node to be executed. */ 51 | const DeletePlanNode *plan_; 52 | /** The child executor to obtain rid from. */ 53 | std::unique_ptr child_executor_; 54 | 55 | // lab3 tesk2 add 56 | std::vector table_indexes; 57 | /** Metadata identifying the table that should be deleted. */ 58 | const TableMetadata *table_info_; 59 | }; 60 | } // namespace bustub 61 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/execution/executors/index_scan_executor.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // index_scan_executor.h 6 | // 7 | // Identification: src/include/execution/executors/index_scan_executor.h 8 | // 9 | // Copyright (c) 2015-20, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | 18 | #include "common/rid.h" 19 | #include "execution/executor_context.h" 20 | #include "execution/executors/abstract_executor.h" 21 | #include "execution/plans/index_scan_plan.h" 22 | #include "storage/index/index_iterator.h" 23 | #include "storage/table/tuple.h" 24 | 25 | namespace bustub { 26 | 27 | /** 28 | * IndexScanExecutor executes an index scan over a table. 29 | */ 30 | 31 | class IndexScanExecutor : public AbstractExecutor { 32 | using KeyType = GenericKey<8>; 33 | using ValueType = RID; 34 | using KeyComparator = GenericComparator<8>; 35 | 36 | public: 37 | /** 38 | * Creates a new index scan executor. 39 | * @param exec_ctx the executor context 40 | * @param plan the index scan plan to be executed 41 | */ 42 | IndexScanExecutor(ExecutorContext *exec_ctx, const IndexScanPlanNode *plan); 43 | 44 | const Schema *GetOutputSchema() override { return plan_->OutputSchema(); }; 45 | 46 | void Init() override; 47 | 48 | bool Next(Tuple *tuple, RID *rid) override; 49 | 50 | private: 51 | /** The index scan plan node to be executed. */ 52 | const IndexScanPlanNode *plan_; 53 | // lab3 task2 add 54 | /** 标识了应扫描的表的元数据 **/ 55 | const TableMetadata *table_info_; 56 | /** 标识了要扫描的索引的索引信息 **/ 57 | const IndexInfo *index_info_; 58 | 59 | std::unique_ptr index_iter{nullptr}; 60 | 61 | BPlusTreeIndex *GetBPlusTreeIndex() { 62 | return dynamic_cast *>(index_info_->index_.get()); 63 | } 64 | }; 65 | } // namespace bustub 66 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/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 | #include 18 | 19 | #include "execution/executor_context.h" 20 | #include "execution/executors/abstract_executor.h" 21 | #include "execution/plans/insert_plan.h" 22 | #include "storage/table/tuple.h" 23 | 24 | namespace bustub { 25 | /** 26 | * InsertExecutor executes an insert into a table. 27 | * Inserted values can either be embedded in the plan itself ("raw insert") or come from a child executor. 28 | */ 29 | class InsertExecutor : public AbstractExecutor { 30 | public: 31 | /** 32 | * Creates a new insert executor. 33 | * @param exec_ctx the executor context 34 | * @param plan the insert plan to be executed 35 | * @param child_executor the child executor to obtain insert values from, can be nullptr 36 | */ 37 | InsertExecutor(ExecutorContext *exec_ctx, const InsertPlanNode *plan, 38 | std::unique_ptr &&child_executor); 39 | 40 | const Schema *GetOutputSchema() override { return plan_->OutputSchema(); }; 41 | 42 | void Init() override; 43 | 44 | // Note that Insert does not make use of the tuple pointer being passed in. 45 | // We return false if the insert failed for any reason, and return true if all inserts succeeded. 46 | bool Next([[maybe_unused]] Tuple *tuple, RID *rid) override; 47 | 48 | private: 49 | /** The insert plan node to be executed. */ 50 | const InsertPlanNode *plan_; 51 | // lab3 task2 add 52 | /** 标识了应插入的表的元数据 **/ 53 | const TableMetadata *table_info_; 54 | 55 | size_t next_insert{0}; 56 | std::unique_ptr child_executor_; 57 | std::vector table_indexes; 58 | }; 59 | } // namespace bustub 60 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/execution/executors/limit_executor.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // limit_executor.h 6 | // 7 | // Identification: src/include/execution/executors/limit_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/executors/abstract_executor.h" 19 | #include "execution/plans/limit_plan.h" 20 | 21 | namespace bustub { 22 | /** 23 | * LimitExecutor limits the number of output tuples with an optional offset. 24 | */ 25 | class LimitExecutor : public AbstractExecutor { 26 | public: 27 | /** 28 | * Creates a new limit executor. 29 | * @param exec_ctx the executor context 30 | * @param plan the limit plan to be executed 31 | * @param child_executor the child executor that produces tuple 32 | */ 33 | LimitExecutor(ExecutorContext *exec_ctx, const LimitPlanNode *plan, 34 | std::unique_ptr &&child_executor); 35 | 36 | const Schema *GetOutputSchema() override { return plan_->OutputSchema(); }; 37 | 38 | void Init() override; 39 | 40 | bool Next(Tuple *tuple, RID *rid) override; 41 | 42 | private: 43 | /** The limit plan node to be executed. */ 44 | const LimitPlanNode *plan_; 45 | /** The child executor to obtain value from. */ 46 | std::unique_ptr child_executor_; 47 | 48 | // lab3 task2 add 49 | uint32_t skipped{0}; 50 | uint32_t emitted{0}; 51 | }; 52 | } // namespace bustub 53 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/execution/executors/nested_index_join_executor.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // nested_index_join_executor.h 6 | // 7 | // Identification: src/include/execution/executors/nested_index_join_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 | #include 18 | #include 19 | #include 20 | 21 | #include "common/rid.h" 22 | #include "execution/executor_context.h" 23 | #include "execution/executors/abstract_executor.h" 24 | #include "execution/expressions/abstract_expression.h" 25 | #include "execution/plans/nested_index_join_plan.h" 26 | #include "storage/table/tmp_tuple.h" 27 | #include "storage/table/tuple.h" 28 | 29 | namespace bustub { 30 | 31 | /** 32 | * IndexJoinExecutor executes index join operations. 33 | */ 34 | class NestIndexJoinExecutor : public AbstractExecutor { 35 | using KeyType = GenericKey<8>; 36 | using ValueType = RID; 37 | using KeyComparator = GenericComparator<8>; 38 | 39 | public: 40 | /** 41 | * Creates a new nested index join executor. 42 | * @param exec_ctx the context that the hash join should be performed in 43 | * @param plan the nested index join plan node 44 | * @param outer table child 45 | */ 46 | NestIndexJoinExecutor(ExecutorContext *exec_ctx, const NestedIndexJoinPlanNode *plan, 47 | std::unique_ptr &&child_executor); 48 | 49 | const Schema *GetOutputSchema() override { return plan_->OutputSchema(); } 50 | 51 | void Init() override; 52 | 53 | bool Next(Tuple *tuple, RID *rid) override; 54 | 55 | private: 56 | /** The nested index join plan node. */ 57 | const NestedIndexJoinPlanNode *plan_; 58 | 59 | // lab3 task2 add 60 | /** Metadata identifying the inner table that should be fetched. */ 61 | const TableMetadata *inner_table_info_; 62 | /** Index info identifying the index of the inner table to be probed */ 63 | /** 标识了要探测的innerTable的索引 的索引信息 */ 64 | const IndexInfo *inner_index_info_; 65 | 66 | std::unique_ptr child_executor_; 67 | 68 | BPlusTreeIndex *GetBPlusTreeIndex() { 69 | return dynamic_cast *>(inner_index_info_->index_.get()); 70 | } 71 | 72 | bool Probe(Tuple *left_tuple, Tuple *right_raw_tuple); 73 | }; 74 | } // namespace bustub 75 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/execution/executors/nested_loop_join_executor.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // nested_loop_join_executor.h 6 | // 7 | // Identification: src/include/execution/executors/nested_loop_join_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 | #include 18 | 19 | #include "execution/executor_context.h" 20 | #include "execution/executors/abstract_executor.h" 21 | #include "execution/plans/nested_loop_join_plan.h" 22 | #include "storage/table/tuple.h" 23 | 24 | namespace bustub { 25 | /** 26 | * NestedLoopJoinExecutor joins two tables using nested loop. 27 | * The child executor can either be a sequential scan 28 | */ 29 | class NestedLoopJoinExecutor : public AbstractExecutor { 30 | public: 31 | /** 32 | * Creates a new NestedLoop join executor. 33 | * @param exec_ctx the executor context 34 | * @param plan the NestedLoop join plan to be executed 35 | * @param left_executor the child executor that produces tuple for the left side of join 36 | * @param right_executor the child executor that produces tuple for the right side of join 37 | * 38 | */ 39 | NestedLoopJoinExecutor(ExecutorContext *exec_ctx, const NestedLoopJoinPlanNode *plan, 40 | std::unique_ptr &&left_executor, 41 | std::unique_ptr &&right_executor); 42 | 43 | const Schema *GetOutputSchema() override { return plan_->OutputSchema(); }; 44 | 45 | void Init() override; 46 | 47 | bool Next(Tuple *tuple, RID *rid) override; 48 | 49 | private: 50 | /** The NestedLoop plan node to be executed. */ 51 | const NestedLoopJoinPlanNode *plan_; 52 | 53 | // lab3 tesk2 add 54 | std::unique_ptr left_executor_; 55 | std::unique_ptr right_executor_; 56 | bool Advance(RID *left_rid, Tuple *right_tuple, RID *right_rid); 57 | 58 | Tuple left_tuple{}; 59 | }; 60 | } // namespace bustub 61 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/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 | #include 17 | 18 | #include "execution/executor_context.h" 19 | #include "execution/executors/abstract_executor.h" 20 | #include "execution/plans/seq_scan_plan.h" 21 | #include "storage/table/table_iterator.h" 22 | #include "storage/table/tuple.h" 23 | 24 | namespace bustub { 25 | 26 | /** 27 | * SeqScanExecutor executes a sequential scan over a table. 28 | */ 29 | class SeqScanExecutor : public AbstractExecutor { 30 | public: 31 | /** 32 | * Creates a new sequential scan executor. 33 | * @param exec_ctx the executor context 34 | * @param plan the sequential scan plan to be executed 35 | */ 36 | SeqScanExecutor(ExecutorContext *exec_ctx, const SeqScanPlanNode *plan); 37 | 38 | void Init() override; 39 | 40 | bool Next(Tuple *tuple, RID *rid) override; 41 | 42 | const Schema *GetOutputSchema() override { return plan_->OutputSchema(); } 43 | 44 | private: 45 | /** The sequential scan plan node to be executed. */ 46 | const SeqScanPlanNode *plan_; 47 | // lab3 task2 add 48 | /** 标识了应扫描的表的元数据 **/ 49 | const TableMetadata *table_info_; 50 | /** 表迭代器,TableIterator支持对表堆进行顺序扫描 **/ 51 | std::unique_ptr table_iter{nullptr}; 52 | }; 53 | } // namespace bustub 54 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/execution/executors/update_executor.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // update_executor.h 6 | // 7 | // Identification: src/include/execution/executors/update_executor.h 8 | // 9 | // Copyright (c) 2015-20, Carnegie Mellon University Database Group 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #pragma once 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "execution/executor_context.h" 20 | #include "execution/executors/abstract_executor.h" 21 | #include "execution/plans/update_plan.h" 22 | #include "storage/table/tuple.h" 23 | #include "type/value_factory.h" 24 | 25 | namespace bustub { 26 | 27 | /** 28 | * UpdateExecutor executes an update in a table. 29 | * Updated values from a child executor. 30 | */ 31 | class UpdateExecutor : public AbstractExecutor { 32 | friend class UpdatePlanNode; 33 | 34 | public: 35 | /** 36 | * Creates a new update executor. 37 | * @param exec_ctx the executor context 38 | * @param plan the update plan to be executed 39 | */ 40 | UpdateExecutor(ExecutorContext *exec_ctx, const UpdatePlanNode *plan, 41 | std::unique_ptr &&child_executor); 42 | 43 | const Schema *GetOutputSchema() override { return plan_->OutputSchema(); }; 44 | 45 | void Init() override; 46 | 47 | bool Next([[maybe_unused]] Tuple *tuple, RID *rid) override; 48 | 49 | /* 50 | * Given an old tuple, creates a new updated tuple based on the updateinfo given in the plan 51 | * @param old_tup the tuple to be updated 52 | */ 53 | Tuple GenerateUpdatedTuple(const Tuple &old_tup) { 54 | auto update_attrs = plan_->GetUpdateAttr(); 55 | Schema schema = table_info_->schema_; 56 | uint32_t col_count = schema.GetColumnCount(); 57 | std::vector values; 58 | for (uint32_t idx = 0; idx < col_count; idx++) { 59 | if (update_attrs->find(idx) == update_attrs->end()) { 60 | values.emplace_back(old_tup.GetValue(&schema, idx)); 61 | } else { 62 | UpdateInfo info = update_attrs->at(idx); 63 | Value val = old_tup.GetValue(&schema, idx); 64 | switch (info.type_) { 65 | case UpdateType::Add: 66 | values.emplace_back(val.Add(ValueFactory::GetIntegerValue(info.update_val_))); 67 | break; 68 | 69 | case UpdateType::Set: 70 | values.emplace_back(ValueFactory::GetIntegerValue(info.update_val_)); 71 | break; 72 | } 73 | } 74 | } 75 | return Tuple(values, &schema); 76 | } 77 | 78 | private: 79 | /** The update plan node to be executed. */ 80 | const UpdatePlanNode *plan_; 81 | /** Metadata identifying the table that should be updated. */ 82 | const TableMetadata *table_info_; 83 | /** The child executor to obtain value from. */ 84 | std::unique_ptr child_executor_; 85 | 86 | // lab3 task2 add 87 | std::vector table_indexes; 88 | }; 89 | } // namespace bustub 90 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/storage/index/b_plus_tree.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/include/index/b_plus_tree.h 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | #pragma once 12 | 13 | #include // NOLINT 14 | #include 15 | #include 16 | #include 17 | 18 | #include "concurrency/transaction.h" 19 | #include "storage/index/index_iterator.h" 20 | #include "storage/page/b_plus_tree_internal_page.h" 21 | #include "storage/page/b_plus_tree_leaf_page.h" 22 | 23 | namespace bustub { 24 | 25 | #define BPLUSTREE_TYPE BPlusTree 26 | 27 | enum class Operation { SEARCH, INSERT, DELETE }; 28 | 29 | /** 30 | * Main class providing the API for the Interactive B+ Tree. 31 | * 32 | * Implementation of simple b+ tree data structure where internal pages direct 33 | * the search and leaf pages contain actual data. 34 | * (1) We only support unique key 35 | * (2) support insert & remove 36 | * (3) The structure should shrink and grow dynamically 37 | * (4) Implement index iterator for range scan 38 | */ 39 | INDEX_TEMPLATE_ARGUMENTS 40 | class BPlusTree { 41 | using InternalPage = BPlusTreeInternalPage; 42 | using LeafPage = BPlusTreeLeafPage; 43 | 44 | public: 45 | explicit BPlusTree(std::string name, BufferPoolManager *buffer_pool_manager, const KeyComparator &comparator, 46 | int leaf_max_size = LEAF_PAGE_SIZE, int internal_max_size = INTERNAL_PAGE_SIZE); 47 | 48 | // Returns true if this B+ tree has no keys and values. 49 | bool IsEmpty() const; 50 | 51 | // Insert a key-value pair into this B+ tree. 52 | bool Insert(const KeyType &key, const ValueType &value, Transaction *transaction = nullptr); 53 | 54 | // Remove a key and its value from this B+ tree. 55 | void Remove(const KeyType &key, Transaction *transaction = nullptr); 56 | 57 | // return the value associated with a given key 58 | bool GetValue(const KeyType &key, std::vector *result, Transaction *transaction = nullptr); 59 | 60 | // index iterator 61 | INDEXITERATOR_TYPE begin(); 62 | INDEXITERATOR_TYPE Begin(const KeyType &key); 63 | INDEXITERATOR_TYPE end(); 64 | 65 | void Print(BufferPoolManager *bpm) { 66 | ToString(reinterpret_cast(bpm->FetchPage(root_page_id_)->GetData()), bpm); 67 | } 68 | 69 | void Draw(BufferPoolManager *bpm, const std::string &outf) { 70 | std::ofstream out(outf); 71 | out << "digraph G {" << std::endl; 72 | ToGraph(reinterpret_cast(bpm->FetchPage(root_page_id_)->GetData()), bpm, out); 73 | out << "}" << std::endl; 74 | out.close(); 75 | } 76 | 77 | // read data from file and insert one by one 78 | void InsertFromFile(const std::string &file_name, Transaction *transaction = nullptr); 79 | 80 | // read data from file and remove one by one 81 | void RemoveFromFile(const std::string &file_name, Transaction *transaction = nullptr); 82 | // expose for test purpose 83 | Page *FindLeafPage(const KeyType &key, bool leftMost = false); 84 | 85 | private: 86 | void StartNewTree(const KeyType &key, const ValueType &value); 87 | 88 | bool InsertIntoLeaf(const KeyType &key, const ValueType &value, Transaction *transaction = nullptr); 89 | 90 | void InsertIntoParent(BPlusTreePage *old_node, const KeyType &key, BPlusTreePage *new_node, 91 | Transaction *transaction = nullptr); 92 | 93 | template 94 | N *Split(N *node); 95 | 96 | template 97 | bool CoalesceOrRedistribute(N *node, Transaction *transaction = nullptr, bool is_root_page_id_latched = false); 98 | 99 | template 100 | bool Coalesce(N **neighbor_node, N **node, BPlusTreeInternalPage **parent, 101 | int index, Transaction *transaction = nullptr, bool is_root_page_id_latched = false); 102 | 103 | template 104 | void Redistribute(N *neighbor_node, N *node, BPlusTreeInternalPage *parent, 105 | int index, bool is_root_page_id_latched = false); 106 | 107 | bool AdjustRoot(BPlusTreePage *node, bool is_root_page_id_latched = false); 108 | 109 | void UpdateRootPageId(int insert_record = 0); 110 | 111 | /* Debug Routines for FREE!! */ 112 | void ToGraph(BPlusTreePage *page, BufferPoolManager *bpm, std::ofstream &out) const; 113 | 114 | void ToString(BPlusTreePage *page, BufferPoolManager *bpm) const; 115 | 116 | void ClearTransactionPageSetAndUnpinEach(Transaction *transaction) const; 117 | 118 | void ClearTransactionPageSet(Transaction *transaction) const; 119 | 120 | std::pair FindLeafPageByOperation(const KeyType &key, Operation operation = Operation::SEARCH, 121 | Transaction *transaction = nullptr, bool leftMost = false, 122 | bool rightMost = false); 123 | 124 | // member variable 125 | std::string index_name_; 126 | std::mutex root_page_id_latch; 127 | page_id_t root_page_id_; 128 | BufferPoolManager *buffer_pool_manager_; 129 | KeyComparator comparator_; 130 | int leaf_max_size_; 131 | int internal_max_size_; 132 | }; 133 | 134 | } // namespace bustub 135 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/storage/index/b_plus_tree_index.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/include/index/b_plus_tree_index.h 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | 12 | #pragma once 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include "storage/index/b_plus_tree.h" 19 | #include "storage/index/index.h" 20 | 21 | namespace bustub { 22 | 23 | #define BPLUSTREE_INDEX_TYPE BPlusTreeIndex 24 | 25 | INDEX_TEMPLATE_ARGUMENTS 26 | class BPlusTreeIndex : public Index { 27 | public: 28 | BPlusTreeIndex(IndexMetadata *metadata, BufferPoolManager *buffer_pool_manager); 29 | 30 | void InsertEntry(const Tuple &key, RID rid, Transaction *transaction) override; 31 | 32 | void DeleteEntry(const Tuple &key, RID rid, Transaction *transaction) override; 33 | 34 | void ScanKey(const Tuple &key, std::vector *result, Transaction *transaction) override; 35 | 36 | INDEXITERATOR_TYPE GetBeginIterator(); 37 | 38 | INDEXITERATOR_TYPE GetBeginIterator(const KeyType &key); 39 | 40 | INDEXITERATOR_TYPE GetEndIterator(); 41 | 42 | protected: 43 | // comparator for key 44 | KeyComparator comparator_; 45 | // container 46 | BPlusTree container_; 47 | }; 48 | 49 | } // namespace bustub 50 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/storage/index/index.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // BusTub 4 | // 5 | // index.h 6 | // 7 | // Identification: src/include/storage/index/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 | #include 19 | 20 | #include "catalog/schema.h" 21 | #include "storage/table/tuple.h" 22 | #include "type/value.h" 23 | 24 | namespace bustub { 25 | 26 | /** 27 | * class IndexMetadata - Holds metadata of an index object 28 | * 29 | * The metadata object maintains the tuple schema and key attribute of an 30 | * index, since the external callers does not know the actual structure of 31 | * the index key, so it is the index's responsibility to maintain such a 32 | * mapping relation and does the conversion between tuple key and index key 33 | */ 34 | class Transaction; 35 | class IndexMetadata { 36 | public: 37 | IndexMetadata() = delete; 38 | 39 | IndexMetadata(std::string index_name, std::string table_name, const Schema *tuple_schema, 40 | std::vector key_attrs) 41 | : name_(std::move(index_name)), table_name_(std::move(table_name)), key_attrs_(std::move(key_attrs)) { 42 | key_schema_ = Schema::CopySchema(tuple_schema, key_attrs_); 43 | } 44 | 45 | ~IndexMetadata() { delete key_schema_; } 46 | 47 | inline const std::string &GetName() const { return name_; } 48 | 49 | inline const std::string &GetTableName() { return table_name_; } 50 | 51 | // Returns a schema object pointer that represents the indexed key 52 | inline Schema *GetKeySchema() const { return key_schema_; } 53 | 54 | // Return the number of columns inside index key (not in tuple key) 55 | // Note that this must be defined inside the cpp source file 56 | // because it uses the member of catalog::Schema which is not known here 57 | uint32_t GetIndexColumnCount() const { return static_cast(key_attrs_.size()); } 58 | 59 | // Returns the mapping relation between indexed columns and base table 60 | // columns 61 | inline const std::vector &GetKeyAttrs() const { return key_attrs_; } 62 | 63 | // Get a string representation for debugging 64 | std::string ToString() const { 65 | std::stringstream os; 66 | 67 | os << "IndexMetadata[" 68 | << "Name = " << name_ << ", " 69 | << "Type = B+Tree, " 70 | << "Table name = " << table_name_ << "] :: "; 71 | os << key_schema_->ToString(); 72 | 73 | return os.str(); 74 | } 75 | 76 | private: 77 | std::string name_; 78 | std::string table_name_; 79 | // The mapping relation between key schema and tuple schema 80 | const std::vector key_attrs_; 81 | // schema of the indexed key 82 | Schema *key_schema_; 83 | }; 84 | 85 | ///////////////////////////////////////////////////////////////////// 86 | // Index class definition 87 | ///////////////////////////////////////////////////////////////////// 88 | 89 | /** 90 | * class Index - Base class for derived indices of different types 91 | * 92 | * The index structure majorly maintains information on the schema of the 93 | * schema of the underlying table and the mapping relation between index key 94 | * and tuple key, and provides an abstracted way for the external world to 95 | * interact with the underlying index implementation without exposing 96 | * the actual implementation's interface. 97 | * 98 | * Index object also handles predicate scan, in addition to simple insert, 99 | * delete, predicate insert, point query, and full index scan. Predicate scan 100 | * only supports conjunction, and may or may not be optimized depending on 101 | * the type of expressions inside the predicate. 102 | */ 103 | class Index { 104 | public: 105 | explicit Index(IndexMetadata *metadata) : metadata_(metadata) {} 106 | 107 | virtual ~Index() { delete metadata_; } 108 | 109 | // Return the metadata object associated with the index 110 | IndexMetadata *GetMetadata() const { return metadata_; } 111 | 112 | int GetIndexColumnCount() const { return metadata_->GetIndexColumnCount(); } 113 | 114 | const std::string &GetName() const { return metadata_->GetName(); } 115 | 116 | Schema *GetKeySchema() const { return metadata_->GetKeySchema(); } 117 | 118 | const std::vector &GetKeyAttrs() const { return metadata_->GetKeyAttrs(); } 119 | 120 | // Get a string representation for debugging 121 | std::string ToString() const { 122 | std::stringstream os; 123 | 124 | os << "INDEX: (" << GetName() << ")"; 125 | os << metadata_->ToString(); 126 | return os.str(); 127 | } 128 | 129 | /////////////////////////////////////////////////////////////////// 130 | // Point Modification 131 | /////////////////////////////////////////////////////////////////// 132 | // designed for secondary indexes. 133 | virtual void InsertEntry(const Tuple &key, RID rid, Transaction *transaction) = 0; 134 | 135 | // delete the index entry linked to given tuple 136 | virtual void DeleteEntry(const Tuple &key, RID rid, Transaction *transaction) = 0; 137 | 138 | virtual void ScanKey(const Tuple &key, std::vector *result, Transaction *transaction) = 0; 139 | 140 | private: 141 | //===--------------------------------------------------------------------===// 142 | // Data members 143 | //===--------------------------------------------------------------------===// 144 | IndexMetadata *metadata_; 145 | }; 146 | 147 | } // namespace bustub 148 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/storage/index/index_iterator.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/include/index/index_iterator.h 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | /** 12 | * index_iterator.h 13 | * For range scan of b+ tree 14 | */ 15 | #pragma once 16 | #include "buffer/buffer_pool_manager.h" 17 | #include "storage/page/b_plus_tree_leaf_page.h" 18 | #include "storage/page/page.h" 19 | 20 | namespace bustub { 21 | 22 | #define INDEXITERATOR_TYPE IndexIterator 23 | 24 | INDEX_TEMPLATE_ARGUMENTS 25 | class IndexIterator { 26 | using LeafPage = BPlusTreeLeafPage; 27 | 28 | public: 29 | // you may define your own constructor based on your member variables 30 | IndexIterator(BufferPoolManager *bpm, Page *page, int idx = 0); 31 | ~IndexIterator(); 32 | 33 | bool isEnd(); 34 | 35 | const MappingType &operator*(); 36 | 37 | IndexIterator &operator++(); 38 | 39 | bool operator==(const IndexIterator &itr) const; 40 | 41 | bool operator!=(const IndexIterator &itr) const; 42 | 43 | private: 44 | // add your own private member variables here 45 | BufferPoolManager *buffer_pool_manager_; 46 | Page *page; 47 | LeafPage *leaf = nullptr; 48 | int idx = 0; 49 | }; 50 | 51 | } // namespace bustub 52 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/storage/page/b_plus_tree_internal_page.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/include/page/b_plus_tree_internal_page.h 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | #pragma once 12 | 13 | #include 14 | 15 | #include "storage/page/b_plus_tree_page.h" 16 | 17 | namespace bustub { 18 | 19 | #define B_PLUS_TREE_INTERNAL_PAGE_TYPE BPlusTreeInternalPage 20 | #define INTERNAL_PAGE_HEADER_SIZE 24 21 | #define INTERNAL_PAGE_SIZE ((PAGE_SIZE - INTERNAL_PAGE_HEADER_SIZE) / (sizeof(MappingType))) 22 | /** 23 | * Store n indexed keys and n+1 child pointers (page_id) within internal page. 24 | * Pointer PAGE_ID(i) points to a subtree in which all keys K satisfy: 25 | * K(i) <= K < K(i+1). 26 | * NOTE: since the number of keys does not equal to number of child pointers, 27 | * the first key always remains invalid. That is to say, any search/lookup 28 | * should ignore the first key. 29 | * 30 | * Internal page format (keys are stored in increasing order): 31 | * -------------------------------------------------------------------------- 32 | * | HEADER | KEY(1)+PAGE_ID(1) | KEY(2)+PAGE_ID(2) | ... | KEY(n)+PAGE_ID(n) | 33 | * -------------------------------------------------------------------------- 34 | */ 35 | INDEX_TEMPLATE_ARGUMENTS 36 | class BPlusTreeInternalPage : public BPlusTreePage { 37 | public: 38 | // must call initialize method after "create" a new node 39 | void Init(page_id_t page_id, page_id_t parent_id = INVALID_PAGE_ID, int max_size = INTERNAL_PAGE_SIZE); 40 | 41 | KeyType KeyAt(int index) const; 42 | void SetKeyAt(int index, const KeyType &key); 43 | int ValueIndex(const ValueType &value) const; 44 | ValueType ValueAt(int index) const; 45 | 46 | ValueType Lookup(const KeyType &key, const KeyComparator &comparator) const; 47 | void PopulateNewRoot(const ValueType &old_value, const KeyType &new_key, const ValueType &new_value); 48 | int InsertNodeAfter(const ValueType &old_value, const KeyType &new_key, const ValueType &new_value); 49 | void Remove(int index); 50 | ValueType RemoveAndReturnOnlyChild(); 51 | 52 | // Split and Merge utility methods 53 | void MoveAllTo(BPlusTreeInternalPage *recipient, const KeyType &middle_key, BufferPoolManager *buffer_pool_manager); 54 | void MoveHalfTo(BPlusTreeInternalPage *recipient, BufferPoolManager *buffer_pool_manager); 55 | void MoveFirstToEndOf(BPlusTreeInternalPage *recipient, const KeyType &middle_key, 56 | BufferPoolManager *buffer_pool_manager); 57 | void MoveLastToFrontOf(BPlusTreeInternalPage *recipient, const KeyType &middle_key, 58 | BufferPoolManager *buffer_pool_manager); 59 | 60 | private: 61 | void CopyNFrom(MappingType *items, int size, BufferPoolManager *buffer_pool_manager); 62 | void CopyLastFrom(const MappingType &pair, BufferPoolManager *buffer_pool_manager); 63 | void CopyFirstFrom(const MappingType &pair, BufferPoolManager *buffer_pool_manager); 64 | MappingType array[0]; 65 | }; 66 | } // namespace bustub 67 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/storage/page/b_plus_tree_leaf_page.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/include/page/b_plus_tree_leaf_page.h 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | #pragma once 12 | 13 | #include 14 | #include 15 | 16 | #include "storage/page/b_plus_tree_page.h" 17 | 18 | namespace bustub { 19 | 20 | #define B_PLUS_TREE_LEAF_PAGE_TYPE BPlusTreeLeafPage 21 | #define LEAF_PAGE_HEADER_SIZE 28 22 | #define LEAF_PAGE_SIZE ((PAGE_SIZE - LEAF_PAGE_HEADER_SIZE) / sizeof(MappingType)) 23 | 24 | /** 25 | * Store indexed key and record id(record id = page id combined with slot id, 26 | * see include/common/rid.h for detailed implementation) together within leaf 27 | * page. Only support unique key. 28 | * 29 | * Leaf page format (keys are stored in order): 30 | * ---------------------------------------------------------------------- 31 | * | HEADER | KEY(1) + RID(1) | KEY(2) + RID(2) | ... | KEY(n) + RID(n) 32 | * ---------------------------------------------------------------------- 33 | * 34 | * Header format (size in byte, 28 bytes in total): 35 | * --------------------------------------------------------------------- 36 | * | PageType (4) | LSN (4) | CurrentSize (4) | MaxSize (4) | 37 | * --------------------------------------------------------------------- 38 | * ----------------------------------------------- 39 | * | ParentPageId (4) | PageId (4) | NextPageId (4) 40 | * ----------------------------------------------- 41 | */ 42 | INDEX_TEMPLATE_ARGUMENTS 43 | class BPlusTreeLeafPage : public BPlusTreePage { 44 | public: 45 | // After creating a new leaf page from buffer pool, must call initialize 46 | // method to set default values 47 | void Init(page_id_t page_id, page_id_t parent_id = INVALID_PAGE_ID, int max_size = LEAF_PAGE_SIZE); 48 | // helper methods 49 | page_id_t GetNextPageId() const; 50 | void SetNextPageId(page_id_t next_page_id); 51 | KeyType KeyAt(int index) const; 52 | int KeyIndex(const KeyType &key, const KeyComparator &comparator) const; 53 | const MappingType &GetItem(int index); 54 | 55 | // insert and delete methods 56 | int Insert(const KeyType &key, const ValueType &value, const KeyComparator &comparator); 57 | bool Lookup(const KeyType &key, ValueType *value, const KeyComparator &comparator) const; 58 | int RemoveAndDeleteRecord(const KeyType &key, const KeyComparator &comparator); 59 | 60 | // Split and Merge utility methods 61 | void MoveHalfTo(BPlusTreeLeafPage *recipient); 62 | void MoveAllTo(BPlusTreeLeafPage *recipient); 63 | void MoveFirstToEndOf(BPlusTreeLeafPage *recipient); 64 | void MoveLastToFrontOf(BPlusTreeLeafPage *recipient); 65 | 66 | private: 67 | void CopyNFrom(MappingType *items, int size); 68 | void CopyLastFrom(const MappingType &item); 69 | void CopyFirstFrom(const MappingType &item); 70 | page_id_t next_page_id_; 71 | MappingType array[0]; 72 | }; 73 | } // namespace bustub 74 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/include/storage/page/b_plus_tree_page.h: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/include/page/b_plus_tree_page.h 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | #pragma once 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "buffer/buffer_pool_manager.h" 19 | #include "storage/index/generic_key.h" 20 | 21 | namespace bustub { 22 | 23 | #define MappingType std::pair 24 | 25 | #define INDEX_TEMPLATE_ARGUMENTS template 26 | 27 | // define page type enum 28 | enum class IndexPageType { INVALID_INDEX_PAGE = 0, LEAF_PAGE, INTERNAL_PAGE }; 29 | 30 | /** 31 | * Both internal and leaf page are inherited from this page. 32 | * 33 | * It actually serves as a header part for each B+ tree page and 34 | * contains information shared by both leaf page and internal page. 35 | * 36 | * Header format (size in byte, 24 bytes in total): 37 | * ---------------------------------------------------------------------------- 38 | * | PageType (4) | LSN (4) | CurrentSize (4) | MaxSize (4) | 39 | * ---------------------------------------------------------------------------- 40 | * | ParentPageId (4) | PageId(4) | 41 | * ---------------------------------------------------------------------------- 42 | */ 43 | class BPlusTreePage { 44 | public: 45 | bool IsLeafPage() const; 46 | bool IsRootPage() const; 47 | void SetPageType(IndexPageType page_type); 48 | IndexPageType GetPageType() const; 49 | 50 | int GetSize() const; 51 | void SetSize(int size); 52 | void IncreaseSize(int amount); 53 | 54 | int GetMaxSize() const; 55 | void SetMaxSize(int max_size); 56 | int GetMinSize() const; 57 | 58 | page_id_t GetParentPageId() const; 59 | void SetParentPageId(page_id_t parent_page_id); 60 | 61 | page_id_t GetPageId() const; 62 | void SetPageId(page_id_t page_id); 63 | 64 | void SetLSN(lsn_t lsn = INVALID_LSN); 65 | 66 | private: 67 | // member variable, attributes that both internal and leaf page share 68 | IndexPageType page_type_ __attribute__((__unused__)); 69 | lsn_t lsn_ __attribute__((__unused__)); 70 | int size_ __attribute__((__unused__)); 71 | int max_size_ __attribute__((__unused__)); 72 | page_id_t parent_page_id_ __attribute__((__unused__)); 73 | page_id_t page_id_ __attribute__((__unused__)); 74 | }; 75 | 76 | } // namespace bustub 77 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/storage/index/b_plus_tree_index.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/index/b_plus_tree_index.cpp 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | 12 | #include "storage/index/b_plus_tree_index.h" 13 | 14 | namespace bustub { 15 | /* 16 | * Constructor 17 | */ 18 | INDEX_TEMPLATE_ARGUMENTS 19 | BPLUSTREE_INDEX_TYPE::BPlusTreeIndex(IndexMetadata *metadata, BufferPoolManager *buffer_pool_manager) 20 | : Index(metadata), 21 | comparator_(metadata->GetKeySchema()), 22 | container_(metadata->GetName(), buffer_pool_manager, comparator_) {} 23 | 24 | INDEX_TEMPLATE_ARGUMENTS 25 | void BPLUSTREE_INDEX_TYPE::InsertEntry(const Tuple &key, RID rid, Transaction *transaction) { 26 | // construct insert index key 27 | KeyType index_key; 28 | index_key.SetFromKey(key); 29 | 30 | container_.Insert(index_key, rid, transaction); 31 | } 32 | 33 | INDEX_TEMPLATE_ARGUMENTS 34 | void BPLUSTREE_INDEX_TYPE::DeleteEntry(const Tuple &key, RID rid, Transaction *transaction) { 35 | // construct delete index key 36 | KeyType index_key; 37 | index_key.SetFromKey(key); 38 | 39 | container_.Remove(index_key, transaction); 40 | } 41 | 42 | INDEX_TEMPLATE_ARGUMENTS 43 | void BPLUSTREE_INDEX_TYPE::ScanKey(const Tuple &key, std::vector *result, Transaction *transaction) { 44 | // construct scan index key 45 | KeyType index_key; 46 | index_key.SetFromKey(key); 47 | 48 | container_.GetValue(index_key, result, transaction); 49 | } 50 | 51 | INDEX_TEMPLATE_ARGUMENTS 52 | INDEXITERATOR_TYPE BPLUSTREE_INDEX_TYPE::GetBeginIterator() { return container_.begin(); } 53 | 54 | INDEX_TEMPLATE_ARGUMENTS 55 | INDEXITERATOR_TYPE BPLUSTREE_INDEX_TYPE::GetBeginIterator(const KeyType &key) { return container_.Begin(key); } 56 | 57 | INDEX_TEMPLATE_ARGUMENTS 58 | INDEXITERATOR_TYPE BPLUSTREE_INDEX_TYPE::GetEndIterator() { return container_.end(); } 59 | 60 | template class BPlusTreeIndex, RID, GenericComparator<4>>; 61 | template class BPlusTreeIndex, RID, GenericComparator<8>>; 62 | template class BPlusTreeIndex, RID, GenericComparator<16>>; 63 | template class BPlusTreeIndex, RID, GenericComparator<32>>; 64 | template class BPlusTreeIndex, RID, GenericComparator<64>>; 65 | 66 | } // namespace bustub 67 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/storage/index/index_iterator.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * index_iterator.cpp 3 | */ 4 | #include 5 | 6 | #include "storage/index/index_iterator.h" 7 | 8 | namespace bustub { 9 | 10 | /* 11 | * NOTE: you can change the destructor/constructor method here 12 | * set your own input parameters 13 | */ 14 | INDEX_TEMPLATE_ARGUMENTS 15 | INDEXITERATOR_TYPE::IndexIterator(BufferPoolManager *bpm, Page *page, int idx) 16 | : buffer_pool_manager_(bpm), page(page), idx(idx) { 17 | leaf = reinterpret_cast(page->GetData()); 18 | } 19 | 20 | INDEX_TEMPLATE_ARGUMENTS 21 | INDEXITERATOR_TYPE::~IndexIterator() { 22 | page->RUnlatch(); 23 | buffer_pool_manager_->UnpinPage(page->GetPageId(), false); 24 | } 25 | 26 | INDEX_TEMPLATE_ARGUMENTS 27 | bool INDEXITERATOR_TYPE::isEnd() { return leaf->GetNextPageId() == INVALID_PAGE_ID && idx == leaf->GetSize(); } 28 | 29 | INDEX_TEMPLATE_ARGUMENTS 30 | const MappingType &INDEXITERATOR_TYPE::operator*() { return leaf->GetItem(idx); } 31 | 32 | INDEX_TEMPLATE_ARGUMENTS 33 | INDEXITERATOR_TYPE &INDEXITERATOR_TYPE::operator++() { 34 | if (idx == leaf->GetSize() - 1 && leaf->GetNextPageId() != INVALID_PAGE_ID) { 35 | auto next_page = buffer_pool_manager_->FetchPage(leaf->GetNextPageId()); 36 | 37 | next_page->RLatch(); 38 | page->RUnlatch(); 39 | buffer_pool_manager_->UnpinPage(page->GetPageId(), false); 40 | 41 | page = next_page; 42 | leaf = reinterpret_cast(page->GetData()); 43 | idx = 0; 44 | } else { 45 | idx++; 46 | } 47 | 48 | return *this; 49 | } 50 | 51 | INDEX_TEMPLATE_ARGUMENTS 52 | bool INDEXITERATOR_TYPE::operator==(const IndexIterator &itr) const { 53 | return leaf->GetPageId() == itr.leaf->GetPageId() && idx == itr.idx; 54 | } 55 | 56 | INDEX_TEMPLATE_ARGUMENTS 57 | bool INDEXITERATOR_TYPE::operator!=(const IndexIterator &itr) const { 58 | return !(leaf->GetPageId() == itr.leaf->GetPageId() && idx == itr.idx); 59 | } 60 | 61 | template class IndexIterator, RID, GenericComparator<4>>; 62 | 63 | template class IndexIterator, RID, GenericComparator<8>>; 64 | 65 | template class IndexIterator, RID, GenericComparator<16>>; 66 | 67 | template class IndexIterator, RID, GenericComparator<32>>; 68 | 69 | template class IndexIterator, RID, GenericComparator<64>>; 70 | 71 | } // namespace bustub 72 | -------------------------------------------------------------------------------- /Project#3-QueryExecution/src/storage/page/b_plus_tree_page.cpp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // CMU-DB Project (15-445/645) 4 | // ***DO NO SHARE PUBLICLY*** 5 | // 6 | // Identification: src/page/b_plus_tree_page.cpp 7 | // 8 | // Copyright (c) 2018, Carnegie Mellon University Database Group 9 | // 10 | //===----------------------------------------------------------------------===// 11 | 12 | #include "storage/page/b_plus_tree_page.h" 13 | 14 | namespace bustub { 15 | 16 | /* 17 | * Helper methods to get/set page type 18 | * Page type enum class is defined in b_plus_tree_page.h 19 | */ 20 | bool BPlusTreePage::IsLeafPage() const { return page_type_ == IndexPageType::LEAF_PAGE; } 21 | bool BPlusTreePage::IsRootPage() const { return parent_page_id_ == INVALID_PAGE_ID; } 22 | void BPlusTreePage::SetPageType(IndexPageType page_type) { page_type_ = page_type; } 23 | IndexPageType BPlusTreePage::GetPageType() const { return page_type_; } 24 | 25 | /* 26 | * Helper methods to get/set size (number of key/value pairs stored in that 27 | * page) 28 | */ 29 | int BPlusTreePage::GetSize() const { return size_; } 30 | void BPlusTreePage::SetSize(int size) { size_ = size; } 31 | void BPlusTreePage::IncreaseSize(int amount) { size_ += amount; } 32 | 33 | /* 34 | * Helper methods to get/set max size (capacity) of the page 35 | */ 36 | int BPlusTreePage::GetMaxSize() const { return max_size_; } 37 | void BPlusTreePage::SetMaxSize(int size) { max_size_ = size; } 38 | 39 | /* 40 | * Helper method to get min page size 41 | * Generally, min page size == max page size / 2 42 | */ 43 | int BPlusTreePage::GetMinSize() const { return max_size_ / 2; } 44 | 45 | /* 46 | * Helper methods to get/set parent page id 47 | */ 48 | page_id_t BPlusTreePage::GetParentPageId() const { return parent_page_id_; } 49 | void BPlusTreePage::SetParentPageId(page_id_t parent_page_id) { parent_page_id_ = parent_page_id; } 50 | 51 | /* 52 | * Helper methods to get/set self page id 53 | */ 54 | page_id_t BPlusTreePage::GetPageId() const { return page_id_; } 55 | void BPlusTreePage::SetPageId(page_id_t page_id) { page_id_ = page_id; } 56 | 57 | /* 58 | * Helper methods to set lsn 59 | */ 60 | void BPlusTreePage::SetLSN(lsn_t lsn) { lsn_ = lsn; } 61 | 62 | } // namespace bustub 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CMU15-445-Intro To Database Systems (Fall 2019) 2 | My homework and projects about learning **CMU15-445 Lecture Fall 2019** 3 | 4 | The Lecture 02 Advanced SQL and Homework#1 SQL is **Fall 2018** 5 | 6 | Projects are **Fall 2020** 7 | 8 | Other homework are mainly **Fall 2019** 9 | 10 | ### Homework (Fall 2019) 11 | 12 | - [x] #1 SQL **(Fall 2018)** 13 | - [x] #2 Index 14 | - [x] #2 Index **(Fall 2020)** 15 | - [x] #2 Index **(Fall 2018)** 16 | - [x] #3 Join Algorithms 17 | 18 | ### Project (Fall 2020) 19 | 20 | - [x] #1 Buffer-Pool and additional Clock manager 21 | - [x] #2 B+TREE 22 | - [x] #3 Query Execution 23 | 24 | --------------------------------------------------------------------------------