05 Bufferpool

Download as pdf or txt
Download as pdf or txt
You are on page 1of 80

05 Buffer Pools

Intro to Database Systems Andy Pavlo


15-445/15-645
Fall 2019 AP Computer Science
Carnegie Mellon University
2

ADMINISTRIVIA

Homework #1 is due TODAY @ 11:59pm

Project #1 is due Fri Sept 26th @ 11:59pm

CMU 15-445/645 (Fall 2019)


3

D ATA B A S E W O R K L O A D S

On-Line Transaction Processing (OLTP)


→ Fast operations that only read/update a small amount of
data each time.

On-Line Analytical Processing (OLAP)


→ Complex queries that read a lot of data to compute
aggregates.

Hybrid Transaction + Analytical Processing


→ OLTP + OLAP together on the same database instance

CMU 15-445/645 (Fall 2019)


4

B I F U R C AT E D E N V I R O N M E N T

Transactions Analytical Queries

Extract
Transform
Load

OLTP Data Silos OLAP Data Warehouse


CMU 15-445/645 (Fall 2019)
4

B I F U R C AT E D E N V I R O N M E N T
Transactions
Analytical Queries

Extract
Transform
Load

HTAP Database OLAP Data Warehouse


CMU 15-445/645 (Fall 2019)
5

D ATA B A S E S T O R A G E

Problem #1: How the DBMS represents the


database in files on disk.

Problem #2: How the DBMS manages its memory


and move data back-and-forth from disk.

CMU 15-445/645 (Fall 2019)


6

D ATA B A S E S T O R A G E

Spatial Control:
→ Where to write pages on disk.
→ The goal is to keep pages that are used together often as
physically close together as possible on disk.

Temporal Control:
→ When to read pages into memory, and when to write
them to disk.
→ The goal is minimize the number of stalls from having to
read data from disk.

CMU 15-445/645 (Fall 2019)


7

D I S K- O R I E N T E D D B M S
Get page #2 Execution
Engine
Buffer Pool
Directory Header

Pointer to page #2
2
Memory
Database File

Directory Header Header Header Header Header

1 2 3 4 5 … Pages

Disk
CMU 15-445/645 (Fall 2019)
8

T O D AY ' S A G E N D A

Buffer Pool Manager


Replacement Policies
Other Memory Pools

CMU 15-445/645 (Fall 2019)


9

B U F F E R P O O L O R G A N I Z AT I O N
Buffer
Memory region organized as an array Pool
of fixed-size pages.
frame1
An array entry is called a frame.
frame2
frame3
When the DBMS requests a page, an
frame4
exact copy is placed into one of these
frames.
page1 page2 page3 page4

On-Disk File

CMU 15-445/645 (Fall 2019)


9

B U F F E R P O O L O R G A N I Z AT I O N
Buffer
Memory region organized as an array Pool
of fixed-size pages.
page1
frame1
An array entry is called a frame.
frame2
frame3
When the DBMS requests a page, an
frame4
exact copy is placed into one of these
frames.
page1 page2 page3 page4

On-Disk File

CMU 15-445/645 (Fall 2019)


9

B U F F E R P O O L O R G A N I Z AT I O N
Buffer
Memory region organized as an array Pool
of fixed-size pages.
page1
frame1
An array entry is called a frame.
frame2
page3
frame3
When the DBMS requests a page, an
frame4
exact copy is placed into one of these
frames.
page1 page2 page3 page4

On-Disk File

CMU 15-445/645 (Fall 2019)


10

B U F F E R P O O L M E TA - D ATA
Page Buffer
The page table keeps track of pages Table Pool
that are currently in memory.
page1 frame1
page1
page3 frame2
page3
Also maintains additional meta-data
frame3
per page:
→ Dirty Flag frame4
→ Pin/Reference Counter
page1 page2 page3 page4

On-Disk File

CMU 15-445/645 (Fall 2019)


10

B U F F E R P O O L M E TA - D ATA
Page Buffer
The page table keeps track of pages Table Pool
that are currently in memory.
page1 frame1
page1
page3 frame2
page3
Also maintains additional meta-data
frame3
per page:
→ Dirty Flag frame4
→ Pin/Reference Counter
page1 page2 page3 page4

On-Disk File

CMU 15-445/645 (Fall 2019)


10

