Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
637009abf8 | ||
|
|
e391687a2e | ||
|
|
3cad683e98 | ||
|
|
51f720ad9f | ||
|
|
f7697e992f | ||
|
|
8a25672da0 | ||
|
|
4478618a17 | ||
|
|
4321264563 | ||
|
|
1bf1e773a5 | ||
|
|
611513ed9d | ||
|
|
45f8e38c1f | ||
|
|
f5f90d89a3 | ||
|
|
66e8626fc9 | ||
|
|
aab3637fd7 | ||
|
|
ef53299240 | ||
|
|
659352e992 | ||
|
|
fde465354e | ||
|
|
5bd0da5970 | ||
|
|
b011a30ab6 | ||
|
|
2c4360df9b | ||
|
|
eb15a96eca |
@@ -43,3 +43,305 @@ buildNumber.properties
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
.classpath
|
||||
|
||||
# ---> TeX
|
||||
## Core latex/pdflatex auxiliary files:
|
||||
*.aux
|
||||
*.lof
|
||||
*.log
|
||||
*.lot
|
||||
*.fls
|
||||
*.out
|
||||
*.toc
|
||||
*.fmt
|
||||
*.fot
|
||||
*.cb
|
||||
*.cb2
|
||||
.*.lb
|
||||
|
||||
## Intermediate documents:
|
||||
*.dvi
|
||||
*.xdv
|
||||
*-converted-to.*
|
||||
# these rules might exclude image files for figures etc.
|
||||
# *.ps
|
||||
# *.eps
|
||||
# *.pdf
|
||||
|
||||
## Generated if empty string is given at "Please type another file name for output:"
|
||||
.pdf
|
||||
|
||||
## Bibliography auxiliary files (bibtex/biblatex/biber):
|
||||
*.bbl
|
||||
*.bcf
|
||||
*.blg
|
||||
*-blx.aux
|
||||
*-blx.bib
|
||||
*.run.xml
|
||||
|
||||
## Build tool auxiliary files:
|
||||
*.fdb_latexmk
|
||||
*.synctex
|
||||
*.synctex(busy)
|
||||
*.synctex.gz
|
||||
*.synctex.gz(busy)
|
||||
*.pdfsync
|
||||
|
||||
## Build tool directories for auxiliary files
|
||||
# latexrun
|
||||
latex.out/
|
||||
|
||||
## Auxiliary and intermediate files from other packages:
|
||||
# algorithms
|
||||
*.alg
|
||||
*.loa
|
||||
|
||||
# achemso
|
||||
acs-*.bib
|
||||
|
||||
# amsthm
|
||||
*.thm
|
||||
|
||||
# beamer
|
||||
*.nav
|
||||
*.pre
|
||||
*.snm
|
||||
*.vrb
|
||||
|
||||
# changes
|
||||
*.soc
|
||||
|
||||
# comment
|
||||
*.cut
|
||||
|
||||
# cprotect
|
||||
*.cpt
|
||||
|
||||
# elsarticle (documentclass of Elsevier journals)
|
||||
*.spl
|
||||
|
||||
# endnotes
|
||||
*.ent
|
||||
|
||||
# fixme
|
||||
*.lox
|
||||
|
||||
# feynmf/feynmp
|
||||
*.mf
|
||||
*.mp
|
||||
*.t[1-9]
|
||||
*.t[1-9][0-9]
|
||||
*.tfm
|
||||
|
||||
#(r)(e)ledmac/(r)(e)ledpar
|
||||
*.end
|
||||
*.?end
|
||||
*.[1-9]
|
||||
*.[1-9][0-9]
|
||||
*.[1-9][0-9][0-9]
|
||||
*.[1-9]R
|
||||
*.[1-9][0-9]R
|
||||
*.[1-9][0-9][0-9]R
|
||||
*.eledsec[1-9]
|
||||
*.eledsec[1-9]R
|
||||
*.eledsec[1-9][0-9]
|
||||
*.eledsec[1-9][0-9]R
|
||||
*.eledsec[1-9][0-9][0-9]
|
||||
*.eledsec[1-9][0-9][0-9]R
|
||||
|
||||
# glossaries
|
||||
*.acn
|
||||
*.acr
|
||||
*.glg
|
||||
*.glo
|
||||
*.gls
|
||||
*.glsdefs
|
||||
*.lzo
|
||||
*.lzs
|
||||
*.slg
|
||||
*.slo
|
||||
*.sls
|
||||
|
||||
# uncomment this for glossaries-extra (will ignore makeindex's style files!)
|
||||
# *.ist
|
||||
|
||||
# gnuplot
|
||||
*.gnuplot
|
||||
*.table
|
||||
|
||||
# gnuplottex
|
||||
*-gnuplottex-*
|
||||
|
||||
# gregoriotex
|
||||
*.gaux
|
||||
*.glog
|
||||
*.gtex
|
||||
|
||||
# htlatex
|
||||
*.4ct
|
||||
*.4tc
|
||||
*.idv
|
||||
*.lg
|
||||
*.trc
|
||||
*.xref
|
||||
|
||||
# hyperref
|
||||
*.brf
|
||||
|
||||
# knitr
|
||||
*-concordance.tex
|
||||
# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
|
||||
# *.tikz
|
||||
*-tikzDictionary
|
||||
|
||||
# listings
|
||||
*.lol
|
||||
|
||||
# luatexja-ruby
|
||||
*.ltjruby
|
||||
|
||||
# makeidx
|
||||
*.idx
|
||||
*.ilg
|
||||
*.ind
|
||||
|
||||
# minitoc
|
||||
*.maf
|
||||
*.mlf
|
||||
*.mlt
|
||||
*.mtc[0-9]*
|
||||
*.slf[0-9]*
|
||||
*.slt[0-9]*
|
||||
*.stc[0-9]*
|
||||
|
||||
# minted
|
||||
_minted*
|
||||
*.pyg
|
||||
|
||||
# morewrites
|
||||
*.mw
|
||||
|
||||
# newpax
|
||||
*.newpax
|
||||
|
||||
# nomencl
|
||||
*.nlg
|
||||
*.nlo
|
||||
*.nls
|
||||
|
||||
# pax
|
||||
*.pax
|
||||
|
||||
# pdfpcnotes
|
||||
*.pdfpc
|
||||
|
||||
# sagetex
|
||||
*.sagetex.sage
|
||||
*.sagetex.py
|
||||
*.sagetex.scmd
|
||||
|
||||
# scrwfile
|
||||
*.wrt
|
||||
|
||||
# svg
|
||||
svg-inkscape/
|
||||
|
||||
# sympy
|
||||
*.sout
|
||||
*.sympy
|
||||
sympy-plots-for-*.tex/
|
||||
|
||||
# pdfcomment
|
||||
*.upa
|
||||
*.upb
|
||||
|
||||
# pythontex
|
||||
*.pytxcode
|
||||
pythontex-files-*/
|
||||
|
||||
# tcolorbox
|
||||
*.listing
|
||||
|
||||
# thmtools
|
||||
*.loe
|
||||
|
||||
# TikZ & PGF
|
||||
*.dpth
|
||||
*.md5
|
||||
*.auxlock
|
||||
|
||||
# titletoc
|
||||
*.ptc
|
||||
|
||||
# todonotes
|
||||
*.tdo
|
||||
|
||||
# vhistory
|
||||
*.hst
|
||||
*.ver
|
||||
|
||||
# easy-todo
|
||||
*.lod
|
||||
|
||||
# xcolor
|
||||
*.xcp
|
||||
|
||||
# xmpincl
|
||||
*.xmpi
|
||||
|
||||
# xindy
|
||||
*.xdy
|
||||
|
||||
# xypic precompiled matrices and outlines
|
||||
*.xyc
|
||||
*.xyd
|
||||
|
||||
# endfloat
|
||||
*.ttt
|
||||
*.fff
|
||||
|
||||
# Latexian
|
||||
TSWLatexianTemp*
|
||||
|
||||
## Editors:
|
||||
# WinEdt
|
||||
*.bak
|
||||
*.sav
|
||||
|
||||
# Texpad
|
||||
.texpadtmp
|
||||
|
||||
# LyX
|
||||
*.lyx~
|
||||
|
||||
# Kile
|
||||
*.backup
|
||||
|
||||
# gummi
|
||||
.*.swp
|
||||
|
||||
# KBibTeX
|
||||
*~[0-9]*
|
||||
|
||||
# TeXnicCenter
|
||||
*.tps
|
||||
|
||||
# auto folder when using emacs and auctex
|
||||
./auto/*
|
||||
*.el
|
||||
|
||||
# expex forward references with \gathertags
|
||||
*-tags.tex
|
||||
|
||||
# standalone packages
|
||||
*.sta
|
||||
|
||||
# Makeindex log files
|
||||
*.lpz
|
||||
|
||||
# xwatermark package
|
||||
*.xwm
|
||||
|
||||
# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
|
||||
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
|
||||
# Uncomment the next line to have this generated file ignored.
|
||||
#*Notes.bib
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
\documentclass{article}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage{amsfonts}
|
||||
\usepackage{amsmath, amssymb, textcomp, gensymb}
|
||||
\usepackage[a4paper, total={6in, 8in}]{geometry}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{enumerate}
|
||||
|
||||
\title{CS 448 Spring 2024 Homework 1}
|
||||
\author{Sean Rettig}
|
||||
|
||||
\begin{document}
|
||||
\maketitle
|
||||
|
||||
\section*{Question 1. (0.50 pts)}
|
||||
\begin{enumerate}[(a)]
|
||||
\item Discuss the main capabilities that should be provided by a DBMS
|
||||
\item Highlight the difference of using a database system with respect to the following approaches. Please, make sure to highlight the benefits offered by a DBMS.
|
||||
\begin{enumerate}[1.]
|
||||
\item Traditional file systems
|
||||
\item In-memory storage
|
||||
\end{enumerate}
|
||||
\end{enumerate}
|
||||
|
||||
\hrule
|
||||
|
||||
\begin{enumerate}[(a)]
|
||||
\item One of the main capabilities that should be provided by a databse include a self describing nature. The database shouldn't
|
||||
just store it's own data, but it should also store a complete definition of the database structure and it's constraints.
|
||||
|
||||
Another capability should be an insulation between programs and data, otherwise called program-data independence.
|
||||
This allows changing data structures and storage organization without having to change the DBMS access programs.
|
||||
|
||||
Thirdly, there is data abstraction. The DBMS should provide a conceptual representation of it's data, and should hide the actual physical implementation.
|
||||
|
||||
The database should also support multiple view of the data.
|
||||
The user should not be limited to the actual positioning of the data, and should be able to view it in multiple ways.
|
||||
|
||||
Finally, the database should facilitate sharing of data and multiuser transaction processing. Multiple users should be able to access the data at the same time.
|
||||
\item \begin{enumerate}[1.]
|
||||
\item The traditional filesystem does not include the main characteristics of a DBMS well. There is no self describing nature in a filesystem,
|
||||
The program or software needs to know where the information is stored to be able to access it. There is no conceptual representation of the data either.
|
||||
Additionally, there are not multiple views of the data. Finally, sharing information is very difficult because traditional filesystems are very user focused,
|
||||
so if someone has information stored in their own filesystem place, it is not readily accessible by anyone else.
|
||||
\item It is not explicitely designated how in-memory storage would be designed. However, if the application software is storing everything in-memory and in the program that is running,
|
||||
all it takes is for the program to stop or the computer to shut down and the data will be gone.
|
||||
\end{enumerate}
|
||||
\end{enumerate}
|
||||
|
||||
\newpage
|
||||
\section*{Question 2. (0.50 pts)}
|
||||
Cite some examples of integrity constraints that you think can apply to the database shown in
|
||||
Figure 1.2 in the textbook. Please, provide at least two examples for each type of the following
|
||||
constraints: unique constraints and referential integrity constraints
|
||||
\hrule
|
||||
\vspace{.5cm}
|
||||
\noindent
|
||||
Unique: Lets say that each section must have a unique section\_identifier, and each student must have a unique student\_number.
|
||||
\\\\
|
||||
\noindent
|
||||
Referential: Each student\_number in the grade report must refer to a student in STUDENT. Each section identifier in GRADE\_REPORT must
|
||||
refer to a section\_identifier in SECTION
|
||||
|
||||
|
||||
\section*{Question 3. (0.25 pts)}
|
||||
What is the difference between a database schema and a database state? Please, use examples to
|
||||
support your answer.
|
||||
\hrule
|
||||
\vspace{.5cm}
|
||||
\noindent
|
||||
The database schema is the description of the database and what information it holds, and how it all relates to each other.
|
||||
The database state is the current data actually in the database.\\\\
|
||||
For example, in Figure 1.2, the database schema for the STUDENT table says that it includes the students name, Student\_number, Class, and Major.
|
||||
The database state includes actual student names, and the rest of the information like Name: Smith, Student\_number: 17, Class: 1, Major: CS and then other students as well.
|
||||
|
||||
|
||||
\section*{Question 4. (0.50 pts)}
|
||||
\begin{enumerate}[(a)]
|
||||
\item What is logical independence and physical independence? Please, use examples to
|
||||
support your answer.
|
||||
\item Which one is harder to achieve? Explain why.
|
||||
\end{enumerate}
|
||||
\hrule
|
||||
\vspace{.5cm}
|
||||
\noindent
|
||||
\begin{enumerate}[(a)]
|
||||
\item Data independence refers to the capacity to change different levels in the three scheme architecture without affecting each other.
|
||||
Logical independence is the ability to change the conceptual schema, while physical independence refers to the ability to change the internal schema.
|
||||
\\\\
|
||||
If you had logical independence, you could add a row to GRADE\_REPORT in Figure 1.2 and all the external views that
|
||||
call for data that is in the other columns will not be affected at all.
|
||||
|
||||
If you had physical independence, you could change the way that GRADE\_REPORT is actually stored in the
|
||||
DBMS by creating a better way of accessing the data. The conceptual schema wouldn't cahnge and neither would the external schema.
|
||||
\item Logical independence is harder to achieve. This is because it allows structural and constraint changes, but you cannot affect application programs.
|
||||
\end{enumerate}
|
||||
|
||||
|
||||
\section*{Question 5. (0.50 pts)}
|
||||
What are the different components of a DBMS? Discuss the importance and need of each
|
||||
component.
|
||||
\hrule
|
||||
\vspace{.5cm}
|
||||
\noindent
|
||||
\begin{itemize}
|
||||
\item \textbf{Interfaces for DBA staff, Casual Users, Application Programmers, and Parametric Users}: This is important because
|
||||
the data is needed to be accessed, but not everyone needs the same type of access. Some need more advanced while others need simpler access.
|
||||
\item \textbf{DDL Compiler}: This prcoesses schema definitions. This is important to create the catalog.
|
||||
\item \textbf{Query Optimizer}: This component takes queries and looks for ways to optimize them. Either by consulting the catalog or through other means.
|
||||
It is important because it improves performance.
|
||||
\item \textbf{Precompiler}: This extracts DML commands and sends them to the DML compiler for compilation into object code.
|
||||
This is important to be able to communicate to the database.
|
||||
\item \textbf{Runtime Database processor}: This executes the commands, query plans, and transactions. This is important in accessing the database.
|
||||
\item \textbf{Stored Data Manager}: This uses basic operating system services for carrying out low-level IO to disk and main memory. It's important
|
||||
because the low-level IO needs to reach the higher level calls.
|
||||
\item \textbf{Concurrency control and Backup and Recovery systems}: Handle concurrency access as well as backup and recovery of the database. These are important
|
||||
to support the main capabilities of the database being concurrency access and then another important feature of backup.
|
||||
\end{itemize}
|
||||
|
||||
\section*{Question 6. (0.50 pts)}
|
||||
\begin{enumerate}[(a)]
|
||||
\item What is a user transaction?
|
||||
\item What properties must be maintained for a transaction by the database system? Please,
|
||||
discuss each property using an example to support your argument.
|
||||
\end{enumerate}
|
||||
\hrule
|
||||
\vspace{.5cm}
|
||||
\noindent
|
||||
\begin{enumerate}[(a)]
|
||||
\item A transaction, as the textbook says, is an execuiting program or process. It can include one or more database accesses.
|
||||
It can read or update records as well.
|
||||
\item Properties that the DBMS have must include isolation as well as atomicity.
|
||||
|
||||
Isolation ensures that each transaction takes place without effecting other transactions. This means that if I had one transaction asking
|
||||
for all the students in one class, but in the middle of that transaction I update the students in the class, the first transaction will
|
||||
have the same result as if I didn't do the second one.
|
||||
|
||||
Atomicity ensures that either all the databse operations in a transaction are executed or none are. For example,
|
||||
if, in my transaction, I calculated GPA of all students and added that to their records, but my second operation doesn't complete successfully, then the first part of
|
||||
of my transaction will not execute.
|
||||
\end{enumerate}
|
||||
|
||||
\section*{Question 7. (0.25 pts)}
|
||||
Why is accessing a disk block expensive? Discuss the time components involved in accessing a
|
||||
disk block.
|
||||
\vspace{.5cm}
|
||||
\hrule
|
||||
\vspace{.5cm}
|
||||
\noindent
|
||||
It is expensive for a couple of reasons. Given the address, the disk controller must physically position the read/write head on the
|
||||
on the correct track. This is called seek time and can take anywhere from 5 to 10 msec.\\
|
||||
After seek time there is also rotational delay. This is waiting for the beginning of the desired block to rotate into position under the read/write head. For a 15,000 rpm (pretty fast) disk, the average rotational
|
||||
delay is 2 msec.\\
|
||||
After that there is actually transferring the data. This is called the block transfer time, which can differ between disks and OSes, but is generally less than
|
||||
the seek time and rotational delay.\\
|
||||
Thus, disk access time = seek time + rotational delay + block transfer time.
|
||||
\end{document}
|
||||
@@ -0,0 +1,75 @@
|
||||
\documentclass{article}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage{enumerate}
|
||||
\usepackage{amsfonts}
|
||||
\usepackage{amsmath, amssymb, textcomp, gensymb}
|
||||
\usepackage[a4paper, total={6in, 8in}]{geometry}
|
||||
\usepackage{graphicx}
|
||||
|
||||
\title{CS 448 Spring 2024 Homework 2}
|
||||
\author{Sean Rettig}
|
||||
|
||||
\begin{document}
|
||||
\maketitle
|
||||
|
||||
\section{}
|
||||
Suppose that each of the following operations is applied directly to the database state shown in
|
||||
the Figure 5.6 and database schema in the Figure 5.7 in the Textbook (7th Edition). The figures
|
||||
are also shown in slides 5-31 and slides 5-37 respectively. Discuss all integrity constraints
|
||||
violated by each operation (including the tables affected), if any, and the different ways to
|
||||
enforce the constraints (without modifying the operation) with some relevant explanation(s). For
|
||||
example, the operation Delete the PROJECT tuple with Pname = 'ProductX' violates a
|
||||
referential integrity constraint with WORKS\_ON. Possible ways to enforce the operation are: (i)
|
||||
reject the delete; (ii) delete cascade (delete all tuples in WORKS\_ON that correspond to Pname
|
||||
= 'ProductX').\\
|
||||
\begin{enumerate} [(a)]
|
||||
\item Delete the WORKS\_ON tuples with Essn = '999887777'.
|
||||
\item Modify the Super\_ssn attribute of the EMPLOYEE tuple with Ssn = '999887777' to NULL.
|
||||
\item Insert tuple $<$'555123456', Phil, 'M', 2000-12-01, 'Son'$>$ into Dependent.
|
||||
\item Delete the DEPT\_LOCATIONS tuples where Dnumber < 3.
|
||||
\end{enumerate}
|
||||
|
||||
\textbf{Answer:}
|
||||
\begin{enumerate} [(a)]
|
||||
\item This operation is acceptable. There are no integrity Constraints that are violated.
|
||||
Referencing Figure 5.6, it deletes two tuples in the WORKED\_ON table.
|
||||
\item This operation is acceptable. There are no integrity constraints that are violated.
|
||||
Referencing Figure 5.6, it modifies a single value of a tuple in the EMPLOYEE table to NULL.
|
||||
\item This insertion violates the referential integrity constraint specified on
|
||||
Essn in DEPENDENT because no corresponding referenced tuple exists in
|
||||
EMPLOYEE with Ssn = 555123456. Possible ways to enforce the operation are: (i) reject the delete;
|
||||
\item This deletion is acceptable. There are no integrity constraints that are violated.
|
||||
Referencing Figure 5.6, it deletes a single tuple in the DEPT\_LOCATIONS table.
|
||||
\end{enumerate}
|
||||
|
||||
\section{}
|
||||
Database design often involves decisions about the storage of attributes. For example, the SSN can
|
||||
be subdivided in groups and stored in multiple attributes for security/validation purpose (validate
|
||||
the last four digits). Another example is the address, which can be stored as a single attribute or
|
||||
split in multiple attributes (City, State, ZIP, Street Address).
|
||||
\begin{enumerate} [(a)]
|
||||
\item Discuss specific scenarios where it is useful to store the address as one attribute (i.e., a
|
||||
text field) or multiple attributes (i.e., separate fields for city, state, zip, number). Explain
|
||||
your answer.
|
||||
\item Discuss at least 2 additional scenarios of information that can benefit of such decisions
|
||||
(split in multiple attributes)? You need to use other examples i.e. other than “Address”
|
||||
and “SSN”. Explain you answer.
|
||||
\end{enumerate}
|
||||
\textbf{Answer:}
|
||||
\begin{enumerate} [(a)]
|
||||
\item Storing an address as a single text field can make information insertion and storage much simpler,
|
||||
since all the user would need to insert is the string with their address, and all that would need to be stored is the string.
|
||||
However, storing multiple attributes like this could be helpful if one needs to gather information about the address. If you wanted to sort
|
||||
all users by city, or state, it would be hard if the address was just a text field instead of split into attributes by city, state, zip, number that
|
||||
you could easily query.
|
||||
\item (1st scenario) A phone number could benefit from being split into multiple attributes. It could consist of the country code of origin,
|
||||
the area code, the telephone prefix, and line number. The first two could be usefull information to use within queries.\\
|
||||
\\
|
||||
(2nd scenario) A Date entry could benefit from being split into multiple attributes. This could allow for further granularity if it
|
||||
allowed an optional NULL valued seconds and nanoseconds, etc. Additionally, if, for example, you wanted to select all within the month of May, it would be easier to grab
|
||||
the month number instead of parsing a string of the date.
|
||||
\end{enumerate}
|
||||
|
||||
|
||||
|
||||
\end{document}
|
||||
@@ -0,0 +1,128 @@
|
||||
import sys
|
||||
|
||||
# Use this file to write your queries. Submit this file in Gradescope after finishing your homework.
|
||||
|
||||
#TODO: Write your username and answer to each query as a string in the return statements in the functions below.
|
||||
# Do not change the function names.
|
||||
|
||||
#Make sure to test that python prints out the strings (your username and SQL queries) correctly.
|
||||
|
||||
#usage:python3 hw1.py
|
||||
# make sure the program prints out your SQL statements correctly. That means the autograder will read you SQL correctly.
|
||||
# Running the Python3 file will not execute your SQL statements (just prints them).
|
||||
|
||||
def username():
|
||||
return "srettig" # Write your username here
|
||||
|
||||
|
||||
def query1():
|
||||
return """
|
||||
SELECT
|
||||
Fname,
|
||||
Minit,
|
||||
Lname
|
||||
FROM
|
||||
cs448_employee ce
|
||||
WHERE
|
||||
(
|
||||
SELECT
|
||||
COUNT(*)
|
||||
FROM
|
||||
cs448_dependent cd
|
||||
WHERE
|
||||
ce.Ssn = cd.Essn
|
||||
) >= 3
|
||||
AND (
|
||||
SELECT
|
||||
SUM(Hours)
|
||||
FROM
|
||||
cs448_works_on cwo
|
||||
WHERE
|
||||
ce.Ssn = cwo.Essn
|
||||
) >= 30;
|
||||
"""
|
||||
|
||||
def query2():
|
||||
return """
|
||||
UPDATE
|
||||
cs448_dept_location
|
||||
Set
|
||||
Dlocation = 'Lafayette'
|
||||
WHERE
|
||||
Dnumber in
|
||||
(
|
||||
SELECT
|
||||
Dnumber
|
||||
From
|
||||
cs448_department cd
|
||||
WHERE
|
||||
(
|
||||
SELECT
|
||||
COUNT(*)
|
||||
FROM
|
||||
cs448_employee ce
|
||||
WHERE
|
||||
cd.Dnumber = ce.Dnumber
|
||||
) < 5)
|
||||
"""
|
||||
|
||||
def query3():
|
||||
return """
|
||||
DELETE
|
||||
FROM
|
||||
cs448_dependent
|
||||
WHERE
|
||||
Essn in
|
||||
(
|
||||
SELECT
|
||||
ce.Ssn
|
||||
From
|
||||
cs448_employee ce,
|
||||
cs448_employee cem
|
||||
WHERE
|
||||
ce.Super_ssn = cem.Ssn
|
||||
AND ce.Dnumber != cem.Dnumber)
|
||||
"""
|
||||
|
||||
def query4():
|
||||
return """
|
||||
SELECT
|
||||
Fname,
|
||||
Minit,
|
||||
Lname
|
||||
From
|
||||
cs448_employee
|
||||
WHERE
|
||||
(Salary,
|
||||
Ssn) IN (
|
||||
SELECT
|
||||
MAX(Salary),
|
||||
Ssn
|
||||
FROM
|
||||
cs448_employee ce2
|
||||
Group BY
|
||||
ce2.Dnumber)
|
||||
"""
|
||||
|
||||
#Do not edit below
|
||||
|
||||
def main():
|
||||
query_options = {1: query1(), 2: query2(), 3: query3(), 4: query4()}
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
if username() == "username":
|
||||
print("Make sure to change the username function to return your username.")
|
||||
return
|
||||
else:
|
||||
print(username())
|
||||
for query in query_options.values():
|
||||
print(query)
|
||||
elif len(sys.argv) == 2:
|
||||
if sys.argv[1] == "username":
|
||||
print(username())
|
||||
else:
|
||||
print(query_options[int(sys.argv[1])])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
After Width: | Height: | Size: 911 KiB |
|
After Width: | Height: | Size: 891 KiB |
|
After Width: | Height: | Size: 784 KiB |
|
After Width: | Height: | Size: 850 KiB |
@@ -0,0 +1,95 @@
|
||||
\documentclass{article}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage{enumitem}
|
||||
\usepackage{amsfonts}
|
||||
\usepackage{amsmath, amssymb, textcomp, gensymb}
|
||||
\usepackage[a4paper, total={6in, 8in}]{geometry}
|
||||
\usepackage{graphicx}
|
||||
|
||||
\title{CS 448 Spring 2024 Homework 3}
|
||||
\author{Sean Rettig}
|
||||
|
||||
\begin{document}
|
||||
\maketitle
|
||||
|
||||
\section{ (1.0 Point)}
|
||||
Specify the following queries in relational algebra (R.A.) on the COMPANY database schema
|
||||
shown in Figure 5.5 in the Textbook. Do not use any other information from the database state
|
||||
on Figure 5.6 to build the queries.
|
||||
\begin{enumerate} [label=(\alph*)]
|
||||
\item List names of employees (Fname, Minit, Lname) who are directly supervised by a female supervisor.
|
||||
\item List names of employees (Fname, Minit, Lname) who are NOT assigned to every project.
|
||||
\item List names of employees (Fname, Minit, Lname) in Departments with locations in Houston or Sugarland.
|
||||
\item List the names of department managers (Fname, Minit, Lname) who have no dependents.
|
||||
\end{enumerate}
|
||||
\textbf{Answer:}\\
|
||||
\begin{enumerate} [label=(\alph*)]
|
||||
\item $\pi_{\text{Fname, Minit, Lname}}(\text{EMPLOYEE}* (\rho_{(\text{Super\_ssn})}(\pi_{\text{Ssn}}(\sigma_{\text{Sex=female}}(\text{EMPLOYEE})))))$
|
||||
\item (EMPLOYEE - (EMPLOYEE $\div \pi_{\text{Pnumber}}(\text{PROJECT})$))
|
||||
\item $\pi_{\text{Fname, Minit, Lname}}($\\
|
||||
$\text{EMPLOYEE}\bowtie_{\text{Dno=Dnumber}} (\sigma_{\text{Dlocation='Houston' OR Dlocation='Sugarland'}}(\text{DEPT\_LOCATIONS}))$\\
|
||||
$)$
|
||||
\item $\pi_{\text{Fname, Minit, Lname}}($\\
|
||||
$(\text{EMPLOYEE}\bowtie_{\text{Ssn=Mgr\_ssn}}(\text{DEPARTMENT})) * (\pi_{\text{Ssn}}(\text{EMPLOYEE}) - \rho_{(\text{Ssn})}(\pi_{\text{Essn}}(\text{DEPENDENT})))$
|
||||
\\ $)$
|
||||
\end{enumerate}
|
||||
|
||||
\section{1.0 Point}
|
||||
Consider SQL queries Q13 and Q4A in Chapter 6.
|
||||
\begin{enumerate} [label=(\alph*)]
|
||||
\item Draw the initial query tree for each of these queries, and then show how the query tree is
|
||||
optimized by the algorithm outlined in Section 19.1.
|
||||
\item For each query, compare the initial query and the final query tree. Discuss the difference
|
||||
between each tree.
|
||||
\end{enumerate}
|
||||
\noindent
|
||||
\textbf{Answer:}\\
|
||||
\textbf{Q13 Unoptimized:}\\
|
||||
\includegraphics[width=0.8\textwidth]{Q13 UNOPT.jpg}\\
|
||||
Step 1 specified a break up of any SELECT operations, and that was used to break up the third to final SELECT operation
|
||||
into multiple cascading SELECT Operations. I used Step 2 and 4 to move the SELECT Operations down as far as they can, as well as combining them
|
||||
with their respective CARTESION PRODUCT into a JOIN operation. I followed Step 3 by moving the most restricive SELECT
|
||||
down to the bottom of the tree. Step 5 was used to move project operations as far down the tree as needed.\\
|
||||
\newpage
|
||||
\textbf{Q13 Optimized:}\\
|
||||
\includegraphics[width=0.8\textwidth]{Q13 OPT.jpg}\\
|
||||
\textbf{Q4A Unoptimized:}\\
|
||||
\includegraphics[width=0.8\textwidth]{Q4A UNOPT.jpg}\\
|
||||
Step 1 specified a break up of any SELECT operations, and that was used to break up the two third to final SELECT operations
|
||||
into multiple cascading SELECT Operations. I used Step 2 and 4 to move the SELECT Operations down as far as they can, as well as combining them
|
||||
with their respective CARTESION PRODUCT into a JOIN operation. I followed Step 3 by moving the most restricive SELECT operations
|
||||
down to the bottom of the tree. Step 5 was used to move project operations as far down the tree as needed.\\
|
||||
\textbf{Q4A Optimized:}\\
|
||||
\includegraphics[width=0.8\textwidth]{Q4A OPT.jpg}
|
||||
|
||||
\newpage
|
||||
\section{1.0 Point}
|
||||
Suppose that a disk unit has the following parameters: seek time s = 20 msec; rotational delay rd
|
||||
= 10 msec; block transfer time btt = 1 msec; block size B = 2400 bytes; interblock gap size G =
|
||||
600 bytes. An EMPLOYEE file has the following fields: Ssn , 9 bytes; Last\_name , 20 bytes;
|
||||
First\_name , 20 bytes; Middle\_init , 1 byte; Birth\_date , 10 bytes; Address , 35 bytes; Phone , 12
|
||||
bytes; Supervisor\_ssn , 9 bytes; Department , 4 bytes; Job\_code , 4 bytes; deletion marker, 1
|
||||
byte. The EMPLOYEE file has r = 30,000 records, fixed-length format, and unspanned blocking.
|
||||
Write appropriate formulas and calculate the following values for the above EMPLOYEE file:
|
||||
|
||||
\begin{enumerate} [label=(\alph*)]
|
||||
\item \textbf{Calculate the record size R (including the deletion marker), the blocking factor bfr, and the number of disk blocks b.}\\
|
||||
Record size:\\
|
||||
Ssn + Last\_name + First\_name + Middle\_init + Birth\_date + Address + Phone + Supervisor\_ssn + Department + Job\_code + deletion marker\\
|
||||
\[= 9 + 20 + 20 + 1 + 10 + 35 + 12 + 9 + 4 + 4 + 1 = 125\text{ bytes}\]
|
||||
$bfr = \lfloor B/R \rfloor = \lfloor 2400 / 125 \rfloor = 19$\\
|
||||
Number of disk blocks required $= \lceil r / bfr \rceil = \lceil 30000 / 19 \rceil = 1579$ blocks
|
||||
\item \textbf{Calculate the wasted space in each disk block because of the unspanned organization.}\\
|
||||
Unused space $= B - (bfr * R) = 2400 - (19 *125) = 25$ bytes
|
||||
\item \textbf{Calculate the transfer rate tr and the bulk transfer rate btr for this disk unit (see Appendix B in the textbook for definitions of tr and btr).}\\
|
||||
$tr = B/btt = 2400 / 1 = 2400$ bytes/msec\\
|
||||
$btr = (B/(B+G)) * tr = (2400/(2400+600)) * 2400 = 1920$ bytes/msec
|
||||
\item \textbf{Calculate the average number of block accesses needed to search for an arbitrary record in the file, using linear search.}\\
|
||||
average block accesses for linear search = $b/2 = 1579 / 2 = 789.5$ blocks
|
||||
\item \textbf{Calculate in msec the average time needed to search for an arbitrary record in the file,
|
||||
using linear search, if the file blocks are stored on consecutive disk blocks and double
|
||||
buffering is used.}\\
|
||||
Average time to search for an arbitrary record = average blocks * average time = $b/2 * (s+rd+(k*B/btr)) = 1579/2 * (20 + 10 +(1579*(2400/1920))) = 1581960.625$ msec
|
||||
\end{enumerate}
|
||||
|
||||
\end{document}
|
||||
@@ -0,0 +1,153 @@
|
||||
\documentclass{article}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage{enumitem}
|
||||
\usepackage{amsfonts}
|
||||
\usepackage{amsmath, amssymb, textcomp, gensymb}
|
||||
\usepackage[a4paper, total={6in, 8in}]{geometry}
|
||||
\usepackage{graphicx}
|
||||
|
||||
\title{CS 448 Spring 2024 Homework 4}
|
||||
\author{Sean Rettig}
|
||||
|
||||
\begin{document}
|
||||
\maketitle
|
||||
|
||||
\section{}
|
||||
Consider the universal relation R = \{A, B, C, D, E, F, G, H, I, J\} and the set of functional
|
||||
dependencies F.\\
|
||||
\\
|
||||
F =\\
|
||||
\\
|
||||
\{\{A, B\}→\{C, D\},\\
|
||||
\{D\}→\{E, F, G\},\\
|
||||
\{F, G\}→\{H\},\\
|
||||
\{A\}→\{I\},\\
|
||||
\{A, B\}→\{E, G\},\\
|
||||
\{A, I\} → \{I, J\}\}
|
||||
|
||||
\begin{enumerate} [label=(\alph*)]
|
||||
\item \textbf{What is the closure of the set \{A, D\}?}\\
|
||||
$\{A, D\}^+ = \{A, D, E, F, G, H, I, J\}$
|
||||
\item \textbf{What is the key for R?}\\
|
||||
Key $= \{A, B\}$, since \{A, B\}'s closure includes all atributes.
|
||||
\item \textbf{What is the minimum cover for the set of functional dependencies F?}\\
|
||||
Convert to canonical form:\\
|
||||
\{\{A, B\}→\{C\},\\
|
||||
\{A, B\}→\{D\},\\
|
||||
\{D\}→\{E\},\\
|
||||
\{D\}→\{F\},\\
|
||||
\{D\}→\{G\},\\
|
||||
\{F, G\}→\{H\},\\
|
||||
\{A\}→\{I\},\\
|
||||
\{A, B\}→\{E\},\\
|
||||
\{A, B\}→\{G\},\\
|
||||
\{A, I\} → \{I\}\\
|
||||
\{A, I\} → \{J\}\}\\
|
||||
Eliminate extraneous stuff:\\
|
||||
\{\{A, B\}→\{C\},\\
|
||||
\{A, B\}→\{D\},\\
|
||||
\{D\}→\{E\},\\
|
||||
\{D\}→\{F\},\\
|
||||
\{D\}→\{G\},\\
|
||||
\{F, G\}→\{H\},\\
|
||||
\{A\}→\{I\},\\
|
||||
\{A, B\}→\{E\},\\
|
||||
\{A, B\}→\{G\},\\
|
||||
\{A\} → \{J\}\}\\
|
||||
Eliminate redundancies:\\
|
||||
\{\{A, B\}→\{C\},\\
|
||||
\{A, B\}→\{D\},\\
|
||||
\{D\}→\{E\},\\
|
||||
\{D\}→\{F\},\\
|
||||
\{D\}→\{G\},\\
|
||||
\{F, G\}→\{H\},\\
|
||||
\{A\}→\{I\},\\
|
||||
\{A\} → \{J\}\}\\
|
||||
|
||||
\item \textbf{Decompose R into 2NF.}\\
|
||||
R = \{A, B, C, D, E, F, G, H, I, J\}\\
|
||||
Split up:\\
|
||||
$R_1$ = \{\underline{A}, \underline{B}, C, D, E, F, G, H\}; $R_2$ = \{\underline{A}, I, J\}\\
|
||||
This is because every nonprime element in $R_1$ is fully functionally dependent on \{A, B\}, and every nonprime element in $R_2$ is fully functionally dependent on $\{A\}$.
|
||||
\item Decompose R into 3NF\\
|
||||
$R_1$ = \{\underline{A}, \underline{B}, C, D\}; $R_2$ = \{\underline{A}, I, J\}; $R_3$ = \{\underline{D}, E, F, G\} $R_4$ = \{\underline{F}, \underline{G}, H\}\\
|
||||
\end{enumerate}
|
||||
|
||||
\newpage
|
||||
\section{}
|
||||
\begin{enumerate} [label=(\alph*)]
|
||||
\item \textbf{What are the possible sources of the information that defines the functional dependencies
|
||||
that hold among the attributes of a relation schema? Discuss two possible sources. Explain your
|
||||
answer.}\\
|
||||
Functional dependencies must be defined explicitely by someone who knows the semantics of the attributes in the relation.
|
||||
So what are some possible sources for these semantics?\\
|
||||
\\
|
||||
A possible source could be the entity that wants to use the database. Lets say its a company that want's to keep track of laptops. Perhaps they have a bunch of attributes that they
|
||||
want to be able to keep track of about the laptops. They can put together the attributes and then make some sort of ID for each laptop that has functional dependencies for the relation.\\
|
||||
\\
|
||||
Another possible source could be some sort of relationship that is already defined in the nature of whatever you are already trying to model. For example, the relationship between a child and their mother.
|
||||
There is a functional dependency from the child to the mother because the child can only have one biological mother while the mother could have multiple children.
|
||||
|
||||
\item \textbf{What is meant by the closure of a set of functional dependencies? Illustrate with an example.}\\
|
||||
The closure of a set of FD really just means that it includes all inferences that can be made from a sparser set of functional dependencies. It's the most explicit you can be about a group of relations.\\
|
||||
For example, if there is a functional dependency between my SSN and me $(A \rightarrow B)$, and also a functional dependency between me and my mother $(B \rightarrow C)$, the closure of the set of those two would also include the functional dependency that can be inferred between my ssn and my mother. $(A \rightarrow C)$.
|
||||
Thus, the closure of the SSN would be $A^+ = \{A, B, C\}$.
|
||||
\item \textbf{What is the lossless (or nonadditive) join property of a decomposition? Why is it important?}\\
|
||||
This property ensures that spurious tuples, or tuples that were not in the original relation before decomposition, do not appear after rejoining the relations.\\
|
||||
This is important so we can complete the normalization of the data and relations without losing information. We need the benefits that come with normalizing relations, but we cannot sacrifice data to achieve it.
|
||||
\end{enumerate}
|
||||
|
||||
\newpage
|
||||
\section{}
|
||||
Consider the following four schedules for transactions T1, T2 and T3:
|
||||
\begin{enumerate} [label=\alph*]
|
||||
\item r1(X); r3(X); w1(X); r2(X); w3(X); w2(X)
|
||||
\item r1(Y); r3(Y); w3(X); w1(X); r2(X); w2(Y)
|
||||
\item w2(X); r1(Y); w2(Y); r2(X); w2(Y); r3(Y)
|
||||
\item r3(X); r2(X); w3(X); r1(Y); w1(X); r2(Y)
|
||||
\item r3(X); r2(X); r1(X); w3(X); w1(X); w2(X)
|
||||
\end{enumerate}
|
||||
\begin{enumerate} [label=(\alph*)]
|
||||
\item For each schedule, specify whether or not the schedule is conflict serializable and why. To
|
||||
determine if a schedule is conflict serializable you can either use the precedence graph or swap
|
||||
conflicting operations.
|
||||
\item Then, for each serializable schedule, give the equivalent serial schedule.
|
||||
\end{enumerate}
|
||||
\hrule
|
||||
\begin{enumerate} [label=(\alph*)]
|
||||
\item \textbf{r1(X); r3(X); w1(X); r2(X); w3(X); w2(X)}\\
|
||||
Not-Serializable. There is a cycle between $T_1$ and $T_3$ in the precedence graph.\\
|
||||
\includegraphics[width=0.5\linewidth]{pred_graph_a.jpg}
|
||||
\item \textbf{r1(Y); r3(Y); w3(X); w1(X); r2(X); w2(Y)}\\
|
||||
Serializable.\\
|
||||
r3(Y); w3(X); r1(Y); w1(X); r2(X); w2(Y)\\
|
||||
\includegraphics[width=0.5\linewidth]{pred_graph_b.jpg}
|
||||
\item \textbf{w2(X); r1(Y); w2(Y); r2(X); w2(Y); r3(Y)}\\
|
||||
Serializable.\\
|
||||
r1(Y); w2(X); w2(Y); r2(X); w2(Y); r3(Y)\\
|
||||
\includegraphics[width=0.5\linewidth]{pred_graph_c.jpg}
|
||||
\item \textbf{r3(X); r2(X); w3(X); r1(Y); w1(X); r2(Y)}\\
|
||||
Serializable.\\
|
||||
r2(X); r2(Y); r3(X); w3(X); r1(Y); w1(X)\\
|
||||
\includegraphics[width=0.5\linewidth]{pred_graph_d.jpg}
|
||||
\item \textbf{r3(X); r2(X); r1(X); w3(X); w1(X); w2(X)}\\
|
||||
Not-Serializable. There is a cycle between all edges in the precedence graph.\\
|
||||
\includegraphics[width=0.5\linewidth]{pred_graph_e.jpg}
|
||||
\end{enumerate}
|
||||
\newpage
|
||||
\section{(0.75 points)}
|
||||
Consider the following actions taken by transaction T1 on a database with objects X and Y:\\
|
||||
\textbf{R1(X), W1(X), R1(Y), W1(Y)}\\
|
||||
Without altering the order of operations of T1, give example schedules with an additional
|
||||
Transactions T2 (with 4 operations accessing both database objects X and Y) that fulfill the
|
||||
following conditions:\\
|
||||
\begin{enumerate} [label=(\alph*)]
|
||||
\item \textbf{Give an example schedule using two transactions (T1 and T2) which is conflict serializable.}\\
|
||||
w2(X); r1(X); r2(Y); w2(Y); r2(X); w1(X); r1(Y); w1(Y)\\
|
||||
The precedence graph shows no cycles.
|
||||
\item \textbf{Give an example schedule using two transactions (T1 and T2) which is not conflict serializable. Explain why the schedule is not conflict serializable.}\\
|
||||
w2(X); r1(X); r2(Y); w2(Y); w1(X); r2(X); r1(Y); w1(Y)\\
|
||||
The precedence graph has a cycle between $T_1$ and $T_2$. $T_1$ writes before $T_2$ reads, but $T_2$ has already written before $T_1$.
|
||||
\end{enumerate}
|
||||
|
||||
\end{document}
|
||||
|
After Width: | Height: | Size: 191 KiB |
|
After Width: | Height: | Size: 302 KiB |
|
After Width: | Height: | Size: 328 KiB |
|
After Width: | Height: | Size: 359 KiB |
|
After Width: | Height: | Size: 361 KiB |
@@ -0,0 +1,18 @@
|
||||
\documentclass{article}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage{enumitem}
|
||||
\usepackage{amsfonts}
|
||||
\usepackage{amsmath, amssymb, textcomp, gensymb}
|
||||
\usepackage[a4paper, total={6in, 8in}]{geometry}
|
||||
\usepackage{graphicx}
|
||||
|
||||
\title{CS 448 Spring 2024 Homework 5}
|
||||
\author{Sean Rettig}
|
||||
|
||||
\begin{document}
|
||||
\maketitle
|
||||
|
||||
\section{}
|
||||
|
||||
|
||||
\end{document}
|
||||
@@ -0,0 +1,24 @@
|
||||
# 1/9/24
|
||||
Claude Shannon? came up with theory of information. You are looking for information and knowledge
|
||||
|
||||
You want to integrate all the data. Some centralized warehouse. Utilities to access the data. Queries to let you get the data you care about.
|
||||
|
||||
# 1/11/24
|
||||
Additional DBMS functionality
|
||||
- Temporal database as well
|
||||
|
||||
|
||||
#### Data Abstraction
|
||||
- A data model
|
||||
- Can store as a table
|
||||
- can store as a tree
|
||||
- or a network
|
||||
- Used to hide storage details and present the users with a conceptual view of the database
|
||||
|
||||
|
||||
|
||||
|
||||
# 1/16/24
|
||||
How you store the data is independent from how you access the data.
|
||||
|
||||
the very first database model was called the entity relationship model
|
||||
@@ -0,0 +1,17 @@
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
# Eclipse m2e generated files
|
||||
# Eclipse Core
|
||||
.project
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
.classpath
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "java",
|
||||
"name": "test",
|
||||
"request": "launch",
|
||||
"mainClass": "test",
|
||||
"projectName": "cs448p1"
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "Current File",
|
||||
"request": "launch",
|
||||
"mainClass": "${file}"
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "App",
|
||||
"request": "launch",
|
||||
"mainClass": "cs448.App",
|
||||
"projectName": "cs448p1",
|
||||
"args": "./data_30MB.tsv 2 nm0000001"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"java.compile.nullAnalysis.mode": "disabled"
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Maven: org.mapdb:mapdb:3.0.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib:1.2.71" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-common:1.2.71" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.jetbrains:annotations:13.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.collections:eclipse-collections-api:10.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.collections:eclipse-collections:10.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.collections:eclipse-collections-forkjoin:10.0.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.guava:guava:28.0-jre" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.guava:failureaccess:1.0.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.code.findbugs:jsr305:3.0.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.checkerframework:checker-qual:2.8.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.errorprone:error_prone_annotations:2.3.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.j2objc:j2objc-annotations:1.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.codehaus.mojo:animal-sniffer-annotations:1.17" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.jpountz.lz4:lz4:1.3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.mapdb:elsa:3.0.0-M5" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.11" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,10 @@
|
||||
nconst primaryName birthYear deathYear primaryProfession knownForTitles
|
||||
nm0000001 Fred Astaire 1899 1987 soundtrack,actor,miscellaneous tt0072308,tt0053137,tt0043044,tt0050419
|
||||
nm0000002 Lauren Bacall 1924 2014 actress,soundtrack tt0071877,tt0037382,tt0038355,tt0117057
|
||||
nm0000003 Brigitte Bardot 1934 \N actress,soundtrack,producer tt0054452,tt0049189,tt0059956,tt0057345
|
||||
nm0000004 John Belushi 1949 1982 actor,writer,soundtrack tt0078723,tt0072562,tt0077975,tt0080455
|
||||
nm0000005 Ingmar Bergman 1918 2007 writer,director,actor tt0083922,tt0050976,tt0050986,tt0060827
|
||||
nm0000006 Ingrid Bergman 1915 1982 actress,soundtrack,producer tt0034583,tt0071877,tt0038787,tt0038109
|
||||
nm0000007 Humphrey Bogart 1899 1957 actor,soundtrack,producer tt0033870,tt0034583,tt0037382,tt0043265
|
||||
nm0000008 Marlon Brando 1924 2004 actor,soundtrack,director tt0047296,tt0078788,tt0068646,tt0070849
|
||||
nm0000009 Richard Burton 1925 1984 actor,producer,soundtrack tt0059749,tt0061184,tt0057877,tt0087803
|
||||
|
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>edu.cs.purdue</groupId>
|
||||
<artifactId>cs448p1</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<name>cs448p1</name>
|
||||
<!-- FIXME change it to the project's website -->
|
||||
<url>http://www.example.com</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.7</maven.compiler.source>
|
||||
<maven.compiler.target>1.7</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- https://mvnrepository.com/artifact/org.mapdb/mapdb -->
|
||||
<dependency>
|
||||
<groupId>org.mapdb</groupId>
|
||||
<artifactId>mapdb</artifactId>
|
||||
<version>3.0.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
|
||||
<plugins>
|
||||
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
</plugin>
|
||||
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.7.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>cs448.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,54 @@
|
||||
package cs448;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class App
|
||||
{
|
||||
public static void main( String[] args )
|
||||
{
|
||||
String input_file_path = args[0];
|
||||
int backend = Integer.parseInt(args[1]);
|
||||
String id = args[2];
|
||||
project1 p = new project1();
|
||||
long startts;
|
||||
String[] column_names = {"nconst", "primaryName", "birthYear", "deathYear", "primaryProfession", "knownForTitles"};
|
||||
try {
|
||||
switch (backend){
|
||||
case 0:
|
||||
startts = System.nanoTime();
|
||||
System.out.println(p.select_file(input_file_path,id,column_names));
|
||||
System.out.println("Elapsed time in (ns): "+(System.nanoTime()-startts));
|
||||
break;
|
||||
case 1:
|
||||
startts = System.nanoTime();
|
||||
p.load_mainmemory(input_file_path);
|
||||
System.out.println("Load: elapsed time in (ns): "+(System.nanoTime()-startts));
|
||||
startts = System.nanoTime();
|
||||
System.out.println(p.select_mainmemory(id,column_names));
|
||||
System.out.println("Query: elapsed time in (ns): "+(System.nanoTime()-startts));
|
||||
break;
|
||||
case 2:
|
||||
startts = System.nanoTime();
|
||||
p.load_mapdb(input_file_path);
|
||||
System.out.println("Load: elapsed time in (ns): "+(System.nanoTime()-startts));
|
||||
startts = System.nanoTime();
|
||||
System.out.println(p.select_mapdb(id,column_names));
|
||||
System.out.println("Query: elapsed time in (ns): "+(System.nanoTime()-startts));
|
||||
break;
|
||||
default:
|
||||
System.out.println("Syntax: project1 path/to/datafile 0|1|2 id");
|
||||
}
|
||||
}
|
||||
catch(IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (OutOfMemoryError e){
|
||||
System.gc();
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
p.db.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package cs448;
|
||||
|
||||
import org.mapdb.DB;
|
||||
import org.mapdb.DBMaker;
|
||||
import org.mapdb.Serializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.io.File;
|
||||
import java.lang.StringBuilder;
|
||||
|
||||
/**
|
||||
* A class to compare different storage backends.
|
||||
*
|
||||
* @author Sean Rettig
|
||||
* @version January 22, 2024
|
||||
*/
|
||||
|
||||
|
||||
public class project1 {
|
||||
|
||||
/* Data structure for Main-memory back-end */
|
||||
HashMap<String,Dictionary<String, String>> mm_map = new HashMap<String,Dictionary<String, String>>();
|
||||
|
||||
/* Data structure for MapDB persistent storage*/
|
||||
String dbfile = "data.db";
|
||||
DB db = DBMaker.fileDB(dbfile).make();
|
||||
|
||||
// use this for MapDB storage
|
||||
ConcurrentMap mapdb = db.hashMap("map").make();
|
||||
|
||||
void load_mainmemory(String file_path) throws IOException {
|
||||
Scanner sc = new Scanner((new File(file_path)));
|
||||
String line = "";
|
||||
|
||||
while (sc.hasNextLine()) {
|
||||
line = sc.nextLine();
|
||||
String[] row = line.split("\t");
|
||||
|
||||
Dictionary<String, String> row_dict = new Hashtable<>();
|
||||
|
||||
row_dict.put("primaryName", row[1]);
|
||||
row_dict.put("birthYear", row[2]);
|
||||
row_dict.put("deathYear", row[3]);
|
||||
row_dict.put("primaryProfession", row[4]);
|
||||
row_dict.put("knownForTitles", row[5]);
|
||||
|
||||
mm_map.put(row[0], row_dict);
|
||||
}
|
||||
}
|
||||
|
||||
void load_mapdb(String file_path) throws IOException{
|
||||
Scanner sc = new Scanner((new File(file_path)));
|
||||
String line = "";
|
||||
|
||||
while (sc.hasNextLine()) {
|
||||
line = sc.nextLine();
|
||||
String[] row = line.split("\t");
|
||||
|
||||
Dictionary<String, String> row_dict = new Hashtable<>();
|
||||
|
||||
row_dict.put("primaryName", row[1]);
|
||||
row_dict.put("birthYear", row[2]);
|
||||
row_dict.put("deathYear", row[3]);
|
||||
row_dict.put("primaryProfession", row[4]);
|
||||
row_dict.put("knownForTitles", row[5]);
|
||||
|
||||
mapdb.put(row[0], row_dict);
|
||||
}
|
||||
}
|
||||
|
||||
String select_file(String file_path, String key, String[] column_names) throws IOException{
|
||||
Scanner sc = new Scanner(new File(file_path));
|
||||
String line = "";
|
||||
|
||||
while (sc.hasNextLine()) {
|
||||
line = sc.nextLine();
|
||||
if (line.contains(key)) {
|
||||
sc.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (line != "") {
|
||||
String[] row = line.split("\t");
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String col_name : column_names) {
|
||||
switch (col_name) {
|
||||
case "nconst":
|
||||
sb.append(row[0]);
|
||||
break;
|
||||
|
||||
case "primaryName":
|
||||
sb.append(row[1]);
|
||||
break;
|
||||
|
||||
case "birthYear":
|
||||
sb.append(row[2]);
|
||||
break;
|
||||
|
||||
case "deathYear":
|
||||
sb.append(row[3]);
|
||||
break;
|
||||
|
||||
case "primaryProfession":
|
||||
sb.append(row[4]);
|
||||
break;
|
||||
|
||||
case "knownForTitles":
|
||||
sb.append(row[5]);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sb.append("\t");
|
||||
}
|
||||
line = sb.toString();
|
||||
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
String select_mainmemory(String key, String[] column_names){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Dictionary<String, String> data = mm_map.get(key);
|
||||
for (String col_name : column_names) {
|
||||
if (col_name == "nconst") {
|
||||
sb.append(key);
|
||||
} else {
|
||||
sb.append(data.get(col_name));
|
||||
}
|
||||
sb.append("\t");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
String select_mapdb(String key, String[] column_names){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Dictionary<String, String> data = (Dictionary<String, String>) mapdb.get(key);
|
||||
for (String col_name : column_names) {
|
||||
if (col_name == "nconst") {
|
||||
sb.append(key);
|
||||
} else {
|
||||
sb.append(data.get(col_name));
|
||||
}
|
||||
sb.append("\t");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
int fastestLoad(){
|
||||
// 1: Main-memory Load
|
||||
// 2: MapDB Load
|
||||
int fastest = 1;
|
||||
return fastest;
|
||||
}
|
||||
|
||||
int fastestSelect(){
|
||||
// 0: File Select
|
||||
// 1: Main-memory Select
|
||||
// 2: MapDB Select
|
||||
int fastest = 1;
|
||||
return fastest;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>edu.cs.purdue</groupId>
|
||||
<artifactId>cs448p2</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<name>cs448p2</name>
|
||||
<url>https://www.cs.purdue.edu/homes/bb/cs448f19/</url>
|
||||
|
||||
<properties>
|
||||
<java.version>10</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- https://mvnrepository.com/artifact/org.mapdb/mapdb -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>minibase</groupId>
|
||||
<artifactId>bufmgr-project</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${basedir}/lib/bufmgrAssign.jar</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
|
||||
<plugins>
|
||||
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<configuration>
|
||||
<release>${java.version}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
</plugin>
|
||||
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.7.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>test.TestDriver</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,314 @@
|
||||
package bufmgr;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
|
||||
import diskmgr.DiskMgrException;
|
||||
import global.Minibase;
|
||||
import global.Page;
|
||||
import global.PageId;
|
||||
|
||||
/**
|
||||
* <h3>Minibase Buffer Manager</h3>
|
||||
* The buffer manager reads disk pages into a main memory page as needed. The
|
||||
* collection of main memory pages (called frames) used by the buffer manager
|
||||
* for this purpose is called the buffer pool. This is just an array of Page
|
||||
* objects. The buffer manager is used by access methods, heap files, and
|
||||
* relational operators to read, write, allocate, and de-allocate pages.
|
||||
*/
|
||||
public class BufMgr {
|
||||
|
||||
// INSTANCE VARIABLES
|
||||
// Some of these are accessed during the test cases
|
||||
// DO NOT CHANGE THE BELOW INSTANCE VARIABLE NAMES - you should use them as appropriate in your code
|
||||
// You may add additional ones as you need to
|
||||
|
||||
/** bufPool: the buffer pool. An array of Page objects */
|
||||
private Page[] bufPool = null;
|
||||
|
||||
/** frmDescr: An arracy of FrameDescriptor objects, holding information about the contents of each frame. */
|
||||
private FrameDescriptor[] frmDescr = null;
|
||||
|
||||
/** numOfFrames: the number of frames used for the maximum capacity of the buffer pool */
|
||||
private int numOfFrames = -1;
|
||||
|
||||
/** replacementPolicy: will be set to FIFO when the constructor is called. */
|
||||
private static String replacementPolicy = "FIFO";
|
||||
|
||||
/** map: Hash table to track which frame in the buffer a page is in <Key: PageID, Value: Frame> */
|
||||
private Map<Integer, Integer> pageMap = new HashMap<>();
|
||||
//
|
||||
|
||||
/** fifo: queue for FIFO page replacement. All unpinned pages will be stored here, with the first element being
|
||||
* the pageID that was unpinned the longest time ago */
|
||||
private Queue<Integer> fifo = new LinkedList<>();
|
||||
|
||||
// END OF REQUIRED INSTANCE VARIABLES
|
||||
|
||||
/**
|
||||
* Resets a FrameDescriptor to the default values with no pageID
|
||||
*/
|
||||
protected void resetFrameDescriptor(int frameId) {
|
||||
resetFrameDescriptor(frameId, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a FrameDescriptor to the default values with the given pageID
|
||||
*/
|
||||
protected void resetFrameDescriptor(int frameId, int pageno) {
|
||||
frmDescr[frameId].pageno = pageno;
|
||||
frmDescr[frameId].pinCount = 0;
|
||||
frmDescr[frameId].dirtyBit = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the BufMgr object. Allocate pages (frames) for the buffer pool in main
|
||||
* memory and make the buffer manage aware that the replacement policy is
|
||||
* specified by replacerArg (e.g., LH, Clock, LRU, MRU, LIRS, etc.).
|
||||
*
|
||||
* @param numbufs
|
||||
* number of buffers in the buffer pool
|
||||
* @param lookAheadSize
|
||||
* number of pages to be looked ahead - can be ignored for this assignment
|
||||
* @param replacementPolicy
|
||||
* Name of the replacement policy
|
||||
*/
|
||||
public BufMgr(int numbufs, int lookAheadSize, String replacementPolicy) {
|
||||
// we ignore replacementPolicy as there is only one policy implemented in the
|
||||
// system
|
||||
numOfFrames = numbufs;
|
||||
bufPool = new Page[numOfFrames];
|
||||
frmDescr = new FrameDescriptor[numOfFrames];
|
||||
this.replacementPolicy = replacementPolicy;
|
||||
for (int i = 0; i < numOfFrames; i++) {
|
||||
bufPool[i] = new Page();
|
||||
frmDescr[i] = new FrameDescriptor();
|
||||
resetFrameDescriptor(i, -1);
|
||||
fifo.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pin a page. First check if this page is already in the buffer pool. If it is,
|
||||
* increment the pin_count and return a pointer to this page. If the pin_count
|
||||
* was 0 before the call, the page was a replacement candidate, but is no longer
|
||||
* a candidate. If the page is not in the pool, choose a frame (from the set of
|
||||
* replacement candidates) to hold this page, read the page (using the
|
||||
* appropriate method from diskmgr package) and pin it. Also, must write out the
|
||||
* old page in chosen frame if it is dirty before reading new page.(You can
|
||||
* assume that emptyPage==false for this assignment.)
|
||||
*
|
||||
* @param pageno
|
||||
* page number in the Minibase.
|
||||
* @param page
|
||||
* the pointer point to the page.
|
||||
* @throws BufferPoolExceededException if there are no valid replacement candidates when attempting to pin a page not already in memory
|
||||
* @throws DiskMgrException if there is an error from the DiskMgr layer. This is likely caused by incorrect implementations of other methods in the BufferManager
|
||||
*/
|
||||
public void pinPage(PageId pageno, Page page, boolean emptyPage)
|
||||
throws BufferPoolExceededException, DiskMgrException {
|
||||
//Check if page already in memory
|
||||
if (pageMap.containsKey(pageno.pid)) {
|
||||
// page is already in memory
|
||||
Integer frameno = pageMap.get(pageno.pid);
|
||||
frmDescr[frameno].pinCount++;
|
||||
|
||||
if (frmDescr[frameno].pinCount == 1) {
|
||||
//the frame was marked previously removal, we need to undo that.
|
||||
fifo.remove(frameno);
|
||||
}
|
||||
page.setPage(bufPool[frameno]);
|
||||
} else {
|
||||
if (fifo.size() > 0) {
|
||||
// there is a page that can be removed
|
||||
Integer frameno = fifo.remove();
|
||||
if (frmDescr[frameno].pageno != -1) {
|
||||
// the frame is not empty
|
||||
PageId oldPage = new PageId(frmDescr[frameno].pageno);
|
||||
pageMap.remove(oldPage.pid);
|
||||
if (frmDescr[frameno].dirtyBit) {
|
||||
// the page has been written to, and needs to be written to disk
|
||||
Minibase.DiskManager.write_page(oldPage, bufPool[frameno]);
|
||||
}
|
||||
}
|
||||
// we now have an empty frame in frameno
|
||||
// we can grab the new page
|
||||
Minibase.DiskManager.read_page(pageno, bufPool[frameno]);
|
||||
page.setPage(bufPool[frameno]);
|
||||
pageMap.put(pageno.pid, frameno);
|
||||
resetFrameDescriptor(frameno, pageno.pid);
|
||||
frmDescr[frameno].pinCount++;
|
||||
} else {
|
||||
throw new BufferPoolExceededException("All pages in the buffer pool are pinned.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpin a page specified by a pageId. This method should be called with
|
||||
* dirty==true if the client has modified the page. If so, this call should set
|
||||
* the dirty bit for this frame. Further, if pin_count>0, this method should
|
||||
* decrement it. If pin_count=0 before this call, throw an exception to report
|
||||
* error. (For testing purposes, we ask you to throw an exception named
|
||||
* PageUnpinnedException in case of error.)
|
||||
*
|
||||
* @param pageno
|
||||
* the PageID of the page
|
||||
* @param dirty
|
||||
* whether or not the page is dirty
|
||||
* @throws PageNotFoundException the page is not in memory
|
||||
* @throws PageUnpinnedException the page is already unpinned
|
||||
*/
|
||||
public void unpinPage(PageId pageno, boolean dirty)
|
||||
throws PageNotFoundException, PageUnpinnedException {
|
||||
if (!pageMap.containsKey(pageno.pid)) {
|
||||
throw new PageNotFoundException("the page is not in memory");
|
||||
}
|
||||
Integer frameno = pageMap.get(pageno.pid);
|
||||
|
||||
if (frmDescr[frameno].pinCount > 0) {
|
||||
frmDescr[frameno].pinCount--;
|
||||
if (frmDescr[frameno].pinCount == 0) {
|
||||
//add to fifo
|
||||
fifo.add(frameno);
|
||||
}
|
||||
} else {
|
||||
throw new PageUnpinnedException("the page is already unpinned");
|
||||
}
|
||||
|
||||
if (dirty) {
|
||||
frmDescr[frameno].dirtyBit = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate new pages. Call DB object to allocate a run of new pages and find a
|
||||
* frame in the buffer pool for the first page and pin it. (This call allows a
|
||||
* client of the Buffer Manager to allocate pages on disk.) If buffer is full,
|
||||
* i.e., you can't find a frame for the first page, ask DB to deallocate all
|
||||
* these pages, and return null.
|
||||
*
|
||||
* @param firstpage
|
||||
* the address of the first page.
|
||||
* @param howmany
|
||||
* total number of allocated new pages.
|
||||
*
|
||||
* @return the first page id of the new pages.__ null, if error.
|
||||
* @throws DiskMgrException if there is an error from the DiskMgr layer. This is likely caused by incorrect implementations of other methods of the Buffer Manager
|
||||
* @throws BufferPoolExceededException if the new page cannot be pinned after the run is allocated due to the buffer being full. If this exception is thrown, the newly allocated pages should be deallocated
|
||||
*/
|
||||
public PageId newPage(Page firstpage, int howmany) throws DiskMgrException, BufferPoolExceededException {
|
||||
PageId nPage = null;
|
||||
|
||||
try {
|
||||
nPage = Minibase.DiskManager.allocate_page(howmany);
|
||||
|
||||
pinPage(nPage, firstpage, false);
|
||||
return nPage;
|
||||
|
||||
} catch (BufferPoolExceededException bee) {
|
||||
try {
|
||||
if (nPage != null){
|
||||
Minibase.DiskManager.deallocate_page(nPage, howmany);
|
||||
}
|
||||
} catch (BufMgrException be) {
|
||||
throw new DiskMgrException("Exception in deallocating page.");
|
||||
}
|
||||
throw bee;
|
||||
} catch (BufMgrException be) {
|
||||
throw new DiskMgrException("Exception in allocating page.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called to delete a page that is on disk. This routine
|
||||
* must call the method in diskmgr package to deallocate the page.
|
||||
*
|
||||
* @param pageno
|
||||
* the page number in the data base.
|
||||
* @throws PagePinnedException if the page is still pinned
|
||||
* @throws DiskMgrException if there is an error in the DiskMgr layer. This is likely caused by incorrect implementations in other methods of the Buffer Manager
|
||||
*/
|
||||
public void freePage(PageId pageno) throws PagePinnedException, DiskMgrException {
|
||||
if (pageMap.containsKey(pageno.pid)) {
|
||||
Integer frameno = pageMap.get(pageno.pid);
|
||||
if (frmDescr[frameno].pinCount > 0) {
|
||||
throw new PagePinnedException("The page is still pinned!");
|
||||
} else {
|
||||
pageMap.remove(pageno.pid);
|
||||
resetFrameDescriptor(frameno);
|
||||
// bufPool[frameno] = new Page();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to flush a particular page of the buffer pool to disk. This method calls
|
||||
* the write_page method of the diskmgr package.
|
||||
*
|
||||
* @param pageid
|
||||
* the page number in the database.
|
||||
* @throws PageNotFoundException if the page is not in memory
|
||||
* @throws DiskMgrException if there is an error in the DiskMgr layer. This is likely caused by incorrect implementations in other methods of the Buffer Manager
|
||||
*/
|
||||
public void flushPage(PageId pageid) throws PageNotFoundException, DiskMgrException {
|
||||
// find the frame holding that page
|
||||
Integer frameId = pageMap.get(pageid.pid);
|
||||
if (frameId == null) {
|
||||
throw new PageNotFoundException(
|
||||
"BufMgr.flushPage: Page with id " + pageid.pid + " does not exist in the buffer bool.");
|
||||
} else {
|
||||
Minibase.DiskManager.write_page(pageid, bufPool[frameId]);
|
||||
frmDescr[frameId].dirtyBit = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to flush all dirty pages in the buffer pool to disk
|
||||
* @throws DiskMgrException if there is an error in the DiskMgr layer. This is likely caused by incorrect implementations in other methods of the Buffer Manager
|
||||
*/
|
||||
public void flushAllPages() throws DiskMgrException {
|
||||
for (int i = 0; i < numOfFrames; i++) {
|
||||
if (frmDescr[i].dirtyBit == true) {
|
||||
Minibase.DiskManager.write_page(new PageId(frmDescr[i].pageno), bufPool[i]);
|
||||
frmDescr[i].dirtyBit = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of buffer frames.
|
||||
*/
|
||||
public int getNumBuffers() {
|
||||
return numOfFrames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of unpinned buffer frames.
|
||||
*/
|
||||
public int getNumUnpinned() {
|
||||
int numUnpinned = 0;
|
||||
for (int i = 0; i < numOfFrames; i++) {
|
||||
if (frmDescr[i].pinCount <= 0) {
|
||||
numUnpinned++;
|
||||
}
|
||||
}
|
||||
return numUnpinned;
|
||||
}
|
||||
|
||||
//*** DO NOT CHANGE ANY EXISTING METHODS BELOW THIS LINE ***
|
||||
// Accessor methods for use in test cases
|
||||
public FrameDescriptor getFrameDesc(int frameNum) {
|
||||
return frmDescr[frameNum];
|
||||
}
|
||||
|
||||
public Page getPageFromFrame(int frameNum) {
|
||||
return bufPool[frameNum];
|
||||
}
|
||||
|
||||
public Integer getFrameFromPage(PageId pid) {
|
||||
return pageMap.get(new Integer(pid.pid));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package bufmgr;
|
||||
|
||||
public class BufMgrException extends Throwable
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -53906392083428894L;
|
||||
|
||||
public BufMgrException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package bufmgr;
|
||||
|
||||
public class BufferPoolExceededException extends BufMgrException
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -3879729988119933114L;
|
||||
|
||||
public BufferPoolExceededException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package bufmgr;
|
||||
|
||||
/**
|
||||
* A frame descriptor; contains info about each page in the buffer pool.
|
||||
*/
|
||||
public class FrameDescriptor
|
||||
{
|
||||
/** Identifies the frame's page. */
|
||||
public int pageno = -1;
|
||||
|
||||
/** The frame's pin count. */
|
||||
public int pinCount;
|
||||
|
||||
/** The frame's dirty status. */
|
||||
public boolean dirtyBit;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package bufmgr;
|
||||
|
||||
public class PageNotFoundException extends BufMgrException
|
||||
{
|
||||
|
||||
public PageNotFoundException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 8527332129053870174L;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package bufmgr;
|
||||
|
||||
public class PagePinnedException extends BufMgrException
|
||||
{
|
||||
|
||||
public PagePinnedException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 2891505249472036297L;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package bufmgr;
|
||||
|
||||
public class PageUnpinnedException extends BufMgrException
|
||||
{
|
||||
|
||||
public PageUnpinnedException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 8366005988643934461L;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package diskmgr;
|
||||
|
||||
public class DiskMgrException extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -6796603846181216651L;
|
||||
|
||||
public DiskMgrException(String name)
|
||||
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package diskmgr;
|
||||
|
||||
public class DuplicateEntryException extends DiskMgrException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -7360431299339776190L;
|
||||
|
||||
public DuplicateEntryException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package diskmgr;
|
||||
|
||||
public class FileEntryNotFoundException extends DiskMgrException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -5657953921202448803L;
|
||||
|
||||
public FileEntryNotFoundException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package diskmgr;
|
||||
|
||||
public class FileIOException extends DiskMgrException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 6320388561056052984L;
|
||||
|
||||
public FileIOException(String msg)
|
||||
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package diskmgr;
|
||||
|
||||
public class FileNameTooLongException extends DiskMgrException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -4115614718485246811L;
|
||||
|
||||
public FileNameTooLongException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package diskmgr;
|
||||
|
||||
public class InvalidPageNumberException extends DiskMgrException {
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 5106265663568991693L;
|
||||
|
||||
public InvalidPageNumberException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package diskmgr;
|
||||
|
||||
public class InvalidRunSizeException extends DiskMgrException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1663588077268780074L;
|
||||
|
||||
public InvalidRunSizeException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package diskmgr;
|
||||
|
||||
public class OutOfSpaceException extends DiskMgrException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 2560165916249758898L;
|
||||
|
||||
public OutOfSpaceException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,952 @@
|
||||
package tests;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import bufmgr.*;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
|
||||
import diskmgr.DiskMgrException;
|
||||
import diskmgr.OutOfSpaceException;
|
||||
import global.Convert;
|
||||
import global.GlobalConst;
|
||||
import global.Minibase;
|
||||
import global.Page;
|
||||
import global.PageId;
|
||||
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class BMTest implements GlobalConst {
|
||||
|
||||
public final static boolean OK = true;
|
||||
public final static boolean FAIL = false;
|
||||
|
||||
/** Default database size (in pages). */
|
||||
private final static int DB_SIZE = 10000;
|
||||
|
||||
/** Default buffer pool size (in pages) */
|
||||
private final static int BUF_SIZE = 100;
|
||||
|
||||
/** Default number of pages to be looked ahead */
|
||||
private final static int LAH_SIZE = 10;
|
||||
|
||||
// Filepaths
|
||||
private static String dbpath;
|
||||
private static String logpath;
|
||||
private static final String REMOVE_CMD = "/bin/rm -rf ";
|
||||
private static String remove_logcmd;
|
||||
private static String remove_dbcmd;
|
||||
|
||||
// Instance variables for tests
|
||||
private static int numPages;
|
||||
|
||||
private static Page pg;
|
||||
private static PageId pid, first_pid, last_pid;
|
||||
|
||||
private void checkFDContents(FrameDescriptor fd, int pgid, int pinCount, boolean dirty) {
|
||||
String failmsg = "Failed: - ";
|
||||
boolean passed = true;
|
||||
if (fd.pageno != pgid) {
|
||||
failmsg += "FD pagenumber: " + fd.pageno + ", should be " + pgid + " - ";
|
||||
passed = false;
|
||||
}
|
||||
if (fd.pinCount != pinCount) {
|
||||
failmsg += "FD pincount: " + fd.pinCount + ", should be " + pinCount + " - ";
|
||||
passed = false;
|
||||
}
|
||||
if (fd.dirtyBit != dirty) {
|
||||
failmsg += "Fd dirty bit: " + fd.dirtyBit + ", should be " + dirty;
|
||||
passed = false;
|
||||
}
|
||||
assertTrue(failmsg, passed);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpBeforeClass() throws Exception {
|
||||
|
||||
// Set up remove commands and ensure nothing's left over
|
||||
String remove_cmd = "/bin/rm -rf ";
|
||||
|
||||
dbpath = "/tmp/" + System.getProperty("user.name") + ".minibase-db";
|
||||
logpath = "/tmp/" + System.getProperty("user.name") + ".minibase-log";
|
||||
|
||||
remove_logcmd = REMOVE_CMD + logpath;
|
||||
remove_dbcmd = REMOVE_CMD + dbpath;
|
||||
|
||||
// Commands here is very machine dependent. We assume
|
||||
// user are on UNIX system here
|
||||
try {
|
||||
Runtime.getRuntime().exec(remove_logcmd);
|
||||
Runtime.getRuntime().exec(remove_dbcmd);
|
||||
} catch (IOException e) {
|
||||
System.err.println("" + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
new Minibase(dbpath, DB_SIZE, BUF_SIZE, LAH_SIZE, "FIFO", false);
|
||||
|
||||
numPages = Minibase.BufferManager.getNumUnpinned();
|
||||
pg = new Page();
|
||||
pid = new PageId();
|
||||
first_pid = new PageId();
|
||||
last_pid = new PageId();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
// Remove anything from previous tests
|
||||
// Commands here are very machine dependent. We assume
|
||||
// user are on UNIX system here
|
||||
try {
|
||||
Runtime.getRuntime().exec(remove_logcmd);
|
||||
Runtime.getRuntime().exec(remove_dbcmd);
|
||||
} catch (IOException e) {
|
||||
System.err.println("" + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testA_PinPageNotInMemory() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
// Allocated and pinned one page - check that it's in hash table
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(first_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page not in hash table", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page not in frame", false);
|
||||
FrameDescriptor fd = Minibase.BufferManager.getFrameDesc(fnum);
|
||||
checkFDContents(fd, first_pid.pid, 1, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testB_PinPinnedPageInMemory() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(first_pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for repinning already pinned page", false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr pinning pinned page", false);
|
||||
}
|
||||
// Allocated and pinned one page twice - check that it's in hash table
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(first_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page not in hash table", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page not in frame", false);
|
||||
FrameDescriptor fd = Minibase.BufferManager.getFrameDesc(fnum);
|
||||
checkFDContents(fd, first_pid.pid, 2, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testC_UnpinPinnedPageInMemory() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Allocated and pinned one page, then unpinned it - check that it's in hash
|
||||
// table
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(first_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page not in hash table after unpinning", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page not in frame after unpinning", false);
|
||||
FrameDescriptor fd = Minibase.BufferManager.getFrameDesc(fnum);
|
||||
checkFDContents(fd, first_pid.pid, 0, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testD_PinUnpinnedPageInMemory() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(first_pid, pg, false);
|
||||
} catch (BufferPoolExceededException bpe_ex) {
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full when attempting to repin unpinned page in buffer", false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr repinning page", false);
|
||||
}
|
||||
|
||||
// Allocated and pinned one page, then unpinned it, then pinned it again
|
||||
// check that it's in hash table
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(first_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page not in hash table after repinning page", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page not in frame after repinning page", false);
|
||||
FrameDescriptor fd = Minibase.BufferManager.getFrameDesc(fnum);
|
||||
checkFDContents(fd, first_pid.pid, 1, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testE_UnpinUnpinnedPageInMemory() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Unpin the page twice so that we will be unpinning an unpinned page
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning unpinned page", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
assertTrue(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we get here, the expected exception was not returned
|
||||
assertTrue("Failed: PageUnpinnedException not properly thrown", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testF_UnpinDirtyPage() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Allocated and pinned one page, then unpinned it as dirty
|
||||
// check that it's in hash table
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(first_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page not in hash table after unpinning", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page not in frame after unpinning", false);
|
||||
FrameDescriptor fd = Minibase.BufferManager.getFrameDesc(fnum);
|
||||
checkFDContents(fd, first_pid.pid, 0, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testG_UnpinPageNotInMemory() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 2);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table while unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Allocated two pages and pinned/unpinned first one
|
||||
// Now attempt to unpin second, never-pinned page
|
||||
pid = new PageId(first_pid.pid + 1);
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
assertTrue(true);
|
||||
return;
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue(
|
||||
"Unexpected Failure: PageUnpinnedException thrown, but should have returned HashNotFoundException",
|
||||
false);
|
||||
}
|
||||
|
||||
// If we get here, the expected exception was not returned
|
||||
assertTrue("Failed: PageNotFoundException not properly thrown", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testH_PinPageNotInMemoryWithReplacement() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, numPages + 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Pin and unpin enough pages to fill buffer
|
||||
for (pid.pid = first_pid.pid, last_pid.pid = pid.pid + numPages; pid.pid < last_pid.pid; pid.pid = pid.pid
|
||||
+ 1) {
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for page " + pid.pid, false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for pinning page " + pid.pid, false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " already unpinned", false);
|
||||
}
|
||||
}
|
||||
|
||||
// Now attempt to bring another page into memory
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(last_pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for last page " + last_pid.pid, false);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager when performing replacement", false);
|
||||
}
|
||||
|
||||
// Pinned a page using replacement policy - verify that FD is correct
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(last_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page not in hash table", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page not in frame", false);
|
||||
FrameDescriptor fd = Minibase.BufferManager.getFrameDesc(fnum);
|
||||
checkFDContents(fd, last_pid.pid, 1, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testI_PinPageReplaceDirtyPage() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, numPages + 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Pin and unpin enough pages to fill buffer
|
||||
for (pid.pid = first_pid.pid, last_pid.pid = pid.pid + numPages; pid.pid < last_pid.pid; pid.pid = pid.pid
|
||||
+ 1) {
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
// Write some data to each page
|
||||
int data = pid.pid + 99999;
|
||||
Convert.setIntValue(data, 0, pg.getpage());
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for page " + pid.pid, false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for page " + pid.pid, false);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: could not write page data for page " + pid.pid, false);
|
||||
}
|
||||
// Unpin page - it's dirty
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pid, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " already unpinned", false);
|
||||
}
|
||||
}
|
||||
|
||||
// Now attempt to bring another page into memory, then unpin it
|
||||
pid.pid = last_pid.pid + 1;
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for last page " + last_pid.pid + 1
|
||||
+ " during replacement", false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager when performing replacement", false);
|
||||
}
|
||||
// Pinned a page using replacement policy - FIFO should remove page with
|
||||
// pid=first_pid
|
||||
// Verify that page data in frame is overwritten
|
||||
|
||||
try {
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page " + pid.pid + " not in hash table after replacement", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page " + pid.pid + " not in frame after replacement", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
int data = Convert.getIntValue(0, pg.getpage());
|
||||
if (data == first_pid.pid + 99999)
|
||||
assertTrue("Failure: page stored in frame not overwritten when replaced", false);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: reading from page " + pid.pid, false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pid, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " already unpinned", false);
|
||||
}
|
||||
|
||||
// Bring in page with pid=first_pid again and see if its data is retrieved
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(first_pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded bringing first page in from memory " + first_pid.pid
|
||||
+ " during replacement", false);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager bringing first page in from memory", false);
|
||||
}
|
||||
// Verify contents of page after bringing back from disk
|
||||
try {
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(first_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page " + first_pid.pid + " not in hash table after replacement", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page " + first_pid.pid + " not in frame after replacement", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
int data = Convert.getIntValue(0, pg.getpage());
|
||||
// Finally, check page
|
||||
assertTrue("Failure: page stored in frame not overwritten when replaced", data == first_pid.pid + 99999);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: reading from page " + first_pid.pid, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJ_FIFOBehavior() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, numPages + 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Pin enough pages to fill buffer
|
||||
for (pid.pid = first_pid.pid, last_pid.pid = pid.pid + numPages; pid.pid < last_pid.pid; pid.pid = pid.pid + 1) {
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
// Write some data to each page
|
||||
int data = pid.pid + 99999;
|
||||
Convert.setIntValue(data, 0, pg.getpage());
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for page " + pid.pid, false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for page " + pid.pid, false);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: cannot write data for page " + pid.pid, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Pick three pages to unpin. Store the frames for reference later
|
||||
PageId pg1 = new PageId(), pg2 = new PageId(), pg3 = new PageId();
|
||||
int pageRange = last_pid.pid - first_pid.pid;
|
||||
pg1.pid = first_pid.pid + (pageRange / 3);
|
||||
Integer f1 = Minibase.BufferManager.getFrameFromPage(pg1);
|
||||
pg2.pid = first_pid.pid + (pageRange / 3) * 2;
|
||||
Integer f2 = Minibase.BufferManager.getFrameFromPage(pg2);
|
||||
pg3.pid = first_pid.pid + pageRange-1;
|
||||
Integer f3 = Minibase.BufferManager.getFrameFromPage(pg3);
|
||||
|
||||
// Unpin pages in order: pg2, pg1, pg3. FIFO should then select pg3 to evict
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pg2, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg2.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg2.pid + " already unpinned", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pg1, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg1.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg1.pid + " already unpinned", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pg3, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg3.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg3.pid + " already unpinned", false);
|
||||
}
|
||||
|
||||
// Now attempt to bring another page into memory
|
||||
pid.pid = last_pid.pid + 1;
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for last page " + last_pid.pid + 1
|
||||
+ " during replacement", false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager during replacement", false);
|
||||
}
|
||||
// Pinned a page using replacement policy - FIFO should remove page with pid=pg2
|
||||
// Verify that page data in frame is overwritten
|
||||
|
||||
try {
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page " + pid.pid + " not in hash table after replacement", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page " + pid.pid + " not in frame after replacement", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
int data = Convert.getIntValue(0, pg.getpage());
|
||||
if (data == pg2.pid + 99999)
|
||||
assertTrue("Failure: page stored in frame not overwritten when replaced", false);
|
||||
// Now that replacement policy has been used, verify we actually evicted pg3
|
||||
assertTrue("Failed: wrong page evicted, should be page " + pg2.pid + " in frame " + f2, fnum == f2);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: reading from page " + pid.pid, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testK_BufferFull() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, numPages + 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Pin enough pages to fill buffer
|
||||
for (pid.pid = first_pid.pid, last_pid.pid = pid.pid + numPages; pid.pid < last_pid.pid; pid.pid = pid.pid
|
||||
+ 1) {
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
// Write some data to each page
|
||||
int data = pid.pid + 99999;
|
||||
Convert.setIntValue(data, 0, pg.getpage());
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for page " + pid.pid, false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for page " + pid.pid, false);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: cannot write to page " + pid.pid, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Now attempt to bring another page into memory, it should fail
|
||||
pid.pid = last_pid.pid + 1;
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
} catch (BufferPoolExceededException bpe_ex) {
|
||||
assertTrue(true);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for page " + pid.pid, false);
|
||||
}
|
||||
|
||||
// If we reach here, expected exception was not thrown
|
||||
assertTrue("Failure: expected BufferPoolExceeded exception not thrown thrown for page " + pid.pid, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testL_NewPageDeallocation()
|
||||
{
|
||||
//Allocate enough pages to fill the buffer
|
||||
int numTestPages = numPages - 3; //-3 here is to account for required DiskMgr pages, which we will force to be pinned for this test
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, numTestPages);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
//Force all required DiskMgr pages to be pinned
|
||||
for(pid.pid = 0; pid.pid < first_pid.pid; pid.pid = pid.pid + 1)
|
||||
{
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for DiskMgr page " + pid.pid, false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for DiskMgr page " + pid.pid, false);
|
||||
}
|
||||
}
|
||||
// Pin enough pages to fill buffer
|
||||
for (pid.pid = first_pid.pid+1, last_pid.pid = first_pid.pid + numTestPages; pid.pid < last_pid.pid; pid.pid = pid.pid
|
||||
+ 1) {
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for page " + pid.pid, false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for page " + pid.pid, false);
|
||||
}
|
||||
}
|
||||
//Allocate enough pages to completely fill the database. However, we expect pinning the page to fail here
|
||||
boolean pin = true;
|
||||
try {
|
||||
pid = Minibase.BufferManager.newPage(pg, DB_SIZE - last_pid.pid);
|
||||
} catch (DiskMgrException e) {
|
||||
e.printStackTrace();
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for allocation that fills the DB", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
//Set a flag to show this exception was thrown successfully
|
||||
pin = false;
|
||||
}
|
||||
if(pin)
|
||||
assertTrue("Unexpected Failure: Page allocation with full buffer did not throw BufferPoolExceededException", false);
|
||||
|
||||
//Unpin all pages
|
||||
for (pid.pid = 0; pid.pid < last_pid.pid; pid.pid = pid.pid + 1) {
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " already unpinned", false);
|
||||
}
|
||||
}
|
||||
|
||||
//Allocate new pages again - this should succeed now that the buffer is unpinned
|
||||
try {
|
||||
pid = Minibase.BufferManager.newPage(pg, DB_SIZE - last_pid.pid);
|
||||
} catch (OutOfSpaceException e) {
|
||||
assertTrue("Failure: disk pages not deallocated after failure to pin them", false);
|
||||
} catch (DiskMgrException e) {
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for allocation that fills the DB", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
assertTrue("Unexpected Failure: buffer pool full when trying to allocate new pages", false);
|
||||
}
|
||||
|
||||
//If we get here, then we have succeeded
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
@Test //This is a simple test to demonstrate Freepage method. We create a new empty page, bring it to memory queue but do NOT pin it. It should be able to safely free the page.
|
||||
public void testM_FreeAnEmptyPage()
|
||||
{
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.freePage(first_pid);
|
||||
//assertTrue("freepage success", true);
|
||||
} catch (PagePinnedException e) {
|
||||
assertTrue("Test Failed: Page pinned already", true);
|
||||
//System.out.println(" --> Failed as expected \n");
|
||||
//status = FAIL; // what we want
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@Test //This test first creates a new emopty page, pins it and tries to Free it but as it is pinned already, we expect it to fail.
|
||||
public void testN_FreeAPinnedPage(){
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(first_pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for repinning already pinned page", false);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr pinning pinned page", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.freePage(first_pid);
|
||||
assertTrue("Unexpected behavior: Freepage was a success even though page was pinned", false);
|
||||
} catch (PagePinnedException e) {
|
||||
assertTrue("Test Success i.e. Failed as expected: Page pinned already - so Freepage will not suceed. This is the expected behavior.", true);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testO_FreePageOnWrittenPages() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, numPages + 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
// Pin enough pages to fill buffer
|
||||
for (pid.pid = first_pid.pid, last_pid.pid = pid.pid + numPages; pid.pid < last_pid.pid; pid.pid = pid.pid + 1) {
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
// Write some data to each page
|
||||
int data = pid.pid + 99999;
|
||||
Convert.setIntValue(data, 0, pg.getpage());
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for page " + pid.pid, false);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for page " + pid.pid, false);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: cannot write data for page " + pid.pid, false);
|
||||
}
|
||||
}
|
||||
// Pick three pages to unpin. But unpin only two and keep the third pinned
|
||||
PageId pg1 = new PageId(), pg2 = new PageId(), pg3 = new PageId();
|
||||
int pageRange = last_pid.pid - first_pid.pid;
|
||||
pg1.pid = first_pid.pid + (pageRange / 3);
|
||||
Integer f1 = Minibase.BufferManager.getFrameFromPage(pg1);
|
||||
pg2.pid = first_pid.pid + (pageRange / 3) * 2;
|
||||
Integer f2 = Minibase.BufferManager.getFrameFromPage(pg2);
|
||||
pg3.pid = first_pid.pid + pageRange-1;
|
||||
Integer f3 = Minibase.BufferManager.getFrameFromPage(pg3);
|
||||
// Unpin pages in order: pg2, pg1, pg3 (as should be in FIFO policy). But for the test we do not unpin pg3
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pg2, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg2.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg2.pid + " already unpinned", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pg1, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg1.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg1.pid + " already unpinned", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.freePage(pg1);
|
||||
assertTrue("Tests passed: PG1 was unpinned and should be able to be freed", true);
|
||||
} catch (PagePinnedException e) {
|
||||
assertTrue("Test Failed i.e. should be able to free an empty page", false);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.freePage(pg3);
|
||||
assertTrue("Tests failed: PG3 was pinned (and written) and should NOT be able to be freed", false);
|
||||
} catch (PagePinnedException e) {
|
||||
assertTrue("Test passed i.e. should not be able to free a pinned page that was written on", true);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package tests;
|
||||
|
||||
import org.junit.runner.JUnitCore;
|
||||
import org.junit.runner.Result;
|
||||
import org.junit.runner.notification.Failure;
|
||||
|
||||
public class TestDriver {
|
||||
public static void main(String[] args) {
|
||||
Result result = JUnitCore.runClasses(tests.BMTest.class);
|
||||
|
||||
for (Failure failure : result.getFailures()) {
|
||||
System.out.println(failure.toString());
|
||||
}
|
||||
|
||||
System.out.println(result.wasSuccessful());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
bin/
|
||||
.DS_Store
|
||||
sean.minibase
|
||||
|
||||
# ---> Maven
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
# Eclipse m2e generated files
|
||||
# Eclipse Core
|
||||
.project
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
.classpath
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
Test Case 1 (Handout example)
|
||||
|
||||
Log:
|
||||
W:0,T1,1,1,5,-1
|
||||
R:1,T1,2,2,0
|
||||
W:2,T1,2,2,3,1
|
||||
R:3,T1,1,5,2
|
||||
C:4,T1,3
|
||||
R:5,T2,1,5,-1
|
||||
W:6,T2,1,5,2,5
|
||||
C:7,T2,6
|
||||
|
||||
Test Case 2 (Three transactions)
|
||||
|
||||
Log:
|
||||
R:0,T1,6,6,-1
|
||||
R:1,T2,4,4,-1
|
||||
R:2,T3,9,9,-1
|
||||
W:3,T1,7,7,2,0
|
||||
W:4,T2,2,2,4,1
|
||||
R:5,T3,6,6,2
|
||||
W:6,T1,5,5,8,3
|
||||
W:7,T3,1,1,9,5
|
||||
C:8,T3,7
|
||||
W:9,T1,6,6,2,6
|
||||
C:10,T1,9
|
||||
R:11,T2,5,8,4
|
||||
W:12,T2,7,2,3,11
|
||||
C:13,T2,12
|
||||
|
||||
Test Case 3 (Deadlocks)
|
||||
|
||||
Log:
|
||||
W:0,T1,4,4,1,-1
|
||||
W:1,T2,5,5,2,-1
|
||||
W:2,T3,6,6,3,-1
|
||||
R:3,T1,1,1,0
|
||||
R:4,T2,1,1,1
|
||||
R:5,T3,2,2,2
|
||||
R:6,T2,2,2,4
|
||||
A:7,T3,5
|
||||
W:8,T2,2,2,3,6
|
||||
C:9,T2,8
|
||||
W:10,T1,1,1,2,3
|
||||
C:11,T1,10
|
||||
|
||||
Test Case 4 (No Conflicts)
|
||||
|
||||
Log:
|
||||
R:0,T1,1,1,-1
|
||||
R:1,T2,1,1,-1
|
||||
R:2,T1,2,2,0
|
||||
R:3,T2,2,2,1
|
||||
R:4,T1,3,3,2
|
||||
R:5,T2,3,3,3
|
||||
W:6,T1,4,4,1,4
|
||||
W:7,T2,5,5,2,5
|
||||
C:8,T1,6
|
||||
C:9,T2,7
|
||||
|
||||
Test Case 5: Multiple Deadlocks OR if deadlock detection finds T1 & T2 deadlock first:
|
||||
|
||||
Log: Log:
|
||||
R:0,T1,1,1,-1 R:0,T1,1,1,-1
|
||||
R:1,T2,2,2,-1 R:1,T2,2,2,-1
|
||||
R:2,T3,1,1,-1 R:2,T3,1,1,-1
|
||||
R:3,T2,3,3,1 R:3,T2,3,3,1
|
||||
A:4,T3,2 A:4,T2,3
|
||||
A:5,T2,3 W:5,T3,3,3,4,2
|
||||
W:6,T1,2,2,1,0 W:6,T1,2,2,1,0
|
||||
C:7,T1,6 C:7,T3,5
|
||||
C:8,T1,6
|
||||
|
||||
Test Case 6: Larger deadlock cycle
|
||||
|
||||
Log:
|
||||
R:0,T1,1,1,-1
|
||||
R:1,T2,2,2,-1
|
||||
R:2,T3,3,3,-1
|
||||
R:3,T4,4,4,-1
|
||||
A:4,T4,3
|
||||
W:5,T3,4,4,3,2
|
||||
C:6,T3,5
|
||||
W:7,T2,3,3,2,1
|
||||
C:8,T2,7
|
||||
W:9,T1,2,2,1,0
|
||||
C:10,T1,9
|
||||
|
||||
Test Case 7: Small deadlock cycle
|
||||
|
||||
Log:
|
||||
W:0,T1,1,1,2,-1
|
||||
W:1,T2,2,2,5,-1
|
||||
A:2,T2,1
|
||||
R:3,T1,2,2,0
|
||||
C:4,T1,3
|
||||
|
||||
Test Case 8: Three transaction with deadlock cycle
|
||||
|
||||
Log:
|
||||
R:0,T1,6,6,-1
|
||||
R:1,T2,4,4,-1
|
||||
R:2,T3,9,9,-1
|
||||
W:3,T1,7,7,2,0
|
||||
W:4,T2,2,2,4,1
|
||||
R:5,T3,6,6,2
|
||||
R:6,T2,5,5,4
|
||||
W:7,T3,1,1,9,5
|
||||
A:8,T2,6
|
||||
C:9,T3,7
|
||||
W:10,T1,2,2,8,3
|
||||
W:11,T1,6,6,2,10
|
||||
C:12,T1,11
|
||||
|
||||
Test Case 9: Small transactions without deadlock cycle
|
||||
|
||||
Log:
|
||||
W:0,T1,1,1,2,-1
|
||||
W:1,T2,3,3,5,-1
|
||||
R:2,T1,2,2,0
|
||||
R:3,T2,4,4,1
|
||||
C:4,T1,2
|
||||
C:5,T2,3
|
||||
|
||||
Test Case 10: Handout example with Deadlock
|
||||
|
||||
Log:
|
||||
W:0,T1,1,1,5,-1
|
||||
R:1,T2,2,2,-1
|
||||
R:2,T1,2,2,0
|
||||
A:3,T2,1
|
||||
W:4,T1,2,2,3,2
|
||||
R:5,T1,1,5,4
|
||||
C:6,T1,5
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>edu.cs.purdue</groupId>
|
||||
<artifactId>cs448p4</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<name>cs448p4</name>
|
||||
<url>https://www.cs.purdue.edu/homes/bb/cs448f19/</url>
|
||||
|
||||
<properties>
|
||||
<java.version>10</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
|
||||
<plugins>
|
||||
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<configuration>
|
||||
<release>${java.version}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
</plugin>
|
||||
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.7.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<!--add test cases file in here -->
|
||||
<mainClass>test.TestDriver</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,418 @@
|
||||
package CC;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
enum LockState {
|
||||
NONE,
|
||||
SHARED,
|
||||
EXCLUSIVE
|
||||
}
|
||||
|
||||
class Lock {
|
||||
|
||||
private ArrayList<Integer> transactionIds;
|
||||
private LockState type;
|
||||
private int noReads;
|
||||
|
||||
public Lock() {
|
||||
this.transactionIds = new ArrayList<Integer>();
|
||||
this.noReads = 0;
|
||||
this.type = LockState.NONE;
|
||||
}
|
||||
|
||||
public ArrayList<Integer> getTransactionIds() {
|
||||
return transactionIds;
|
||||
}
|
||||
|
||||
public void addTransactionId(int transactionId) {
|
||||
if (!transactionIds.contains(Integer.valueOf(transactionId))) {
|
||||
transactionIds.add(transactionId);
|
||||
noReads++;
|
||||
}
|
||||
}
|
||||
|
||||
public LockState getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(LockState type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getNoReads() {
|
||||
return noReads;
|
||||
}
|
||||
|
||||
public boolean hasLock(int transactionId) {
|
||||
return transactionIds.contains(Integer.valueOf(transactionId));
|
||||
}
|
||||
|
||||
public void release(int releaseTransactionId) {
|
||||
transactionIds.remove(Integer.valueOf(releaseTransactionId));
|
||||
noReads--;
|
||||
|
||||
if (noReads == 0) {
|
||||
this.type = LockState.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LockTable {
|
||||
private Lock[] locks;
|
||||
private static final int NUM_RECORDS = 10;
|
||||
|
||||
public LockTable() {
|
||||
this.locks = new Lock[NUM_RECORDS];
|
||||
// initialize the locktable
|
||||
for (int recordId = 0; recordId < NUM_RECORDS; recordId++) {
|
||||
locks[recordId] = new Lock();
|
||||
}
|
||||
}
|
||||
|
||||
public Lock getLock(int recordId) {
|
||||
if (recordId >= 0 && recordId < locks.length) {
|
||||
return locks[recordId];
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid recordId: " + recordId);
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseLocksForTransaction(int[] recordIds, int transactionId) {
|
||||
for (int recordId : recordIds) {
|
||||
if (recordId >= 0 && recordId < locks.length) {
|
||||
locks[recordId].release(transactionId);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid recordId: " + recordId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Operation {
|
||||
int getRecordId();
|
||||
|
||||
int getValue();
|
||||
}
|
||||
|
||||
class WriteOp implements Operation {
|
||||
private int recordId;
|
||||
private int value;
|
||||
|
||||
public WriteOp(int recordId, int value) {
|
||||
this.recordId = recordId;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getRecordId() {
|
||||
return recordId;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
class ReadOp implements Operation {
|
||||
private int recordId;
|
||||
|
||||
public ReadOp(int recordId) {
|
||||
this.recordId = recordId;
|
||||
}
|
||||
|
||||
public int getRecordId() {
|
||||
return recordId;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
class CommitOp implements Operation {
|
||||
public int getRecordId() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Transaction {
|
||||
private int currentOperationIndex;
|
||||
private Operation[] operations;
|
||||
private int transactionId;
|
||||
private ArrayList<Integer> recordLocks;
|
||||
private int prevTimestamp;
|
||||
private boolean aborted;
|
||||
|
||||
public Transaction(String[] operations, int transactionId) {
|
||||
this.currentOperationIndex = 0;
|
||||
this.operations = new Operation[operations.length];
|
||||
this.transactionId = transactionId;
|
||||
this.recordLocks = new ArrayList<Integer>();
|
||||
this.prevTimestamp = -1;
|
||||
this.aborted = false;
|
||||
|
||||
int OpIndex = 0;
|
||||
|
||||
for (String operation : operations) {
|
||||
if (operation.charAt(0) == 'W') {
|
||||
this.operations[OpIndex] = new WriteOp(Character.getNumericValue(operation.charAt(2)),
|
||||
Character.getNumericValue(operation.charAt(4)));
|
||||
} else if (operation.charAt(0) == 'R') {
|
||||
this.operations[OpIndex] = new ReadOp(Character.getNumericValue(operation.charAt(2)));
|
||||
} else {
|
||||
this.operations[OpIndex] = new CommitOp();
|
||||
}
|
||||
OpIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCurrentOperationIndex() {
|
||||
return currentOperationIndex;
|
||||
}
|
||||
|
||||
public int getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public void setCurrentOperationIndex(int currentOperationIndex) {
|
||||
this.currentOperationIndex = currentOperationIndex;
|
||||
}
|
||||
|
||||
public Operation[] getOperations() {
|
||||
return operations;
|
||||
}
|
||||
|
||||
public boolean hasNextOperation() {
|
||||
return (currentOperationIndex < operations.length) && !aborted;
|
||||
}
|
||||
|
||||
public int doNextOperation(LockTable lockTable, int[] database, ArrayList<String[]> systemLog, int timestamp,
|
||||
LinkedList<Integer>[] adj) {
|
||||
if (hasNextOperation() && !aborted) {
|
||||
Operation nextOp = operations[currentOperationIndex];
|
||||
Lock nextLock = null;
|
||||
if (!(nextOp instanceof CommitOp)) {
|
||||
nextLock = lockTable.getLock(nextOp.getRecordId());
|
||||
}
|
||||
currentOperationIndex++;
|
||||
|
||||
if (nextOp instanceof ReadOp) {
|
||||
if (!(nextLock.hasLock(transactionId))) {
|
||||
// The current transaction doesn't already have the lock.
|
||||
if (nextLock.getType() == LockState.EXCLUSIVE) {
|
||||
currentOperationIndex--;
|
||||
for (int adjTransactionId : nextLock.getTransactionIds()) {
|
||||
if (adjTransactionId != transactionId
|
||||
&& !adj[transactionId].contains(Integer.valueOf(adjTransactionId))) {
|
||||
adj[transactionId].add(adjTransactionId);
|
||||
}
|
||||
}
|
||||
return timestamp;
|
||||
// The lock on the record is exclusive.
|
||||
} else {
|
||||
nextLock.setType(LockState.SHARED);
|
||||
nextLock.addTransactionId(transactionId);
|
||||
recordLocks.add(nextOp.getRecordId());
|
||||
}
|
||||
}
|
||||
String[] log = { "R", Integer.toString(timestamp), "T" + Integer.toString(transactionId),
|
||||
Integer.toString(nextOp.getRecordId()), Integer.toString(database[nextOp.getRecordId()]),
|
||||
Integer.toString(prevTimestamp) };
|
||||
systemLog.add(log);
|
||||
|
||||
} else if (nextOp instanceof WriteOp) {
|
||||
int prevValue = database[nextOp.getRecordId()];
|
||||
if ((nextLock.hasLock(transactionId) && nextLock.getNoReads() == 1)
|
||||
|| nextLock.getType() == LockState.NONE) {
|
||||
nextLock.setType(LockState.EXCLUSIVE);
|
||||
database[nextOp.getRecordId()] = nextOp.getValue();
|
||||
nextLock.addTransactionId(transactionId);
|
||||
|
||||
if (!recordLocks.contains(Integer.valueOf(nextOp.getRecordId()))) {
|
||||
recordLocks.add(nextOp.getRecordId());
|
||||
}
|
||||
|
||||
} else {
|
||||
currentOperationIndex--;
|
||||
for (int adjTransactionId : nextLock.getTransactionIds()) {
|
||||
if (adjTransactionId != transactionId
|
||||
&& !adj[transactionId].contains(Integer.valueOf(adjTransactionId))) {
|
||||
adj[transactionId].add(adjTransactionId);
|
||||
}
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
String[] log = { "W", Integer.toString(timestamp), "T" + Integer.toString(transactionId),
|
||||
Integer.toString(nextOp.getRecordId()), Integer.toString(prevValue),
|
||||
Integer.toString(database[nextOp.getRecordId()]),
|
||||
Integer.toString(prevTimestamp) };
|
||||
systemLog.add(log);
|
||||
|
||||
} else {
|
||||
for (int recordLock : recordLocks) {
|
||||
lockTable.getLock(recordLock).release(transactionId);
|
||||
}
|
||||
recordLocks = new ArrayList<Integer>();
|
||||
|
||||
String[] log = { "C", Integer.toString(timestamp), "T" + Integer.toString(transactionId),
|
||||
Integer.toString(prevTimestamp) };
|
||||
systemLog.add(log);
|
||||
}
|
||||
|
||||
prevTimestamp = timestamp;
|
||||
timestamp++;
|
||||
}
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
currentOperationIndex = 0;
|
||||
recordLocks = new ArrayList<Integer>();
|
||||
}
|
||||
|
||||
public int abortTransaction(LockTable lockTable, int[] database, ArrayList<String[]> systemLog, int timestamp,
|
||||
LinkedList<Integer>[] adj) {
|
||||
aborted = true;
|
||||
int pastTransaction = prevTimestamp;
|
||||
|
||||
do {
|
||||
String[] lastLog = systemLog.get(pastTransaction);
|
||||
if (lastLog[0] == "W") {
|
||||
database[Integer.parseInt(lastLog[3])] = Integer.parseInt(lastLog[4]);
|
||||
}
|
||||
pastTransaction = Integer.parseInt(lastLog[lastLog.length - 1]);
|
||||
} while (pastTransaction != -1);
|
||||
|
||||
for (int recordLock : recordLocks) {
|
||||
lockTable.getLock(recordLock).release(transactionId);
|
||||
}
|
||||
recordLocks = new ArrayList<Integer>();
|
||||
|
||||
adj[transactionId] = new LinkedList<Integer>();
|
||||
|
||||
String[] log = { "A", Integer.toString(timestamp), "T" + Integer.toString(transactionId),
|
||||
Integer.toString(prevTimestamp) };
|
||||
systemLog.add(log);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public class CC {
|
||||
private static final int NUM_RECORDS = 10;
|
||||
|
||||
/**
|
||||
* Notes:
|
||||
* - Execute all given transactions, using locking.
|
||||
* - Each element in the transactions List represents all operations performed
|
||||
* by one transaction, in order.
|
||||
* - No operation in a transaction can be executed out of order, but operations
|
||||
* may be interleaved with other
|
||||
* transactions if allowed by the locking.
|
||||
* - The index of the transaction in the list is equivalent to the transaction
|
||||
* ID.
|
||||
* - Print the log to the console at the end of the method.
|
||||
* - Return the new db state after executing the transactions.
|
||||
*
|
||||
* @param db the initial status of the db
|
||||
* @param transactions the schedule, which basically is a {@link List} of
|
||||
* transactions.
|
||||
* @return the final status of the db
|
||||
*/
|
||||
public static int[] executeSchedule(int[] db, List<String> transactions) {
|
||||
LockTable lockTable = new LockTable();
|
||||
Queue<Transaction> transactionQueue = new LinkedList<>();
|
||||
Transaction[] transactionsArray = new Transaction[transactions.size() + 1];
|
||||
int newTransactionId = 1;
|
||||
int[] database = new int[NUM_RECORDS];
|
||||
ArrayList<String[]> systemLog = new ArrayList<>();
|
||||
int timestamp = 0;
|
||||
|
||||
LinkedList<Integer>[] adj;
|
||||
|
||||
for (int i = 0; i < NUM_RECORDS; i++) {
|
||||
database[i] = i;
|
||||
}
|
||||
|
||||
for (String transaction : transactions) {
|
||||
Transaction newTransaction = new Transaction(transaction.split(";"), newTransactionId);
|
||||
transactionQueue.add(newTransaction);
|
||||
transactionsArray[newTransactionId] = newTransaction;
|
||||
newTransactionId++;
|
||||
}
|
||||
adj = new LinkedList[transactions.size() + 1];
|
||||
for (int i = 0; i < transactions.size() + 1; ++i) {
|
||||
adj[i] = new LinkedList<Integer>();
|
||||
}
|
||||
|
||||
while (!transactionQueue.isEmpty()) {
|
||||
Transaction curTransaction = transactionQueue.remove();
|
||||
if (curTransaction.hasNextOperation()) {
|
||||
timestamp = curTransaction.doNextOperation(lockTable, database, systemLog, timestamp, adj);
|
||||
|
||||
// Here is where we check if there are deadlocks. We run DFS.
|
||||
boolean[] visited = new boolean[transactions.size() + 1];
|
||||
int[] predecessor = new int[transactions.size() + 1];
|
||||
ArrayList<Integer> nodesInCycle = DFS(curTransaction.getTransactionId(), visited, adj, predecessor);
|
||||
|
||||
if (nodesInCycle != null) {
|
||||
Collections.sort(nodesInCycle);
|
||||
transactionsArray[nodesInCycle.get(nodesInCycle.size() - 1)].abortTransaction(lockTable, database,
|
||||
systemLog, timestamp,
|
||||
adj);
|
||||
timestamp++;
|
||||
}
|
||||
|
||||
transactionQueue.add(curTransaction);
|
||||
}
|
||||
}
|
||||
|
||||
for (String[] log : systemLog) {
|
||||
StringBuilder sb = new StringBuilder(log[0] + ":" + log[1]);
|
||||
for (int k = 2; k < log.length; k++) {
|
||||
sb.append("," + log[k]);
|
||||
}
|
||||
System.out.println(sb.toString());
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
public static ArrayList<Integer> DFS(int v, boolean visited[], LinkedList<Integer> adj[], int predecessor[]) {
|
||||
visited[v] = true;
|
||||
|
||||
Iterator<Integer> i = adj[v].listIterator();
|
||||
while (i.hasNext()) {
|
||||
int n = i.next();
|
||||
if (!visited[n]) {
|
||||
predecessor[n] = v;
|
||||
return DFS(n, visited, adj, predecessor);
|
||||
} else {
|
||||
return returnNodesInCycle(predecessor, v, n);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ArrayList<Integer> returnNodesInCycle(int[] predecessor, int parent, int start) {
|
||||
ArrayList<Integer> nodesInCycle = new ArrayList<>();
|
||||
nodesInCycle.add(parent);
|
||||
nodesInCycle.add(start);
|
||||
|
||||
while (predecessor[start] != parent && predecessor[start] != 0) {
|
||||
nodesInCycle.add(predecessor[start]);
|
||||
start = predecessor[start];
|
||||
}
|
||||
return nodesInCycle;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package CC;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Project
|
||||
{
|
||||
|
||||
public static int[] newDB()
|
||||
{
|
||||
return new int[]{0,1,2,3,4,5,6,7,8,9};
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
//Test Cases
|
||||
//1) Simple testcase (handout)
|
||||
List<String> tc1 = Arrays.asList(new String[]{"W(1,5);R(2);W(2,3);R(1);C","R(1);W(1,2);C"});
|
||||
//2) Three transactions
|
||||
List<String> tc2 = Arrays.asList(new String[]{"R(6);W(7,2);W(5,8);W(6,2);C","R(4);W(2,4);R(5);W(7,3);C","R(9);R(6);W(1,9);C"});
|
||||
//3) Deadlocks
|
||||
List<String> tc3 = Arrays.asList(new String[]{"W(4,1);R(1);W(1,2);C","W(5,2);R(1);R(2);W(2,3);C","W(6,3);R(2);W(2,4);C"});
|
||||
//4) No conflicts
|
||||
List<String> tc4 = Arrays.asList(new String[]{"R(1);R(2);R(3);W(4,1);C","R(1);R(2);R(3);W(5,2);C"});
|
||||
//5) Multiple Deadlocks (handout)
|
||||
List<String> tc5 = Arrays.asList(new String[]{"R(1);W(2,1);C","R(2);R(3);W(1,2);C","R(1);W(3,4);C"});
|
||||
//6) Larger Deadlock Cycle
|
||||
List<String> tc6 = Arrays.asList(new String[]{"R(1);W(2,1);C","R(2);W(3,2);C","R(3);W(4,3);C","R(4);W(1,4);C"});
|
||||
//7) Small Deadlock Cycle
|
||||
List<String> tc7 = Arrays.asList(new String[]{"W(1,2);R(2);C","W(2,5);R(1);C"});
|
||||
//8) Three Transactions Deadlock Cycle
|
||||
List<String> tc8 = Arrays.asList(new String[]{"R(6);W(7,2);W(2,8);W(6,2);C","R(4);W(2,4);R(5);W(7,3);C","R(9);R(6);W(1,9);C"});
|
||||
//9) Small Transactions without Deadlock Cycle
|
||||
List<String> tc9 = Arrays.asList(new String[]{"W(1,2);R(2);C","W(3,5);R(4);C"});
|
||||
//10) Testcase with Deadlock Cycle
|
||||
List<String> tc10 = Arrays.asList(new String[]{"W(1,5);R(2);W(2,3);R(1);C","R(2);R(1);W(1,2);C"});
|
||||
|
||||
//Consult the ExpectedOutputs.txt for the expected DB state and log
|
||||
|
||||
System.out.println("Schedule 1: Handout Test Case:\n\t" + Arrays.toString(CC.executeSchedule(newDB(),tc1)) + "\n");
|
||||
System.out.println("Schedule 2: Three Transactions Test Case:\n\t" + Arrays.toString(CC.executeSchedule(newDB(),tc2)) + "\n");
|
||||
System.out.println("Schedule 3: Deadlocks Test Case:\n\t" + Arrays.toString(CC.executeSchedule(newDB(),tc3)) + "\n");
|
||||
System.out.println("Schedule 4: No Conflicts Test Case:\n\t" + Arrays.toString(CC.executeSchedule(newDB(),tc4)) + "\n");
|
||||
System.out.println("Schedule 5: Multiple Deadlocks Test Case:\n\t" + Arrays.toString(CC.executeSchedule(newDB(),tc5)) + "\n");
|
||||
System.out.println("Schedule 6: Larger Deadlock Cycle Test Case:\n\t" + Arrays.toString(CC.executeSchedule(newDB(),tc6)) + "\n");
|
||||
System.out.println("Schedule 7: Testcase with two transactions and a deadlock\n\t" + Arrays.toString(CC.executeSchedule(newDB(),tc7)) + "\n");
|
||||
System.out.println("Schedule 8: Testcase with three transactions and a deadlock:\n\t" + Arrays.toString(CC.executeSchedule(newDB(),tc8)) + "\n");
|
||||
System.out.println("Schedule 9: Testcase with two transactions and no deadlocks:\n\t" + Arrays.toString(CC.executeSchedule(newDB(),tc9)) + "\n");
|
||||
System.out.println("Schedule 10: Testcase with deadlock between two transactions:\n\t" + Arrays.toString(CC.executeSchedule(newDB(),tc10)) + "\n");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
package tests;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
import CC.*;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class CCTest {
|
||||
|
||||
public final static boolean OK = true;
|
||||
public final static boolean FAIL = false;
|
||||
|
||||
public static int[] newDB()
|
||||
{
|
||||
return new int[]{0,1,2,3,4,5,6,7,8,9};
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule 1. Simple testcase with 2 transactions.
|
||||
* This testcase is shown in the handout, Part 2.
|
||||
*/
|
||||
@Test
|
||||
public void test_A_Simple()
|
||||
{
|
||||
// expected output from the given Schedule
|
||||
int expectedOutput[] = {0, 2, 3, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
// input: T1, T2
|
||||
List<String> tc1 = Arrays.asList(new String[]{"W(1,5);R(2);W(2,3);R(1);C","R(1);W(1,2);C"});
|
||||
|
||||
// Here we are returning the state of the database after executing Schedule 1
|
||||
int methodOutput[] = CC.executeSchedule(newDB(),tc1);
|
||||
|
||||
// Here we are checking whether method output matched with the expected output
|
||||
// if both match it will pass the test, otherwise it will show an error message
|
||||
assertArrayEquals("output did not match expected result",expectedOutput, methodOutput);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule 2. Testcase with three transactions and no deadlock.
|
||||
*/
|
||||
@Test
|
||||
public void test_B_ThreeTransactions()
|
||||
{
|
||||
|
||||
int expectedOutput[] = {0, 9, 4, 3, 4, 8, 2, 3, 8, 9};
|
||||
|
||||
//Testcases
|
||||
//2) Three transactions
|
||||
List<String> tc2 = Arrays.asList(new String[]{"R(6);W(7,2);W(5,8);W(6,2);C","R(4);W(2,4);R(5);W(7,3);C","R(9);R(6);W(1,9);C"});
|
||||
|
||||
int methodOutput[] = CC.executeSchedule(newDB(),tc2);
|
||||
assertArrayEquals("output did not match expected result",expectedOutput, methodOutput);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule 3. Testcase with three transactions and a deadlock.
|
||||
*/
|
||||
@Test
|
||||
public void test_C_Deadlocks()
|
||||
{
|
||||
|
||||
int expectedOutput[] = {0, 2, 3, 3, 1, 2, 6, 7, 8, 9};
|
||||
|
||||
//Testcases
|
||||
//3) Deadlocks
|
||||
List<String> tc3 = Arrays.asList(new String[]{"W(4,1);R(1);W(1,2);C","W(5,2);R(1);R(2);W(2,3);C","W(6,3);R(2);W(2,4);C"});
|
||||
|
||||
int methodOutput[] = CC.executeSchedule(newDB(),tc3);
|
||||
|
||||
assertArrayEquals("output did not match expected result",expectedOutput, methodOutput);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule 4. Testcase with multiple deadlocks.
|
||||
* This testcase is shown in the handout, Part 3 (Deadlock Detection/Handling).
|
||||
*/
|
||||
@Test
|
||||
public void test_D_NoConflicts()
|
||||
{
|
||||
|
||||
int expectedOutput[] = {0, 1, 2, 3, 1, 2, 6, 7, 8, 9};
|
||||
|
||||
//Testcases
|
||||
//4) No conflicts
|
||||
List<String> tc4 = Arrays.asList(new String[]{"R(1);R(2);R(3);W(4,1);C","R(1);R(2);R(3);W(5,2);C"});
|
||||
|
||||
int methodOutput[] = CC.executeSchedule(newDB(),tc4);
|
||||
|
||||
assertArrayEquals("output did not match expected result",expectedOutput, methodOutput);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule 5. Testcase with multiple deadlocks.
|
||||
* This testcase is shown in the handout, Part 3 (Deadlock Detection/Handling).
|
||||
*/
|
||||
@Test
|
||||
public void test_E_MultipleDeadlocks()
|
||||
{
|
||||
// In the Schedule 5 there can be two possible outcomes depending of how you handle deadlocks.
|
||||
int expectedOutput[] = {0, 1, 1, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
//Testcases
|
||||
//5) Multiple Deadlocks
|
||||
List<String> tc5 = Arrays.asList(new String[]{"R(1);W(2,1);C","R(2);R(3);W(1,2);C","R(1);W(3,4);C"});
|
||||
|
||||
int methodOutput[] = CC.executeSchedule(newDB(),tc5);
|
||||
|
||||
try{
|
||||
// if T3 is aborted, and then T2
|
||||
assertArrayEquals("output did not match expected result",expectedOutput, methodOutput);
|
||||
}catch (AssertionError e) {
|
||||
// if we abort T2
|
||||
int expectedOutput_anth[] = {0, 1, 1, 4, 4, 5, 6, 7, 8, 9};
|
||||
assertArrayEquals("output did not match expected result",expectedOutput_anth, methodOutput);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule 6. Testcase with large number of transactions (4) and a deadlock.
|
||||
*/
|
||||
@Test
|
||||
public void test_F_LargerDeadlock()
|
||||
{
|
||||
int expectedOutput[] = {0, 1, 1, 2, 3, 5, 6, 7, 8, 9};
|
||||
|
||||
//Testcases
|
||||
//6) Larger Deadlock Cycle
|
||||
List<String> tc6 = Arrays.asList(new String[]{"R(1);W(2,1);C","R(2);W(3,2);C","R(3);W(4,3);C","R(4);W(1,4);C"});
|
||||
|
||||
int methodOutput[] = CC.executeSchedule(newDB(),tc6);
|
||||
|
||||
assertArrayEquals("output did not match expected result",expectedOutput, methodOutput);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule 7. Testcase with small transactions (2) and a deadlock.
|
||||
*/
|
||||
@Test
|
||||
public void test_G_SmallDeadlock()
|
||||
{
|
||||
int expectedOutput[] = {0, 2, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
//Testcases
|
||||
//7) Small Deadlock Cycle
|
||||
List<String> tc7 = Arrays.asList(new String[]{"W(1,2);R(2);C","W(2,5);R(1);C"});
|
||||
|
||||
int methodOutput[] = CC.executeSchedule(newDB(),tc7);
|
||||
|
||||
assertArrayEquals("output did not match expected result",expectedOutput, methodOutput);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule 8. Testcase with three transactions (2) and a deadlock.
|
||||
*/
|
||||
@Test
|
||||
public void test_H_ThreeTransactionsDeadlock()
|
||||
{
|
||||
int expectedOutput[] = {0, 9, 8, 3, 4, 5, 2, 2, 8, 9};
|
||||
|
||||
//Testcases
|
||||
//8) Three Transactions Deadlock
|
||||
List<String> tc8 = Arrays.asList(new String[]{"R(6);W(7,2);W(2,8);W(6,2);C","R(4);W(2,4);R(5);W(7,3);C","R(9);R(6);W(1,9);C"});
|
||||
|
||||
int methodOutput[] = CC.executeSchedule(newDB(),tc8);
|
||||
|
||||
assertArrayEquals("output did not match expected result",expectedOutput, methodOutput);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule 9. Testcase with small transactions (2) and no deadlocks.
|
||||
*/
|
||||
@Test
|
||||
public void test_I_SmallTransactionsNoDeadlock()
|
||||
{
|
||||
int expectedOutput[] = {0, 2, 2, 5, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
//Testcases
|
||||
//9) Small Transactions without Deadlock Testcase:
|
||||
List<String> tc9 = Arrays.asList(new String[]{"W(1,2);R(2);C","W(3,5);R(4);C"});
|
||||
|
||||
int methodOutput[] = CC.executeSchedule(newDB(),tc9);
|
||||
|
||||
assertArrayEquals("output did not match expected result",expectedOutput, methodOutput);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule 10. Testcase with deadlock between two transactions.
|
||||
*/
|
||||
@Test
|
||||
public void test_J_TestCaseDeadlockDeadlock()
|
||||
{
|
||||
int expectedOutput[] = {0, 5, 3, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
//Testcases
|
||||
//10) Testcase with Deadlock:
|
||||
List<String> tc10 = Arrays.asList(new String[]{"W(1,5);R(2);W(2,3);R(1);C","R(2);R(1);W(1,2);C"});
|
||||
|
||||
int methodOutput[] = CC.executeSchedule(newDB(),tc10);
|
||||
|
||||
assertArrayEquals("output did not match expected result",expectedOutput, methodOutput);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package tests;
|
||||
import org.junit.runner.JUnitCore;
|
||||
import org.junit.runner.Result;
|
||||
import org.junit.runner.notification.Failure;
|
||||
|
||||
public class TestDriver {
|
||||
public static void main(String[] args) {
|
||||
Result result = JUnitCore.runClasses(tests.CCTest.class);
|
||||
|
||||
for (Failure failure : result.getFailures()) {
|
||||
System.out.println(failure.toString());
|
||||
}
|
||||
|
||||
System.out.println(result.wasSuccessful());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<html>
|
||||
<head>
|
||||
<TITLE>Fundamentals of Database Systems Laboratory Book - 2nd Edition - Chapter 1</TITLE>
|
||||
<style type="text/css">
|
||||
a { text-decoration: none }a:hover {text-decoration: none;
|
||||
color: red;
|
||||
background-color: #ccffcc;
|
||||
font-family: helvetica, sans-serif, arial;
|
||||
font-size: 16pts }
|
||||
h1 {font-family: helvetica, sans-serif, arial;
|
||||
color: #000080;
|
||||
background-color: #EECFA1;width: 20em}
|
||||
h2 {font-family: helvetica, sans-serif, arial;
|
||||
color: #000080;
|
||||
background-color: #EECFA1; width: 20em }
|
||||
.special {fontsize: 1.5em;
|
||||
color: blue }
|
||||
</style></head>
|
||||
<body bgcolor="#8AD6EB"alink="#0000CC"link="#0000CC"text="#000000"vlink="#0000CC">
|
||||
|
||||
<center>
|
||||
<h3>Chapter 1 - ER Modeling Tools </h3>
|
||||
</center>
|
||||
|
||||
<h3>Laboratory Manual Chapter</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="ch1.pdf">Chapter 1 (pdf)</a>
|
||||
</ul>
|
||||
|
||||
<h3>ERWin design files</h3>
|
||||
|
||||
<ul>
|
||||
<li><a href="company.erwin">company.erwin</a>
|
||||
<li><a href="vehicles.erwin">vehicles.erwin</a>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,25 @@
|
||||
6
|
||||
Research
|
||||
5
|
||||
333445555
|
||||
22-MAY-1978
|
||||
Administration
|
||||
4
|
||||
987654321
|
||||
01-JAN-1985
|
||||
Headquarters
|
||||
1
|
||||
888665555
|
||||
19-JUN-1971
|
||||
Software
|
||||
6
|
||||
111111100
|
||||
15-MAY-1999
|
||||
Hardware
|
||||
7
|
||||
444444400
|
||||
15-MAY-1998
|
||||
Sales
|
||||
8
|
||||
555555500
|
||||
01-JAN-1997
|
||||
@@ -0,0 +1,56 @@
|
||||
11
|
||||
333445555
|
||||
Alice
|
||||
F
|
||||
05-APR-1976
|
||||
Daughter
|
||||
333445555
|
||||
Theodore
|
||||
M
|
||||
25-OCT-1973
|
||||
Son
|
||||
333445555
|
||||
Joy
|
||||
F
|
||||
03-MAY-1948
|
||||
Spouse
|
||||
987654321
|
||||
Abner
|
||||
M
|
||||
29-FEB-1932
|
||||
Spouse
|
||||
123456789
|
||||
Michael
|
||||
M
|
||||
01-JAN-1978
|
||||
Son
|
||||
123456789
|
||||
Alice
|
||||
F
|
||||
31-DEC-1978
|
||||
Daughter
|
||||
123456789
|
||||
Elizabeth
|
||||
F
|
||||
05-MAY-1957
|
||||
Spouse
|
||||
444444400
|
||||
Johnny
|
||||
M
|
||||
04-APR-1997
|
||||
Son
|
||||
444444400
|
||||
Tommy
|
||||
M
|
||||
07-JUN-1999
|
||||
Son
|
||||
444444401
|
||||
Chris
|
||||
M
|
||||
19-APR-1969
|
||||
Spouse
|
||||
444444402
|
||||
Alec
|
||||
M
|
||||
14-FEB-1964
|
||||
Spouse
|
||||
@@ -0,0 +1,27 @@
|
||||
13
|
||||
1
|
||||
Houston
|
||||
4
|
||||
Stafford
|
||||
5
|
||||
Bellaire
|
||||
5
|
||||
Sugarland
|
||||
5
|
||||
Houston
|
||||
6
|
||||
Atlanta
|
||||
6
|
||||
Sacramento
|
||||
7
|
||||
Milwaukee
|
||||
8
|
||||
Chicago
|
||||
8
|
||||
Dallas
|
||||
8
|
||||
Philadephia
|
||||
8
|
||||
Seattle
|
||||
8
|
||||
Miami
|
||||
@@ -0,0 +1,401 @@
|
||||
40
|
||||
James
|
||||
E
|
||||
Borg
|
||||
888665555
|
||||
10-NOV-27
|
||||
450 Stone, Houston, TX
|
||||
M
|
||||
55000
|
||||
null
|
||||
1
|
||||
Franklin
|
||||
T
|
||||
Wong
|
||||
333445555
|
||||
08-DEC-45
|
||||
638 Voss, Houston, TX
|
||||
M
|
||||
40000
|
||||
888665555
|
||||
5
|
||||
Jennifer
|
||||
S
|
||||
Wallace
|
||||
987654321
|
||||
20-JUN-31
|
||||
291 Berry, Bellaire, TX
|
||||
F
|
||||
43000
|
||||
888665555
|
||||
4
|
||||
John
|
||||
B
|
||||
Smith
|
||||
123456789
|
||||
09-Jan-55
|
||||
731 Fondren, Houston, TX
|
||||
M
|
||||
30000
|
||||
333445555
|
||||
5
|
||||
Alicia
|
||||
J
|
||||
Zelaya
|
||||
999887777
|
||||
19-JUL-58
|
||||
3321 Castle, Spring, TX
|
||||
F
|
||||
25000
|
||||
987654321
|
||||
4
|
||||
Ramesh
|
||||
K
|
||||
Narayan
|
||||
666884444
|
||||
15-SEP-52
|
||||
971 Fire Oak, Humble, TX
|
||||
M
|
||||
38000
|
||||
333445555
|
||||
5
|
||||
Joyce
|
||||
A
|
||||
English
|
||||
453453453
|
||||
31-JUL-62
|
||||
5631 Rice, Houston, TX
|
||||
F
|
||||
25000
|
||||
333445555
|
||||
5
|
||||
Ahmad
|
||||
V
|
||||
Jabbar
|
||||
987987987
|
||||
29-MAR-59
|
||||
980 Dallas, Houston, TX
|
||||
M
|
||||
25000
|
||||
987654321
|
||||
4
|
||||
Jared
|
||||
D
|
||||
James
|
||||
111111100
|
||||
10-OCT-1966
|
||||
123 Peachtree, Atlanta, GA
|
||||
M
|
||||
85000
|
||||
null
|
||||
6
|
||||
Alex
|
||||
D
|
||||
Freed
|
||||
444444400
|
||||
09-OCT-1950
|
||||
4333 Pillsbury, Milwaukee, WI
|
||||
M
|
||||
89000
|
||||
null
|
||||
7
|
||||
John
|
||||
C
|
||||
James
|
||||
555555500
|
||||
30-JUN-1975
|
||||
7676 Bloomington, Sacramento, CA
|
||||
M
|
||||
81000
|
||||
null
|
||||
6
|
||||
Jon
|
||||
C
|
||||
Jones
|
||||
111111101
|
||||
14-NOV-1967
|
||||
111 Allgood, Atlanta, GA
|
||||
M
|
||||
45000
|
||||
111111100
|
||||
6
|
||||
Justin
|
||||
null
|
||||
Mark
|
||||
111111102
|
||||
12-JAN-1966
|
||||
2342 May, Atlanta, GA
|
||||
M
|
||||
40000
|
||||
111111100
|
||||
6
|
||||
Brad
|
||||
C
|
||||
Knight
|
||||
111111103
|
||||
13-FEB-1968
|
||||
176 Main St., Atlanta, GA
|
||||
M
|
||||
44000
|
||||
111111100
|
||||
6
|
||||
Evan
|
||||
E
|
||||
Wallis
|
||||
222222200
|
||||
16-JAN-1958
|
||||
134 Pelham, Milwaukee, WI
|
||||
M
|
||||
92000
|
||||
null
|
||||
7
|
||||
Josh
|
||||
U
|
||||
Zell
|
||||
222222201
|
||||
22-MAY-1954
|
||||
266 McGrady, Milwaukee, WI
|
||||
M
|
||||
56000
|
||||
222222200
|
||||
7
|
||||
Andy
|
||||
C
|
||||
Vile
|
||||
222222202
|
||||
21-JUN-1944
|
||||
1967 Jordan, Milwaukee, WI
|
||||
M
|
||||
53000
|
||||
222222200
|
||||
7
|
||||
Tom
|
||||
G
|
||||
Brand
|
||||
222222203
|
||||
16-DEC-1966
|
||||
112 Third St, Milwaukee, WI
|
||||
M
|
||||
62500
|
||||
222222200
|
||||
7
|
||||
Jenny
|
||||
F
|
||||
Vos
|
||||
222222204
|
||||
11-NOV-1967
|
||||
263 Mayberry, Milwaukee, WI
|
||||
F
|
||||
61000
|
||||
222222201
|
||||
7
|
||||
Chris
|
||||
A
|
||||
Carter
|
||||
222222205
|
||||
21-MAR-1960
|
||||
565 Jordan, Milwaukee, WI
|
||||
F
|
||||
43000
|
||||
222222201
|
||||
7
|
||||
Kim
|
||||
C
|
||||
Grace
|
||||
333333300
|
||||
23-OCT-1970
|
||||
6677 Mills Ave, Sacramento, CA
|
||||
F
|
||||
79000
|
||||
null
|
||||
6
|
||||
Jeff
|
||||
H
|
||||
Chase
|
||||
333333301
|
||||
07-JAN-1970
|
||||
145 Bradbury, Sacramento, CA
|
||||
M
|
||||
44000
|
||||
333333300
|
||||
6
|
||||
Bonnie
|
||||
S
|
||||
Bays
|
||||
444444401
|
||||
19-JUN-1956
|
||||
111 Hollow, Milwaukee, WI
|
||||
F
|
||||
70000
|
||||
444444400
|
||||
7
|
||||
Alec
|
||||
C
|
||||
Best
|
||||
444444402
|
||||
18-JUN-1966
|
||||
233 Solid, Milwaukee, WI
|
||||
M
|
||||
60000
|
||||
444444400
|
||||
7
|
||||
Sam
|
||||
S
|
||||
Snedden
|
||||
444444403
|
||||
31-JUL-1977
|
||||
987 Windy St, Milwaukee, WI
|
||||
M
|
||||
48000
|
||||
444444400
|
||||
7
|
||||
Nandita
|
||||
K
|
||||
Ball
|
||||
555555501
|
||||
16-APR-1969
|
||||
222 Howard, Sacramento, CA
|
||||
M
|
||||
62000
|
||||
555555500
|
||||
6
|
||||
Bob
|
||||
B
|
||||
Bender
|
||||
666666600
|
||||
17-APR-1968
|
||||
8794 Garfield, Chicago, IL
|
||||
M
|
||||
96000
|
||||
null
|
||||
8
|
||||
Jill
|
||||
J
|
||||
Jarvis
|
||||
666666601
|
||||
14-JAN-1966
|
||||
6234 Lincoln, Chicago, IL
|
||||
F
|
||||
36000
|
||||
666666600
|
||||
8
|
||||
Kate
|
||||
W
|
||||
King
|
||||
666666602
|
||||
16-APR-1966
|
||||
1976 Boone Trace, Chicago, IL
|
||||
F
|
||||
44000
|
||||
666666600
|
||||
8
|
||||
Lyle
|
||||
G
|
||||
Leslie
|
||||
666666603
|
||||
09-JUN-1963
|
||||
417 Hancock Ave, Chicago, IL
|
||||
M
|
||||
41000
|
||||
666666601
|
||||
8
|
||||
Billie
|
||||
J
|
||||
King
|
||||
666666604
|
||||
01-JAN-1960
|
||||
556 Washington, Chicago, IL
|
||||
F
|
||||
38000
|
||||
666666603
|
||||
8
|
||||
Jon
|
||||
A
|
||||
Kramer
|
||||
666666605
|
||||
22-AUG-1964
|
||||
1988 Windy Creek, Seattle, WA
|
||||
M
|
||||
41500
|
||||
666666603
|
||||
8
|
||||
Ray
|
||||
H
|
||||
King
|
||||
666666606
|
||||
16-AUG-1949
|
||||
213 Delk Road, Seattle, WA
|
||||
M
|
||||
44500
|
||||
666666604
|
||||
8
|
||||
Gerald
|
||||
D
|
||||
Small
|
||||
666666607
|
||||
15-MAY-1962
|
||||
122 Ball Street, Dallas, TX
|
||||
M
|
||||
29000
|
||||
666666602
|
||||
8
|
||||
Arnold
|
||||
A
|
||||
Head
|
||||
666666608
|
||||
19-MAY-1967
|
||||
233 Spring St, Dallas, TX
|
||||
M
|
||||
33000
|
||||
666666602
|
||||
8
|
||||
Helga
|
||||
C
|
||||
Pataki
|
||||
666666609
|
||||
11-MAR-1969
|
||||
101 Holyoke St, Dallas, TX
|
||||
F
|
||||
32000
|
||||
666666602
|
||||
8
|
||||
Naveen
|
||||
B
|
||||
Drew
|
||||
666666610
|
||||
23-MAY-1970
|
||||
198 Elm St, Philadelphia, PA
|
||||
M
|
||||
34000
|
||||
666666607
|
||||
8
|
||||
Carl
|
||||
E
|
||||
Reedy
|
||||
666666611
|
||||
21-JUN-1977
|
||||
213 Ball St, Philadelphia, PA
|
||||
M
|
||||
32000
|
||||
666666610
|
||||
8
|
||||
Sammy
|
||||
G
|
||||
Hall
|
||||
666666612
|
||||
11-JAN-1970
|
||||
433 Main Street, Miami, FL
|
||||
M
|
||||
37000
|
||||
666666611
|
||||
8
|
||||
Red
|
||||
A
|
||||
Bacher
|
||||
666666613
|
||||
21-MAY-1980
|
||||
196 Elm Street, Miami, FL
|
||||
M
|
||||
33500
|
||||
666666612
|
||||
8
|
||||
@@ -0,0 +1,45 @@
|
||||
11
|
||||
ProductX
|
||||
1
|
||||
Bellaire
|
||||
5
|
||||
ProductY
|
||||
2
|
||||
Sugarland
|
||||
5
|
||||
ProductZ
|
||||
3
|
||||
Houston
|
||||
5
|
||||
Computerization
|
||||
10
|
||||
Stafford
|
||||
4
|
||||
Reorganization
|
||||
20
|
||||
Houston
|
||||
1
|
||||
Newbenefits
|
||||
30
|
||||
Stafford
|
||||
4
|
||||
OperatingSystems
|
||||
61
|
||||
Jacksonville
|
||||
6
|
||||
DatabaseSystems
|
||||
62
|
||||
Birmingham
|
||||
6
|
||||
Middleware
|
||||
63
|
||||
Jackson
|
||||
6
|
||||
InkjetPrinters
|
||||
91
|
||||
Phoenix
|
||||
7
|
||||
LaserPrinters
|
||||
92
|
||||
LasVegas
|
||||
7
|
||||
@@ -0,0 +1,145 @@
|
||||
48
|
||||
123456789
|
||||
1
|
||||
32.5
|
||||
123456789
|
||||
2
|
||||
7.5
|
||||
666884444
|
||||
3
|
||||
40.0
|
||||
453453453
|
||||
1
|
||||
20.0
|
||||
453453453
|
||||
2
|
||||
20.0
|
||||
333445555
|
||||
2
|
||||
10.0
|
||||
333445555
|
||||
3
|
||||
10.0
|
||||
333445555
|
||||
10
|
||||
10.0
|
||||
333445555
|
||||
20
|
||||
10.0
|
||||
999887777
|
||||
30
|
||||
30.0
|
||||
999887777
|
||||
10
|
||||
10.0
|
||||
987987987
|
||||
10
|
||||
35.0
|
||||
987987987
|
||||
30
|
||||
5.0
|
||||
987654321
|
||||
30
|
||||
20.0
|
||||
987654321
|
||||
20
|
||||
15.0
|
||||
888665555
|
||||
20
|
||||
0
|
||||
111111100
|
||||
61
|
||||
40.0
|
||||
111111101
|
||||
61
|
||||
40.0
|
||||
111111102
|
||||
61
|
||||
40.0
|
||||
111111103
|
||||
61
|
||||
40.0
|
||||
222222200
|
||||
62
|
||||
40.0
|
||||
222222201
|
||||
62
|
||||
48.0
|
||||
222222202
|
||||
62
|
||||
40.0
|
||||
222222203
|
||||
62
|
||||
40.0
|
||||
222222204
|
||||
62
|
||||
40.0
|
||||
222222205
|
||||
62
|
||||
40.0
|
||||
333333300
|
||||
63
|
||||
40.0
|
||||
333333301
|
||||
63
|
||||
46.0
|
||||
444444400
|
||||
91
|
||||
40.0
|
||||
444444401
|
||||
91
|
||||
40.0
|
||||
444444402
|
||||
91
|
||||
40.0
|
||||
444444403
|
||||
91
|
||||
40.0
|
||||
555555500
|
||||
92
|
||||
40.0
|
||||
555555501
|
||||
92
|
||||
44.0
|
||||
666666601
|
||||
91
|
||||
40.0
|
||||
666666603
|
||||
91
|
||||
40.0
|
||||
666666604
|
||||
91
|
||||
40.0
|
||||
666666605
|
||||
92
|
||||
40.0
|
||||
666666606
|
||||
91
|
||||
40.0
|
||||
666666607
|
||||
61
|
||||
40.0
|
||||
666666608
|
||||
62
|
||||
40.0
|
||||
666666609
|
||||
63
|
||||
40.0
|
||||
666666610
|
||||
61
|
||||
40.0
|
||||
666666611
|
||||
61
|
||||
40.0
|
||||
666666612
|
||||
61
|
||||
40.0
|
||||
666666613
|
||||
61
|
||||
30.0
|
||||
666666613
|
||||
62
|
||||
10.0
|
||||
666666613
|
||||
63
|
||||
10.0
|
||||
@@ -0,0 +1,69 @@
|
||||
6
|
||||
EMPLOYEE
|
||||
10
|
||||
FNAME
|
||||
VARCHAR
|
||||
MINIT
|
||||
VARCHAR
|
||||
LNAME
|
||||
VARCHAR
|
||||
SSN
|
||||
VARCHAR
|
||||
BDATE
|
||||
VARCHAR
|
||||
ADDRESS
|
||||
VARCHAR
|
||||
SEX
|
||||
VARCHAR
|
||||
SALARY
|
||||
DECIMAL
|
||||
SUPERSSN
|
||||
VARCHAR
|
||||
DNO
|
||||
INTEGER
|
||||
DEPARTMENT
|
||||
4
|
||||
DNAME
|
||||
VARCHAR
|
||||
DNUMBER
|
||||
INTEGER
|
||||
MGRSSN
|
||||
VARCHAR
|
||||
MGRSTARTDATE
|
||||
VARCHAR
|
||||
DEPT_LOCATIONS
|
||||
2
|
||||
DNUMBER
|
||||
INTEGER
|
||||
DLOCATION
|
||||
VARCHAR
|
||||
PROJECTS
|
||||
4
|
||||
PNAME
|
||||
VARCHAR
|
||||
PNUMBER
|
||||
INTEGER
|
||||
PLOCATION
|
||||
VARCHAR
|
||||
DNUM
|
||||
INTEGER
|
||||
WORKS_ON
|
||||
3
|
||||
ESSN
|
||||
VARCHAR
|
||||
PNO
|
||||
INTEGER
|
||||
HOURS
|
||||
DECIMAL
|
||||
DEPENDENT
|
||||
5
|
||||
ESSN
|
||||
VARCHAR
|
||||
DEPENDENT_NAME
|
||||
VARCHAR
|
||||
SEX
|
||||
VARCHAR
|
||||
BDATE
|
||||
VARCHAR
|
||||
RELATIONSHIP
|
||||
VARCHAR
|
||||
@@ -0,0 +1,22 @@
|
||||
7
|
||||
CSc1010
|
||||
sp04
|
||||
02011000
|
||||
CSc1010
|
||||
f05
|
||||
02011000
|
||||
CSc1010
|
||||
sp05
|
||||
02011000
|
||||
CSc4710
|
||||
sp05
|
||||
02012000
|
||||
CSc4710
|
||||
sp06
|
||||
02021000
|
||||
CIS6710
|
||||
sp05
|
||||
02013000
|
||||
CIS8710
|
||||
sp05
|
||||
02012000
|
||||
@@ -0,0 +1,16 @@
|
||||
5
|
||||
CSc1010
|
||||
Computers and Applications
|
||||
Computer Science
|
||||
CSc2310
|
||||
Java
|
||||
Computer Science
|
||||
CSc4710
|
||||
Databases
|
||||
Computer Science
|
||||
CIS6710
|
||||
Databases Programming
|
||||
Computer Information Systems
|
||||
CIS8710
|
||||
Databases
|
||||
Computer Information Systems
|
||||
@@ -0,0 +1,21 @@
|
||||
5
|
||||
1111
|
||||
CSc1010
|
||||
sp04
|
||||
A
|
||||
1111
|
||||
CSc4710
|
||||
sp06
|
||||
B
|
||||
2222
|
||||
CSc1010
|
||||
sp04
|
||||
A
|
||||
2222
|
||||
CIS6710
|
||||
sp04
|
||||
A
|
||||
3333
|
||||
CSc1010
|
||||
sp04
|
||||
C
|
||||
@@ -0,0 +1,17 @@
|
||||
4
|
||||
1111
|
||||
Linekar
|
||||
CSc
|
||||
10-20-1982
|
||||
2222
|
||||
Holmes
|
||||
CSc
|
||||
12-10-1983
|
||||
3333
|
||||
Tyson
|
||||
Math
|
||||
09-21-1985
|
||||
4444
|
||||
Blackwell
|
||||
CSc
|
||||
01-22-1980
|
||||
@@ -0,0 +1,17 @@
|
||||
4
|
||||
02011000
|
||||
Intro to Computers
|
||||
Smith
|
||||
Addison Wesley
|
||||
02012000
|
||||
Database Fundamentals
|
||||
Navathe
|
||||
Addison Wesley
|
||||
02021000
|
||||
Database Concepts
|
||||
Silberschatz
|
||||
McGraw Hill
|
||||
02013000
|
||||
Database Programming
|
||||
Navathe
|
||||
Addison Wesley
|
||||
@@ -0,0 +1,47 @@
|
||||
5
|
||||
STUDENT
|
||||
4
|
||||
SSN
|
||||
INTEGER
|
||||
NAME
|
||||
VARCHAR
|
||||
MAJOR
|
||||
VARCHAR
|
||||
BDATE
|
||||
VARCHAR
|
||||
COURSE
|
||||
3
|
||||
COURSENUM
|
||||
VARCHAR
|
||||
CNAME
|
||||
VARCHAR
|
||||
DEPT
|
||||
VARCHAR
|
||||
ENROLL
|
||||
4
|
||||
SSN
|
||||
INTEGER
|
||||
COURSENUM
|
||||
VARCHAR
|
||||
QUARTER
|
||||
VARCHAR
|
||||
GRADE
|
||||
VARCHAR
|
||||
BOOKADOPTION
|
||||
3
|
||||
COURSENUM
|
||||
VARCHAR
|
||||
QUARTER
|
||||
VARCHAR
|
||||
BOOKISBN
|
||||
INTEGER
|
||||
TEXT
|
||||
4
|
||||
BOOKISBN
|
||||
INTEGER
|
||||
BOOKTITLE
|
||||
VARCHAR
|
||||
PUBLISHER
|
||||
VARCHAR
|
||||
AUTHOR
|
||||
VARCHAR
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
Query 1: Get names of all employees in department 5 who work more than 10 hours/week on the ProductX project.
|
||||
|
||||
answer(F,M,L) :-
|
||||
employee(F,M,L,S,_,_,_,_,_,5),
|
||||
works_on(S,P,H),
|
||||
projects('ProductX',P,_,_),
|
||||
H >= 10.
|
||||
|
||||
Query 2: Get names of all employees who have a dependent with the same first name as their own first names.
|
||||
|
||||
answer(F,M,L) :-
|
||||
employee(F,M,L,S,_,_,_,_,_,_),
|
||||
dependent(S,F,_,_,_).
|
||||
|
||||
Query 3: Get the names of all employees who are directly supervised by Franklin Wong.
|
||||
|
||||
answer(F,M,L) :-
|
||||
employee(F,M,L,_,_,_,_,_,S,_),
|
||||
employee('Franklin',_,'Wong',S,_,_,_,_,_,_).
|
||||
|
||||
Query 4: Get the names of all employees who work on every project.
|
||||
|
||||
temp1(S,P) :-
|
||||
employee(_,_,_,S,_,_,_,_,_,_),
|
||||
projects(_,P,_,_).
|
||||
temp2(S,P) :-
|
||||
works_on(S,P,_).
|
||||
temp3(S) :-
|
||||
temp1(S,P), not temp2(S,P).
|
||||
answer(F,M,L) :-
|
||||
employee(F,M,L,S,_,_,_,_,_,_), not temp3(S).
|
||||
|
||||
Query 5: Get the names of employees who do not work on any project.
|
||||
|
||||
temp1(S) :-
|
||||
works_on(S,_,_).
|
||||
answer(F,M,L) :-
|
||||
employee(F,M,L,S,_,_,_,_,_,_), not temp1(S).
|
||||
|
||||
Query 6: Get the names and addresses of employees who work for at least one project located in Houston but whose department does not have a location in Houston.
|
||||
|
||||
temp1(S) :-
|
||||
works_on(S,P,_), project(_,P,'Houston',_).
|
||||
temp2(S) :-
|
||||
employee(_,_,_,S,_,_,_,_,_,D),
|
||||
not dept_locations(D,'Houston').
|
||||
answer(F,M,L,A) :-
|
||||
employee(F,M,L,S,_,A,_,_,_,_), temp1(S), temp2(S).
|
||||
|
||||
Query 7: Get the names and addresses of employees who work for at least one project located in Houston or whose department does not have a location in Houston. (Note: this is a slight variation of the previous query with 'but' replaced by 'or').
|
||||
|
||||
temp1(S) :-
|
||||
works_on(S,P,_),
|
||||
project(_,P,'Houston',_).
|
||||
temp2(S) :-
|
||||
employee(_,_,_,S,_,_,_,_,_,D),
|
||||
not dept_locations(D,'Houston').
|
||||
answer(F,M,L,A) :-
|
||||
employee(F,M,L,S,_,A,_,_,_,_), temp1(S).
|
||||
answer(F,M,L,A) :-
|
||||
employee(F,M,L,S,_,A,_,_,_,_), temp2(S).
|
||||
|
||||
Query 8: Get the last names of all department managers who have no dependents.
|
||||
|
||||
temp1(S) :-
|
||||
dependent(S,_,_,_,_).
|
||||
answer(L) :-
|
||||
employee(_,_,L,S,_,_,_,_,_,_),
|
||||
department(_,_,S,_),
|
||||
not temp1(S).
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
Query 0: Retrieve the birthdate and address of the employees whose name is "John B. Smith".
|
||||
|
||||
{ u,v | (exists t,w,x,y,z)(
|
||||
employee('John','B','Smith',t,u,v,w,x,y,z) ) }
|
||||
|
||||
Query 1: Retrieve the name and address of all employees who work for the "Research"
|
||||
department.
|
||||
|
||||
{ q,s,v | (exists r,t,u,w,x,y,z,n,o)(
|
||||
employee(q,r,s,t,u,v,w,x,y,z) and
|
||||
department('Research',z,n,o) ) }
|
||||
|
||||
Query 2: For every project located in "Stafford", list the project number, the
|
||||
controlling department number, and the department manager's last name,
|
||||
birth date, and address.
|
||||
|
||||
{ i,k,s,u,v | (exists h,q,r,t,w,x,y,z,l,o)(
|
||||
projects(h,i,'Stafford',k) and
|
||||
employee(q,r,s,t,u,v,w,x,y,z) and
|
||||
department(l,k,t,o) ) }
|
||||
|
||||
Query 6: List the names of employees who have no dependents.
|
||||
|
||||
{ q,s | (exists r,t,u,v,w,x,y,z)(
|
||||
employee(q,r,s,t,u,v,w,x,y,z) and
|
||||
not ((exists m,n,o,p)(dependent(t,m,n,o,p))) ) }
|
||||
|
||||
The following is not SAFE and would not work
|
||||
|
||||
{ q,s | (exists r,t,u,v,w,x,y,z)(
|
||||
employee(q,r,s,t,u,v,w,x,y,z) and
|
||||
(forall l,m,n,o,p)(not (dependent(l,m,n,o,p)) or t<>l) )}
|
||||
|
||||
Query 7: List the names of managers who have at least one dependent.
|
||||
|
||||
{ s,q | (exists r,t,u,v,w,x,y,z,h,i,k,m,n,o,p)(
|
||||
employee(q,r,s,t,u,v,w,x,y,z) and
|
||||
department(h,i,t,k) and
|
||||
dependent(t,m,n,o,p) ) }
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
4
|
||||
csc226
|
||||
Java Programming
|
||||
csc227
|
||||
C++ Programming
|
||||
csc481
|
||||
Automata
|
||||
csc880
|
||||
Logic Programming
|
||||