B U F F E R P O O L M E TA - D ATA
Page Buffer
The page table keeps track of pages Table Pool
that are currently in memory.
page1 frame1
page1
page3 frame2
page3
Also maintains additional meta-data
frame3
per page:
→ Dirty Flag frame4
→ Pin/Reference Counter
page1 page2 page3 page4

On-Disk File

CMU 15-445/645 (Fall 2019)


10

B U F F E R P O O L M E TA - D ATA
Page Buffer
The page table keeps track of pages Table Pool
that are currently in memory.
page1 frame1
page1
page3 frame2
page3
Also maintains additional meta-data
page2
frame3
per page:
→ Dirty Flag frame4
→ Pin/Reference Counter
page1 page2 page3 page4

On-Disk File

CMU 15-445/645 (Fall 2019)


10

B U F F E R P O O L M E TA - D ATA
Page Buffer
The page table keeps track of pages Table Pool
that are currently in memory.
page1 frame1
page1
page3 frame2
page3
Also maintains additional meta-data
page2
frame3
per page:
→ Dirty Flag page2 frame4
→ Pin/Reference Counter
page1 page2 page3 page4

On-Disk File

CMU 15-445/645 (Fall 2019)


11

L O C K S V S . L AT C H E S

Locks:
→ Protects the database's logical contents from other
transactions.
→ Held for transaction duration.
→ Need to be able to rollback changes.

Latches:
→ Protects the critical sections of the DBMS's internal data
structure from other threads. ←Mutex
→ Held for operation duration.
→ Do not need to be able to rollback changes.

CMU 15-445/645 (Fall 2019)


12

PA G E TA B L E V S . PA G E D I R E C T O R Y

The page directory is the mapping from page ids


to page locations in the database files.
→ All changes must be recorded on disk to allow the DBMS
to find on restart.

The page table is the mapping from page ids to a


copy of the page in buffer pool frames.
→ This is an in-memory data structure that does not need to
be stored on disk.

CMU 15-445/645 (Fall 2019)


13

A L L O C AT I O N P O L I C I E S

Global Policies:
→ Make decisions for all active txns.

Local Policies:
→ Allocate frames to a specific txn without considering the
behavior of concurrent txns.
→ Still need to support sharing pages.

CMU 15-445/645 (Fall 2019)


14

B U F F E R P O O L O P T I M I Z AT I O N S

Multiple Buffer Pools


Pre-Fetching
Scan Sharing
Buffer Pool Bypass

CMU 15-445/645 (Fall 2019)


15

M U LT I P L E B U F F E R P O O L S

The DBMS does not always have a single buffer


pool for the entire system.
→ Multiple buffer pool instances
→ Per-database buffer pool
→ Per-page type buffer pool

Helps reduce latch contention and improve


locality.

CMU 15-445/645 (Fall 2019)


17

P R E- F E T C H I N G
Disk Pages
The DBMS can also prefetch pages
based on a query plan. Q1 page0
→ Sequential Scans
→ Index Scans page1

Buffer Pool page2

page0 page3

page4

page5
CMU 15-445/645 (Fall 2019)
17

P R E- F E T C H I N G
Disk Pages
The DBMS can also prefetch pages
based on a query plan. page0
→ Sequential Scans
→ Index Scans Q1 page1

Buffer Pool page2

page0 page3

page1 page4

page5
CMU 15-445/645 (Fall 2019)
17

P R E- F E T C H I N G
Disk Pages
The DBMS can also prefetch pages
based on a query plan. page0
→ Sequential Scans
→ Index Scans Q1 page1

Buffer Pool page2

page0 page3

page1 page4

page5
CMU 15-445/645 (Fall 2019)
17

P R E- F E T C H I N G
Disk Pages
The DBMS can also prefetch pages
based on a query plan. page0
→ Sequential Scans
→ Index Scans Q1 page1

Buffer Pool page2

page3 page3

page1 page4

page2 page5
CMU 15-445/645 (Fall 2019)
17

P R E- F E T C H I N G
Disk Pages
The DBMS can also prefetch pages
based on a query plan. page0
→ Sequential Scans
→ Index Scans page1

Buffer Pool Q1 page2

page3 page3

page1 page4

page2 page5
CMU 15-445/645 (Fall 2019)
17

P R E- F E T C H I N G
Disk Pages
The DBMS can also prefetch pages
based on a query plan. page0
→ Sequential Scans
→ Index Scans page1

Buffer Pool page2

page3 page3

page4 page4

page5 Q1 page5
CMU 15-445/645 (Fall 2019)
18

P R E- F E T C H I N G
Disk Pages
Q1 SELECT * FROM A
index-page0
WHERE val BETWEEN 100 AND 250

index-page1

Buffer Pool index-page2

index-page3

index-page4

index-page5
CMU 15-445/645 (Fall 2019)
18

P R E- F E T C H I N G
index-page0
Disk Pages
index-page1 index-page4 index-page0
index-page2 index-page3 index-page5 index-page6
index-page1
0 99 100 199 200 299 300 399

Buffer Pool index-page2

index-page3

index-page4

index-page5
CMU 15-445/645 (Fall 2019)
18

P R E- F E T C H I N G
index-page0
Disk Pages
index-page1 index-page4
Q1 index-page0
index-page2 index-page3 index-page5 index-page6
index-page1
0 99 100 199 200 299 300 399

Buffer Pool index-page2

index-page0 index-page3

index-page4

index-page5
CMU 15-445/645 (Fall 2019)
18

P R E- F E T C H I N G
index-page0
Disk Pages
index-page1 index-page4 index-page0
index-page2 index-page3 index-page5 index-page6
Q1 index-page1
0 99 100 199 200 299 300 399

Buffer Pool index-page2

index-page0 index-page3

index-page1 index-page4

index-page5
CMU 15-445/645 (Fall 2019)
18

P R E- F E T C H I N G
index-page0
Disk Pages
index-page1 index-page4 index-page0
index-page2 index-page3 index-page5 index-page6
Q1 index-page1
0 99 100 199 200 299 300 399

Buffer Pool index-page2

index-page0 index-page3

index-page1 index-page4

index-page5
CMU 15-445/645 (Fall 2019)
19

SCAN SHARING

Queries can reuse data retrieved from storage or


operator computations.
→ This is different from result caching.

Allow multiple queries to attach to a single cursor


that scans a table.
→ Queries do not have to be the same.
→ Can also share intermediate results.

CMU 15-445/645 (Fall 2019)


20

SCAN SHARING

If a query starts a scan and if there one already


doing this, then the DBMS will attach to the
second query's cursor.
→ The DBMS keeps track of where the second query joined
with the first so that it can finish the scan when it reaches
the end of the data structure.
Fully supported in IBM DB2 and MSSQL.
Oracle only supports cursor sharing for identical
queries.

CMU 15-445/645 (Fall 2019)


21

SCAN SHARING
Disk Pages
Q1 SELECT SUM(val) FROM A
Q1 page0

page1

Buffer Pool page2

page0 page3

page4

page5
CMU 15-445/645 (Fall 2019)
21

SCAN SHARING
Disk Pages
Q1 SELECT SUM(val) FROM A
page0

page1

Buffer Pool Q1 page2

page0 page3

page1 page4

page2 page5
CMU 15-445/645 (Fall 2019)
21

SCAN SHARING
Disk Pages
Q1 SELECT SUM(val) FROM A
page0

page1

Buffer Pool page2

page0 Q1 page3

page1 page4

page2 page5
CMU 15-445/645 (Fall 2019)
21

SCAN SHARING
Disk Pages
Q1 SELECT SUM(val) FROM A
page0

page1

Buffer Pool page2

page3 Q1 page3

page1 page4

page2 page5
CMU 15-445/645 (Fall 2019)
21

SCAN SHARING
Disk Pages
Q1 SELECT SUM(val) FROM A
Q2 page0
Q2 SELECT AVG(val) FROM A
page1

Buffer Pool page2

page3 Q1 page3

page1 page4

page2 page5
CMU 15-445/645 (Fall 2019)
21

SCAN SHARING
Disk Pages
Q1 SELECT SUM(val) FROM A
page0
Q2 SELECT AVG(val) FROM A
page1

Buffer Pool page2

page3 Q2 Q1 page3

page1 page4

page2 page5
CMU 15-445/645 (Fall 2019)
21

SCAN SHARING
Disk Pages
Q1 SELECT SUM(val) FROM A
page0
Q2 SELECT AVG(val) FROM A
page1

Buffer Pool page2

page3 page3

page4 page4

page5 Q2 Q1 page5
CMU 15-445/645 (Fall 2019)
21

SCAN SHARING
Disk Pages
Q1 SELECT SUM(val) FROM A
Q2 page0
Q2 SELECT AVG(val) FROM A
page1

Buffer Pool page2

page3 page3

page4 page4

page5 page5
CMU 15-445/645 (Fall 2019)
21

SCAN SHARING
Disk Pages
Q1 SELECT SUM(val) FROM A
page0
Q2 SELECT AVG(val) FROM A
page1

Buffer Pool Q2 page2

page0 page3

page1 page4

page2 page5
CMU 15-445/645 (Fall 2019)
21

SCAN SHARING
Disk Pages
Q1 SELECT SUM(val) FROM A
page0
Q2 SELECT AVG(val) FROM A LIMIT 100
page1

Buffer Pool Q2 page2

page0 page3

page1 page4

page2 page5
CMU 15-445/645 (Fall 2019)
22

B U F F E R P O O L B Y PA S S

The sequential scan operator will not store fetched


pages in the buffer pool to avoid overhead.
→ Memory is local to running query.
→ Works well if operator needs to read a large sequence of
pages that are contiguous on disk.
→ Can also be used for temporary data (sorting, joins).

Called "Light Scans" in Informix.

CMU 15-445/645 (Fall 2019)


23

O S PA G E C A C H E

Most disk operations go through the OS API.


Unless you tell it not to, the OS maintains its own
filesystem cache.

Most DBMSs use direct I/O (O_DIRECT)to bypass


the OS's cache.
→ Redundant copies of pages.
→ Different eviction policies.

Demo: Postgres
CMU 15-445/645 (Fall 2019)
24

BUFFER REPLACEMENT POLICIES

When the DBMS needs to free up a frame to make


room for a new page, it must decide which page to
evict from the buffer pool.

Goals:
→ Correctness
→ Accuracy
→ Speed
→ Meta-data overhead

CMU 15-445/645 (Fall 2019)


25

L E A S T- R E C E N T LY U S E D

Maintain a timestamp of when each page was last


accessed.

When the DBMS needs to evict a page, select the


one with the oldest timestamp.
→ Keep the pages in sorted order to reduce the search time
on eviction.

CMU 15-445/645 (Fall 2019)


26

CLOCK

Approximation of LRU without ref=0


needing a separate timestamp per page1

page.
→ Each page has a reference bit. ref=0 ref=0
→ When a page is accessed, set to 1. page4 page2

Organize the pages in a circular buffer


with a "clock hand":
→ Upon sweeping, check if a page's bit is set page3
to 1. ref=0
→ If yes, set to zero. If no, then evict.

CMU 15-445/645 (Fall 2019)


26

CLOCK

Approximation of LRU without ref=1


needing a separate timestamp per page1

page.
→ Each page has a reference bit. ref=0 ref=0
→ When a page is accessed, set to 1. page4 page2

Organize the pages in a circular buffer


with a "clock hand":
→ Upon sweeping, check if a page's bit is set page3
to 1. ref=0
→ If yes, set to zero. If no, then evict.

CMU 15-445/645 (Fall 2019)


26

CLOCK

Approximation of LRU without ref=1


needing a separate timestamp per page1

page.
→ Each page has a reference bit. ref=0 ref=0
→ When a page is accessed, set to 1. page4 page2

Organize the pages in a circular buffer


with a "clock hand":
→ Upon sweeping, check if a page's bit is set page3
to 1. ref=0
→ If yes, set to zero. If no, then evict.

CMU 15-445/645 (Fall 2019)


26

CLOCK

Approximation of LRU without ref=0


needing a separate timestamp per page1

page.
→ Each page has a reference bit. ref=0 ref=0
→ When a page is accessed, set to 1. page4 page2

Organize the pages in a circular buffer


with a "clock hand":
→ Upon sweeping, check if a page's bit is set page3
to 1. ref=0
→ If yes, set to zero. If no, then evict.

CMU 15-445/645 (Fall 2019)


26

CLOCK

Approximation of LRU without ref=0


needing a separate timestamp per page1

X
page.
→ Each page has a reference bit. ref=0 ref=0
→ When a page is accessed, set to 1. page4 page2

Organize the pages in a circular buffer


with a "clock hand":
→ Upon sweeping, check if a page's bit is set page3
to 1. ref=0
→ If yes, set to zero. If no, then evict.

CMU 15-445/645 (Fall 2019)


26

CLOCK

Approximation of LRU without ref=0


needing a separate timestamp per page1

page.
→ Each page has a reference bit. ref=0 ref=0
→ When a page is accessed, set to 1. page4 page2
page5

Organize the pages in a circular buffer


with a "clock hand":
→ Upon sweeping, check if a page's bit is set page3
to 1. ref=0
→ If yes, set to zero. If no, then evict.

CMU 15-445/645 (Fall 2019)


26

CLOCK

Approximation of LRU without ref=0


needing a separate timestamp per page1

page.
→ Each page has a reference bit. ref=1 ref=0
→ When a page is accessed, set to 1. page4 page2
page5

Organize the pages in a circular buffer


with a "clock hand":
→ Upon sweeping, check if a page's bit is set page3
to 1. ref=1
→ If yes, set to zero. If no, then evict.

CMU 15-445/645 (Fall 2019)


26

CLOCK

Approximation of LRU without


needing a separate timestamp per
page.
→ Each page has a reference bit. ref=0
X
ref=0
page1

ref=0
→ When a page is accessed, set to 1. page4 page2
page5

Organize the pages in a circular buffer


with a "clock hand":
→ Upon sweeping, check if a page's bit is set page3
to 1. ref=0
→ If yes, set to zero. If no, then evict.

CMU 15-445/645 (Fall 2019)


27

PROBLEMS

LRU and CLOCK replacement policies are


susceptible to sequential flooding.
→ A query performs a sequential scan that reads every page.
→ This pollutes the buffer pool with pages that are read
once and then never again.

The most recently used page is actually the most


unneeded page.

CMU 15-445/645 (Fall 2019)


28

SEQUENTIAL FLOODING

Q1 SELECT * FROM A WHERE id = 1 Disk Pages


Q1 page0

page1

Buffer Pool page2

page0 page3

page4

page5
CMU 15-445/645 (Fall 2019)
28

SEQUENTIAL FLOODING

Q1 SELECT * FROM A WHERE id = 1 Disk Pages


Q2 SELECT AVG(val) FROM A Q2 page0

page1

Buffer Pool page2

page0 page3

page4

page5
CMU 15-445/645 (Fall 2019)
28

SEQUENTIAL FLOODING

Q1 SELECT * FROM A WHERE id = 1 Disk Pages


Q2 SELECT AVG(val) FROM A page0

page1

Buffer Pool page2

page0 Q2 page3

page1 page4

page2 page5
CMU 15-445/645 (Fall 2019)
28

SEQUENTIAL FLOODING

Q1 SELECT * FROM A WHERE id = 1 Disk Pages


Q2 SELECT AVG(val) FROM A page0

page1

Buffer Pool page2

page3 Q2 page3

page1 page4

page2 page5
CMU 15-445/645 (Fall 2019)
28

SEQUENTIAL FLOODING

Q1 SELECT * FROM A WHERE id = 1 Disk Pages


Q2 SELECT AVG(val) FROM A Q2 page0

Q3 SELECT * FROM A WHERE id = 1 page1

Buffer Pool page2

page3 Q2 page3

page1 page4

page2 page5
CMU 15-445/645 (Fall 2019)
29

BETTER POLICIES: LRU-K

Track the history of the last K references as


timestamps and compute the interval between
subsequent accesses.

The DBMS then uses this history to estimate the


next time that page is going to be accessed.

CMU 15-445/645 (Fall 2019)


30

B E T T E R P O L I C I E S : L O C A L I Z AT I O N

The DBMS chooses which pages to evict on a per


txn/query basis. This minimizes the pollution of
the buffer pool from each query.
→ Keep track of the pages that a query has accessed.

Example: Postgres maintains a small ring buffer


that is private to the query.

CMU 15-445/645 (Fall 2019)


31

BETTER POLICIES: PRIORITY HINTS

The DBMS knows what the context of each page


during query execution.
It can provide hints to the buffer pool on whether
a page is important or not.

index-page0
Q1 INSERT INTO A VALUES (id++)
index-page1 index-page4

index-page2 index-page3 index-page5 index-page6

MIN id MAX
CMU 15-445/645 (Fall 2019)
31

BETTER POLICIES: PRIORITY HINTS

The DBMS knows what the context of each page


during query execution.
It can provide hints to the buffer pool on whether
a page is important or not.

index-page0
Q1 INSERT INTO A VALUES (id++)
index-page1 index-page4

index-page2 index-page3 index-page5 index-page6

MIN id MAX
CMU 15-445/645 (Fall 2019)
31

BETTER POLICIES: PRIORITY HINTS

The DBMS knows what the context of each page


during query execution.
It can provide hints to the buffer pool on whether
a page is important or not.

index-page0
Q1 INSERT INTO A VALUES (id++)
index-page1 index-page4
Q2 SELECT * FROM A WHERE id = ?
index-page2 index-page3 index-page5 index-page6

MIN id MAX
CMU 15-445/645 (Fall 2019)
32

D I R T Y PA G E S

FAST: If a page in the buffer pool is not dirty, then


the DBMS can simply "drop" it.

SLOW: If a page is dirty, then the DBMS must


write back to disk to ensure that its changes are
persisted.

Trade-off between fast evictions versus dirty


writing pages that will not be read again in the
future.
CMU 15-445/645 (Fall 2019)
33

B A C KG R O U N D W R I T I N G

The DBMS can periodically walk through the page


table and write dirty pages to disk.

When a dirty page is safely written, the DBMS can


either evict the page or just unset the dirty flag.

Need to be careful that we don’t write dirty pages


before their log records have been written…

CMU 15-445/645 (Fall 2019)


34

OTHER MEMORY POOLS

The DBMS needs memory for things other than


just tuples and indexes.
These other memory pools may not always backed
by disk. Depends on implementation.
→ Sorting + Join Buffers
→ Query Caches
→ Maintenance Buffers
→ Log Buffers
→ Dictionary Caches

CMU 15-445/645 (Fall 2019)


35

CONCLUSION

The DBMS can manage that sweet, sweet memory


better than the OS.

Leverage the semantics about the query plan to


make better decisions:
→ Evictions
→ Allocations
→ Pre-fetching

CMU 15-445/645 (Fall 2019)


36

PROJECT #1

You will build the first component of


your storage manager.
→ Clock Replacement Policy
→ Buffer Pool Manager

We will provide you with the disk


manager and page layouts.

Due Date:
Friday Sept 27th @ 11:59pm

CMU 15-445/645 (Fall 2019)


37

TA S K # 1 CLOCK REPL ACEMENT POLICY

Build a data structure that tracks the usage of


frame_ids using the CLOCK policy.

General Hints:
→ Your ClockReplacer needs to check the "pinned" status
of a Page.
→ If there are no pages touched since last sweep, then
return the lowest page id.

CMU 15-445/645 (Fall 2019)


38

TA S K # 2 BUFFER POOL MANAGER

Use your CLOCK replacer to manage


the allocation of pages. Buffer Pool Database
→ Need to maintain an internal data (In-Memory) (On-Disk)
structures of allocated + free pages. Page6 Page0
→ We will provide you components to
Page2 Page1
read/write data from disk.
→ Use whatever data structure you want for Page4 Page2
the page table.

General Hints:
→ Make sure you get the order of operations
correct when pinning.
CMU 15-445/645 (Fall 2019)
39

G E T T I N G S TA R T E D

Download the source code from GitHub.

Make sure you can build it on your machine.


→ We've tested Ubuntu, OSX, and Windows (WSL2).
→ We are also providing a docker file to setup your
environment.
→ It does not compile on the Andrews machines. Please
contact me if this is a problem.

CMU 15-445/645 (Fall 2019)


40

THINGS TO NOTE

Do not change any file other than the four that


you must hand in.

The projects are cumulative.

We will not be providing solutions.

Post your questions on Piazza or come to our


office hours. We will not help you debug.

CMU 15-445/645 (Fall 2019)


41

CODE QUALIT Y

We will automatically check whether you are


writing good code.
→ Google C++ Style Guide
→ Doxygen Javadoc Style

You need to run these targets before you submit


your implementation to Gradescope.
→ make format
→ make check-lint
→ make check-censored
→ make check-clang-tidy
CMU 15-445/645 (Fall 2019)
42

P L A G I A R I S M WA R N I N G

Your project implementation must be


your own work.
→ You may not copy source code from other
groups or the web.
→ Do not publish your implementation on
GitHub.

Plagiarism will not be tolerated.


See CMU's Policy on Academic
Integrity for additional information.

CMU 15-445/645 (Fall 2019)


43

NEXT CLASS

HASH TABLES!

CMU 15-445/645 (Fall 2019)

You might also like