From 391d9f5be8ff4e589182dd6c8a449a647d1ee0cf Mon Sep 17 00:00:00 2001 From: Pranav Sivaraman Date: Wed, 15 May 2024 03:47:24 -0400 Subject: [PATCH 1/2] Final Repo (#21) --- a2_final/.gitignore | 10 + a2_final/CMakeLists.txt | 23 + a2_final/cmake/colorize.cmake | 79 +++ a2_final/cmake/compile.cmake | 19 + a2_final/cmake/systems.cmake | 54 ++ .../cmsc624-a2-sol-latex-template/Makefile | 122 ++++ .../cmsc624-a2-sol-latex-template/main.tex | 235 +++++++ a2_final/db.pftrace | Bin 0 -> 1451025 bytes a2_final/output.txt | 103 +++ a2_final/run.sh | 9 + a2_final/src/CMakeLists.txt | 29 + a2_final/src/txn/calvin.cc | 515 +++++++++++++++ a2_final/src/txn/lock_manager.cc | 262 ++++++++ a2_final/src/txn/lock_manager.h | 127 ++++ a2_final/src/txn/lock_manager_test.cc | 189 ++++++ a2_final/src/txn/mvcc_storage.cc | 119 ++++ a2_final/src/txn/mvcc_storage.h | 58 ++ a2_final/src/txn/storage.cc | 29 + a2_final/src/txn/storage.h | 46 ++ a2_final/src/txn/txn.cc | 56 ++ a2_final/src/txn/txn.h | 108 ++++ a2_final/src/txn/txn_processor.cc | 596 ++++++++++++++++++ a2_final/src/txn/txn_processor.h | 228 +++++++ a2_final/src/txn/txn_processor_test.cc | 384 +++++++++++ a2_final/src/txn/txn_types.h | 152 +++++ a2_final/src/txn/txn_types_test.cc | 76 +++ a2_final/src/utils/atomic.h | 209 ++++++ a2_final/src/utils/atomic_queue.h | 49 ++ a2_final/src/utils/common.h | 70 ++ a2_final/src/utils/pool.h | 69 ++ a2_final/src/utils/static_thread_pool.h | 86 +++ a2_final/src/utils/testing.h | 70 ++ a2_final/src/utils/thread_pool.h | 21 + 33 files changed, 4202 insertions(+) create mode 100644 a2_final/.gitignore create mode 100644 a2_final/CMakeLists.txt create mode 100644 a2_final/cmake/colorize.cmake create mode 100644 a2_final/cmake/compile.cmake create mode 100644 a2_final/cmake/systems.cmake create mode 100644 a2_final/cmsc624-a2-sol-latex-template/Makefile create mode 100644 a2_final/cmsc624-a2-sol-latex-template/main.tex create mode 100644 a2_final/db.pftrace create mode 100644 a2_final/output.txt create mode 100644 a2_final/run.sh create mode 100644 a2_final/src/CMakeLists.txt create mode 100644 a2_final/src/txn/calvin.cc create mode 100644 a2_final/src/txn/lock_manager.cc create mode 100644 a2_final/src/txn/lock_manager.h create mode 100644 a2_final/src/txn/lock_manager_test.cc create mode 100644 a2_final/src/txn/mvcc_storage.cc create mode 100644 a2_final/src/txn/mvcc_storage.h create mode 100644 a2_final/src/txn/storage.cc create mode 100644 a2_final/src/txn/storage.h create mode 100644 a2_final/src/txn/txn.cc create mode 100644 a2_final/src/txn/txn.h create mode 100644 a2_final/src/txn/txn_processor.cc create mode 100644 a2_final/src/txn/txn_processor.h create mode 100644 a2_final/src/txn/txn_processor_test.cc create mode 100644 a2_final/src/txn/txn_types.h create mode 100644 a2_final/src/txn/txn_types_test.cc create mode 100644 a2_final/src/utils/atomic.h create mode 100644 a2_final/src/utils/atomic_queue.h create mode 100644 a2_final/src/utils/common.h create mode 100644 a2_final/src/utils/pool.h create mode 100644 a2_final/src/utils/static_thread_pool.h create mode 100644 a2_final/src/utils/testing.h create mode 100644 a2_final/src/utils/thread_pool.h diff --git a/a2_final/.gitignore b/a2_final/.gitignore new file mode 100644 index 0000000..87f7612 --- /dev/null +++ b/a2_final/.gitignore @@ -0,0 +1,10 @@ +build +.deps +bin +obj + +.vscode +.DS_Store +.cache/clangd/index +compile_commands.json +work_steal diff --git a/a2_final/CMakeLists.txt b/a2_final/CMakeLists.txt new file mode 100644 index 0000000..d17c1e4 --- /dev/null +++ b/a2_final/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.18) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +project(db_concurrency_control VERSION 0.1.0 LANGUAGES C CXX) + +set(DB_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) +set(DB_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +find_package(Threads REQUIRED) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +enable_testing() + +include(systems) +include(compile) + +include_directories(${DB_SOURCE_DIR}) + +add_subdirectory(src) diff --git a/a2_final/cmake/colorize.cmake b/a2_final/cmake/colorize.cmake new file mode 100644 index 0000000..daabba8 --- /dev/null +++ b/a2_final/cmake/colorize.cmake @@ -0,0 +1,79 @@ +### +# +# @copyright (c) 2009-2014 The University of Tennessee and The University +# of Tennessee Research Foundation. +# All rights reserved. +# @copyright (c) 2012-2014 Inria. All rights reserved. +# @copyright (c) 2012-2014 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, Univ. Bordeaux. All rights reserved. +# +### +# +# @file ColorizeMessage.cmake +# +# @project ECRC +# ECRC is a software package provided by: +# Inria Bordeaux - Sud-Ouest, +# Univ. of Tennessee, +# King Abdullah University of Science and Technology +# Univ. of California Berkeley, +# Univ. of Colorado Denver. +# +# @version 0.9.0 +# @author Cedric Castagnede +# @author Emmanuel Agullo +# @author Mathieu Faverge +# @author Florent Pruvost +# @date 13-07-2012 +# +### + +# Set some colors +if(NOT WIN32) + string(ASCII 27 Esc) + set(ColourReset "${Esc}[m") + set(ColourBold "${Esc}[1m") + set(Red "${Esc}[31m") + set(Green "${Esc}[32m") + set(Yellow "${Esc}[33m") + set(Blue "${Esc}[34m") + set(Magenta "${Esc}[35m") + set(Cyan "${Esc}[36m") + set(White "${Esc}[37m") + set(BoldRed "${Esc}[1;31m") + set(BoldGreen "${Esc}[1;32m") + set(BoldYellow "${Esc}[1;33m") + set(BoldBlue "${Esc}[1;34m") + set(BoldMagenta "${Esc}[1;35m") + set(BoldCyan "${Esc}[1;36m") + set(BoldWhite "${Esc}[1;37m") +endif() + +# Colorize cmake messages during configure +function(message) +list(GET ARGV 0 MessageType) +if(MessageType STREQUAL FATAL_ERROR OR MessageType STREQUAL SEND_ERROR) + list(REMOVE_AT ARGV 0) + string (REPLACE ";" " " ARGV_STR "${ARGV}") + _message(${MessageType} "${BoldRed}${ARGV_STR}${ColourReset}") +elseif(MessageType STREQUAL WARNING) + list(REMOVE_AT ARGV 0) + string (REPLACE ";" " " ARGV_STR "${ARGV}") + _message(${MessageType} "${BoldYellow}${ARGV_STR}${ColourReset}") +elseif(MessageType STREQUAL AUTHOR_WARNING) + list(REMOVE_AT ARGV 0) + string (REPLACE ";" " " ARGV_STR "${ARGV}") + _message(${MessageType} "${Yellow}${ARGV_STR}${ColourReset}") +elseif(MessageType STREQUAL STATUS) + list(REMOVE_AT ARGV 0) + string (REPLACE ";" " " ARGV_STR "${ARGV}") + _message(${MessageType} "${Green}${ARGV_STR}${ColourReset}") +else() + string (REPLACE ";" " " ARGV_STR "${ARGV}") + string (REPLACE "${Esc}[1 " "${Esc}[1;" ARGV_STR "${ARGV_STR}") + _message("${ARGV_STR}") +endif() +endfunction() + +## +## @end file ColorizeMessage.cmake +## \ No newline at end of file diff --git a/a2_final/cmake/compile.cmake b/a2_final/cmake/compile.cmake new file mode 100644 index 0000000..162c9f4 --- /dev/null +++ b/a2_final/cmake/compile.cmake @@ -0,0 +1,19 @@ +add_compile_options("-Wall") + +##### +# Change the default build type from Debug to Release, while still +# supporting overriding the build type. +# +# The CACHE STRING logic here and elsewhere is needed to force CMake +# to pay attention to the value of these variables. +if(NOT CMAKE_BUILD_TYPE) + message(STATUS "No build type specified; defaulting to CMAKE_BUILD_TYPE=Release.") + set(CMAKE_BUILD_TYPE Release CACHE STRING + "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." + FORCE) +else(NOT CMAKE_BUILD_TYPE) + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + message(STATUS "Build type: Debug. Performance will be terrible!") + message(STATUS "Add -DCMAKE_BUILD_TYPE=Release to the CMake command line to get an optimized build.") + endif(CMAKE_BUILD_TYPE STREQUAL "Debug") +endif(NOT CMAKE_BUILD_TYPE) diff --git a/a2_final/cmake/systems.cmake b/a2_final/cmake/systems.cmake new file mode 100644 index 0000000..faf6ac6 --- /dev/null +++ b/a2_final/cmake/systems.cmake @@ -0,0 +1,54 @@ +INCLUDE(colorize) # colorize and highlight message + +IF(WIN32) + SET(HOST_SYSTEM "win32") +ELSE(WIN32) + IF(APPLE) + EXEC_PROGRAM (sw_vers ARGS -productVersion OUTPUT_VARIABLE MACOSX_VERSION) + STRING(REGEX MATCH "[0-9]+.[0-9]+" VERSION "${MACOSX_VERSION}") + SET(MACOS_VERSION ${VERSION}) + SET(HOST_SYSTEM "macosx") + IF(NOT DEFINED ENV{MACOSX_DEPLOYMENT_TARGET}) + # Set cache variable - end user may change this during ccmake or cmake-gui configure. + SET(CMAKE_OSX_DEPLOYMENT_TARGET ${MACOS_VERSION} CACHE STRING + "Minimum OS X version to target for deployment (at runtime); newer APIs weak linked. Set to empty string for default value.") + ENDIF() + set(CMAKE_EXE_LINKER_FLAGS "-framework CoreFoundation -framework Security") + ELSE(APPLE) + IF(EXISTS "/etc/issue") + FILE(READ "/etc/issue" LINUX_ISSUE) + IF(LINUX_ISSUE MATCHES "CentOS") + SET(HOST_SYSTEM "centos") + ELSEIF(LINUX_ISSUE MATCHES "Debian") + SET(HOST_SYSTEM "debian") + ELSEIF(LINUX_ISSUE MATCHES "Ubuntu") + SET(HOST_SYSTEM "ubuntu") + ELSEIF(LINUX_ISSUE MATCHES "Red Hat") + SET(HOST_SYSTEM "redhat") + ELSEIF(LINUX_ISSUE MATCHES "Fedora") + SET(HOST_SYSTEM "fedora") + ENDIF() + ENDIF(EXISTS "/etc/issue") + + IF(EXISTS "/etc/redhat-release") + FILE(READ "/etc/redhat-release" LINUX_ISSUE) + IF(LINUX_ISSUE MATCHES "CentOS") + SET(HOST_SYSTEM "centos") + ENDIF() + ENDIF(EXISTS "/etc/redhat-release") + + IF(NOT HOST_SYSTEM) + SET(HOST_SYSTEM ${CMAKE_SYSTEM_NAME}) + ENDIF() + set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-Wno-unused-but-set-variable -Wno-maybe-uninitialized") + ENDIF(APPLE) +ENDIF(WIN32) + +# query number of logical cores +CMAKE_HOST_SYSTEM_INFORMATION(RESULT CPU_CORES QUERY NUMBER_OF_LOGICAL_CORES) + +MARK_AS_ADVANCED(HOST_SYSTEM CPU_CORES) + +MESSAGE(STATUS "CMSC624 Assignment 2: Understanding Locking, OCC and MVCC") +MESSAGE(STATUS "Found host system: ${HOST_SYSTEM}") +MESSAGE(STATUS "Found host system's CPU: ${CPU_CORES} cores") diff --git a/a2_final/cmsc624-a2-sol-latex-template/Makefile b/a2_final/cmsc624-a2-sol-latex-template/Makefile new file mode 100644 index 0000000..86da174 --- /dev/null +++ b/a2_final/cmsc624-a2-sol-latex-template/Makefile @@ -0,0 +1,122 @@ +############################################################################### +# Project Configuration + +TARGET = $(shell basename $(PWD)).pdf +MAIN = main + +##### + +TARGET_BASE = $(basename $(TARGET)) + +################################################################################ +# Command Configuration + +PDFLATEX = pdflatex +BIBTEX = bibtex +EPS_TO_PDF = epstopdf +OBJ_TO_EPS = tgif -print -eps -color -stdout +GNUPLOT = gnuplot +SPELLCHECK = aspell -t list + +################################################################################ +# Gathering Information + +TEX_MAIN := $(MAIN).tex + +TEX_ALL := $(shell search=$(TEX_MAIN); all=; \ + while [ -n "$$search" ] ; do \ + all="$$all $$search"; \ + search=`egrep "^[^%]*\\input" $$search | \ + sed -En 's/.*input[^\{]*\{(.+)\}/\1.tex/p'`; \ + done; \ + echo "$$all") + +GFX_ALL := $(shell for t in $(TEX_ALL); do \ + cat $$t | \ + egrep '^[^%]*\\includegraphics' | \ + sed -En 's/.*includegraphics(\[.+\])?\{([^\{]*)\}.*/\2/p'; \ + done) + +GFX_FILES := $(shell for g in $(GFX_ALL); do \ + ls $$g.* | \ + egrep "(\.obj|\.eps)$$" | \ + sed -E 's/\.[^ ]+/\.pdf/g'; \ + done) + +GNUPLOT_FILES := $(shell for g in $(GFX_ALL); do \ + test -e $$g.p && \ + test ! -e $$g.eps -a ! -e $$g.obj && \ + echo $$g.pdf; \ + done) + +BIB_FILES := $(shell cat $(TEX_MAIN) | \ + egrep '^[^%]*\\bibliography\{' | \ + sed -E -e 's/.*\{([^\{]+)\}.*/\1/g' \ + -e 's/([^,\{\}]+)/\1.bib/g' \ + -e 's/,/ /g') + +################################################################################ +# Command Rules + +all: $(TARGET) + +$(TARGET): $(TEX_ALL) $(GFX_FILES) $(GNUPLOT_FILES) $(BIB_FILES) + $(PDFLATEX) $(TEX_MAIN) File Rules + +%.pdf: %.eps + $(EPS_TO_PDF) $< + +%.pdf: %.obj + $(OBJ_TO_EPS) $< | \ + $(EPS_TO_PDF) -f -o=$@ + +%.pdf: %.p + $(GNUPLOT) $< | \ + $(EPS_TO_PDF) -f -o=$@ + diff --git a/a2_final/cmsc624-a2-sol-latex-template/main.tex b/a2_final/cmsc624-a2-sol-latex-template/main.tex new file mode 100644 index 0000000..8251c29 --- /dev/null +++ b/a2_final/cmsc624-a2-sol-latex-template/main.tex @@ -0,0 +1,235 @@ +\documentclass[11pt]{article} +\usepackage{fullpage} +\usepackage{amsmath} +\usepackage{graphicx} +\usepackage{tabularx} +\usepackage{float} +\usepackage{hyperref} +\usepackage[usenames,dvipsnames]{xcolor} +\usepackage[normalem]{ulem} + +\setlength{\topmargin}{0in} % top of paper to head (less one inch) +\setlength{\headheight}{0in} % height of the head +\setlength{\headsep}{0in} % head to the top of the body +\setlength{\textheight}{8.75in} % height of the body +\setlength{\oddsidemargin}{0mm} % left edge of paper to body (less one inch) +\setlength{\evensidemargin}{0mm} % ditto, even pages +\setlength{\textwidth}{6.5in} % width of body +\setlength{\topskip}{0in} % top of body to bottom of first line of text +\setlength{\footskip}{0.50in} % bottom of text to bottom of foot + +\newtheorem{theorem}{Theorem} +\newtheorem{corollary}{Corollary} +\newtheorem{lemma}{Lemma} +\newtheorem{observation}{Observation} +\newtheorem{definition}{Definition} +\newtheorem{fact}{Fact} +\newcommand{\proof}{\vspace*{-1ex} \noindent {\bf Proof: }} +\newcommand{\proofsketch}{\vspace*{-1ex} \noindent {\bf Proof Sketch: }} +\newcommand{\qed}{\hfill\rule{2mm}{2mm}} +\newcommand{\ceiling}[1]{{\left\lceil{#1}\right\rceil}} +\newcommand{\floor}[1]{{\left\lfloor{#1}\right\rfloor}} +\newcommand{\paren}[1]{\left({#1}\right)} +\newcommand{\braces}[1]{\left\{{#1}\right\}} +\newcommand{\brackets}[1]{\left[{#1}\right]} +\newcommand{\Prob}{{\rm Prob}} +\newcommand{\prob}{{\rm Prob}} +\newcommand{\host}[1]{\tt \small {#1}} + +\newcommand{\header}[3]{ + \pagestyle{plain} + \noindent + \begin{center} + \framebox{ + \vbox{ + \hbox to 6.28in { {\bf CMSC 624 Database System Architecture and Implementation +\hfill Spring 2024} } + \vspace{4mm} + \hbox to 6.28in { {\Large \hfill #1 \hfill} } + \vspace{4mm} + \hbox to 6.28in { {\sl #2 \hfill #3} } + } + } + + \end{center} + \vspace*{4mm} +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Per-author comment commands +% NOTE: To remove them, build with 'make finished' which will generate a new +% output file with the suffix '-final.pdf' + +\ifdefined\isFinalized + +\newcommand{\note}[1]{} +\newcommand{\mnote}[1]{} + +\newcommand{\pooja}[1]{} +\newcommand{\dna}[1]{} +\newcommand{\answer}[1]{} + +\else + +\newcommand{\note}[1]{{\color{green}{\it Note: #1}}} +\newcommand{\mnote}[1]{\marginpar{{\color{red}{\it\ #1 \ \ }}}} + +\newcommand{\pooja}[1]{{\color{green}{\it Gang - #1}}} +\newcommand{\dna}[1]{{\color{purple}{\it DNA - #1}}} +\newcommand{\answer}[1]{{\color{black}\texttt{{a: - #1}}}} + +\fi + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{document} + +\addtolength{\baselineskip}{-.01\baselineskip} + +\header{Programming Assignment 2}{Assigned: February 23}{Due: March 8, 11:59:59 PM} + +\newcommand{\spc}{\sqcup} +\newcommand{\vers}{spring-2024-624} + +\section{Description} + +In this assignment you will be implementing six concurrency control schemes: + +\begin{itemize} +\item Two versions of locking schemes, both of which implement variations of the standard two-phase locking algorithm we discussed in class. +\item A version of OCC very similar to the serial-validation version described in the OCC paper you read for class. +\item A version of OCC somewhat similar to the parallel-validation version described in the OCC paper. +\item A version of MVCC timestamp ordering that is a simplified version of the PostgreSQL scheme we studied in class. +\item A serializable version of the MVCC scheme that is a simplified version of PostgreSQL's SSI scheme. +\end{itemize} + +\section{Requirements} + +\begin{enumerate} +% + \item Your code must be submitted as a series of commits that are pushed to +the origin/master branch of your private Git repository. We consider your latest commit +prior to the due date/time to represent your submission. +% + \item The directory for your project must be located at the root of your Git repository. +% + \item You are not allowed to work in teams or to copy code from any source. + \item You are not allowed to discuss your analysis with anyone else. +% + \item Please submit (\{your\_name\}\_a2\_sol.pdf) to the assignment 2 link on ELMS. You do not need to submit any code, since we can access to your repositories. +\end{enumerate} + +\section{Part 5} + +\subsection{Carpe datum (0 points)} + +When you finish the coding part of this assignment, we will run your code on our test server, and commit the results back to you. + +\subsection{Simulations are doomed to succeed. (4 points)} + +Transaction durations are accomplished simply by forcing the thread executing each transaction to run in a busy loop for approximately the amount of time specified. This is supposed to simulate transaction logic --- e.g. the application might run some proprietary customer scoring function to estimate the total value of the customer after reading in the customer record from the database. Please list **at least two weaknesses** of this simulation --- i.e. give two reasons why performance of the different concurrency control schemes you experimented with for this assignment would change relative to each other if we ran actual application code instead of just simulating it with a busy loop. + +\answer{your answer here...} +% your answer +\vspace{10mm} + +\subsection{Locking manager (6 points)} + +\begin{enumerate} +\item Is deadlock possible in your locking implementation? Why or why not? \\ +\answer{your answer here...} +% your answer +\vspace{10mm} + +\item Most 2PL systems wait until they access data before they request a lock. But this implementation requests all locks before executing any transaction code. What is a performance-related disadvantage of our implementation in this assignment of requesting all locks in advance? What is a client-usability disadvantage of requesting all locks in advance? \\ +\answer{your answer here...} +% your answer +\vspace{10mm} +\end{enumerate} + +\subsection{OCCam's Razor (6 points)} + +The OCC with serial validation is simpler than OCC with parallel validation. + +\begin{enumerate} +\item How did the two algorithms compare with each other in this simulation? Why do you think that is the case? \\ +\answer{your answer here...} +% your answer +\vspace{10mm} + +\item How does this compare to the OCC paper that we read for class? \\ +\answer{your answer here...} +% your answer +\vspace{10mm} + +\item What is the biggest reason for the difference between your results and the what you expected after reading the OCC paper? \\ +\answer{your answer here...} +% your answer +\vspace{10mm} +\end{enumerate} + +If you did not follow the given pseudocode for OCC with parallel validation, give your pseudocode and argue why it is better. + +\subsection{OCC vs. Locking B (7 points)} + +If your code is correct, you probably found that relative performance of OCC and Locking B were different from the tradeoffs we discussed in class. In fact, you might be quite surprised by your results. Please describe the two biggest differences between the relative performance of OCC vs. Locking B relative to what we discussed in class, and explain why the theory doesn't match the practice for this codebase for each of these two surprises. + +\subsection{MVCC vs. OCC/Locking (6 points)} + +\begin{enumerate} +\item For the read-write tests, MVCC performs worse than OCC and Locking. Why? \\ +\answer{your answer here...} +% your answer +\vspace{10mm} + +\item MVCC even sometimes does worse than serial. Why? \\ +\answer{your answer here...} +% your answer +\vspace{10mm} + +\item Yet for the mixed read-only/read-write experiment it performs the best, even though it wasn't the best for either read-only nor read-write. Why? \\ +\answer{your answer here...} +% your answer +\vspace{10mm} + +\end{enumerate} + +If you wrote your own version, please explain why it's better than the ones presented here. + + +\subsection{MVCC pseudocode (4 points)} + +\begin{enumerate} +\item Why did our MVCC pseudocode request read locks before each read? \\ +\answer{your answer here...} +% your answer +\vspace{10mm} + +\item In particular, what would happen if you didn't acquire these read locks? \\ +\answer{your answer here...} +% your answer +\vspace{10mm} + +\item How long do these locks have to be held? \\ +\answer{your answer here...} +% your answer +\vspace{10mm} + +\item How does the MVCC-SSI pseudocode guarantee serializability? \\ +\answer{your answer here...} +% your answer +\vspace{10mm} + +\end{enumerate} + +\subsection{Mixed transaction lengths (8 points)} + +Take a close look at your high contention read/write results. When transaction lengths are uniform, one of the conccurency control schemes you implemented is best. However, for mixed transaction lengths (the fourth column in the results), you will probably see a different concurrency control scheme as the winner! Please explain why the results changed for mixed transaction lengths. + +\answer{your answer here...} +% your answer +\vspace{10mm} + +\end{document} + diff --git a/a2_final/db.pftrace b/a2_final/db.pftrace new file mode 100644 index 0000000000000000000000000000000000000000..97a0664065dfc52ee2774b4fafd58b99da20bb47 GIT binary patch literal 1451025 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 z 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�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 C_Puog literal 0 HcmV?d00001 diff --git a/a2_final/output.txt b/a2_final/output.txt new file mode 100644 index 0000000..e969a72 --- /dev/null +++ b/a2_final/output.txt @@ -0,0 +1,103 @@ + ------------------------------------------------------------------- + Average Transaction Duration + ------------------------------------------------------------------- + 0.1ms 1ms 10ms (0.1ms, 1ms, 10ms) + ------------------------------------------------------------------- + Low contention Read only (5 records) + ------------------------------------------------------------------- + Serial 6313.64 685.113 80.3091 218.333 + Locking A 61779.1 7023.37 767.145 2177.67 + Locking B 57497.1 7013.83 763.848 2184.98 + OCC 61041.3 6990.28 767.465 2176.91 + OCC-P 59046.3 6979.77 777.341 2346.17 + MVCC 52127.9 6842.07 773.609 2255.84 + Calvin 49631.2 6908.55 775.621 2365.7 + Calvin_I 62502.6 7114.15 777.667 2208.8 + + Low contention Read only (30 records) + ------------------------------------------------------------------- + Serial 6362.16 733.099 76.5669 238.367 + Locking A 33486.9 6767.38 768.894 2187.82 + Locking B 30057.6 6619.49 757.015 2291.36 + OCC 52873.7 6789.52 758.044 2218.23 + OCC-P 47550 6827.73 774.005 2352.38 + MVCC 29755.6 6610.29 770.066 2284.79 + Calvin 30208 6708.56 778.358 2263.26 + Calvin_I 49857.8 7015.77 775.237 2276.95 + + High contention Read only (5 records) + ------------------------------------------------------------------- + Serial 6533.83 696.912 79.5509 237.414 + Locking A 19231.6 2775.61 314.605 617.182 + Locking B 63547.7 7071.99 765.73 2250.21 + OCC 60617.1 6978.53 767.674 2222.98 + OCC-P 55931.1 6984.07 774.68 2323.05 + MVCC 60764.9 7004.81 774.551 2284.43 + Calvin 55069.9 7052.71 778.26 2366.17 + Calvin_I 61507.5 7072.87 778.564 2367.15 + + High contention Read only (30 records) + ------------------------------------------------------------------- + Serial 6167.82 717.895 80.5363 218.753 + Locking A 4248.91 686.413 87.9072 239.431 + Locking B 56060.7 6963.99 770.102 2311.56 + OCC 55545.7 6901.03 764.023 2285.88 + OCC-P 49578.6 6909.33 770.914 2319.84 + MVCC 47701.6 6649.12 754.794 2254.67 + Calvin 36848.5 6865.1 775.915 2270.72 + Calvin_I 47184.1 7031.64 780.226 2200.85 + + Low contention read-write (5 records) + ------------------------------------------------------------------- + Serial 5518.22 689.275 77.8896 231.573 + Locking A 48847.4 6468.86 652.563 1929.77 + Locking B 49441.3 6834.35 760.01 2102.29 + OCC 55304 6258.31 701.676 2172.76 + OCC-P 46418.7 5541.55 748.62 2395.52 + MVCC 37226.4 5932.7 769.837 2326.69 + Calvin 52865.1 6994.41 773.542 2293.76 + Calvin_I 58051 6923.14 772.343 2309.05 + + Low contention read-write (10 records) + ------------------------------------------------------------------- + Serial 6618.44 702.852 78.994 237.47 + Locking A 53508.3 6774 765.874 2269.97 + Locking B 54511.1 7010.7 761.892 2191.58 + OCC 59593.3 7040.93 751.302 2214.78 + OCC-P 56212.6 6846.18 771.228 2207.09 + MVCC 36932 6664.64 745.806 2283.06 + Calvin 44358.4 6621.14 762.247 2247.41 + Calvin_I 55016.4 6820.03 762.852 2143.3 + + High contention read-write (5 records) + ------------------------------------------------------------------- + Serial 6723 715.211 82.2509 241.427 + Locking A 14221.4 2335.92 288.563 775.02 + Locking B 18471 2729.64 283.535 593.739 + OCC 61561.4 7035.69 765.862 2199.1 + OCC-P 54380.8 6921.56 765.339 2241.02 + MVCC 25807.6 1954.46 450.427 540.566 + Calvin 54263.2 6980.73 773.375 2205.76 + Calvin_I 24595.4 3019.24 320.8 633.946 + + High contention read-write (10 records) + ------------------------------------------------------------------- + Serial 7424.06 782.098 77.7501 237.008 + Locking A 8427.41 1039.34 128.171 308.804 + Locking B 7955.51 1113.16 143.877 358.452 + OCC 56568.1 6979.34 760.904 2209.88 + OCC-P 46433.9 6582.25 759.159 2262.38 + MVCC 17151.9 1369.63 173.687 356.568 + Calvin 46452.7 6852.74 772.802 2283.09 + Calvin_I 12025.9 1299.03 138.089 365.976 + + High contention mixed read only/read-write + ------------------------------------------------------------------- + Serial 8996.61 1035.65 101.01 301.373 + Locking A 5093.6 944.327 111.944 327.471 + Locking B 21099.3 4051.01 478.15 828.36 + OCC 33541.9 4080.74 487.084 910.444 + OCC-P 38406.8 4557.94 528.102 976.781 + MVCC 57002.6 7929.36 926.128 2762.65 + Calvin 20907.9 4474.24 471.702 838.858 + Calvin_I 31050.2 4667.61 498.342 868.454 diff --git a/a2_final/run.sh b/a2_final/run.sh new file mode 100644 index 0000000..fe09afc --- /dev/null +++ b/a2_final/run.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +#SBATCH -A m2404 +#SBATCH --time=30:00 +#SBATCH --nodes=1 +#SBATCH --constraint=cpu +#SBATCH --qos regular + +srun -n1 -c 8 --cpu-bind-cores ./work_steal/src/txn_processor_test diff --git a/a2_final/src/CMakeLists.txt b/a2_final/src/CMakeLists.txt new file mode 100644 index 0000000..51cc550 --- /dev/null +++ b/a2_final/src/CMakeLists.txt @@ -0,0 +1,29 @@ + +add_library(txn STATIC + txn/storage.cc + txn/mvcc_storage.cc + txn/txn.cc + txn/txn_processor.cc + txn/lock_manager.cc + txn/calvin.cc +) +target_link_libraries(txn PUBLIC Threads::Threads) + +add_executable(lock_manager_test + txn/lock_manager_test.cc +) +target_link_libraries(lock_manager_test PUBLIC txn) + +add_executable(txn_processor_test + txn/txn_processor_test.cc +) +target_link_libraries(txn_processor_test PUBLIC txn) + +add_executable(txn_types_test + txn/txn_types_test.cc +) +target_link_libraries(txn_types_test PUBLIC txn) + +add_test(NAME lock_manager_test COMMAND lock_manager_test) +add_test(NAME txn_processor_test COMMAND txn_processor_test) +add_test(NAME txn_types_test COMMAND txn_types_test) diff --git a/a2_final/src/txn/calvin.cc b/a2_final/src/txn/calvin.cc new file mode 100644 index 0000000..d8d840f --- /dev/null +++ b/a2_final/src/txn/calvin.cc @@ -0,0 +1,515 @@ +#include "txn_processor.h" +#include "utils/common.h" +#include +#include +#include +#include + +#include "lock_manager.h" + +/*********************************************** + * Calvin Continuous Execution -- Global Locks * + ***********************************************/ +void TxnProcessor::RunCalvinContScheduler() { + Txn *txn; + + std::unordered_map> shared_holders; + std::unordered_map last_excl; + + while (!stopped_) { + if (txn_requests_.Pop(&txn)) { + + adj_list_lock.lock(); + indegree_lock.lock(); + + adj_list[txn] = {}; + + // Print the adj_list in one go so the lines aren't interleaved + + // Don't add to indegree hashmap right away because if indegree == 0, + // we want to add it to the threadpool right away + int ind = 0; + + // Loop through writeset + for (const Key &key : txn->writeset_) { + // Add an edge between the current txn and all shared holders + if (shared_holders.contains(key)) { + for (auto conflicting_txn : shared_holders[key]) { + if (conflicting_txn != txn && + conflicting_txn->Status() == INCOMPLETE && + !adj_list[conflicting_txn].contains(txn)) { + adj_list[conflicting_txn].insert(txn); + ind++; + } + } + shared_holders[key].clear(); + } + + if (last_excl.contains(key) && last_excl[key] != txn) { + last_excl[key]->neighbors_mutex.lock(); + + if (last_excl[key]->Status() != COMMITTED && + last_excl[key]->Status() != ABORTED) { + // We came in before CalvinExecutorFunc took "snapshot" of + // neighbors + txn->indegree++; + last_excl[key]->neighbors.insert(txn); + } + + last_excl[key]->neighbors_mutex.unlock(); + } + + last_excl[key] = txn; + } + + // Loop through readset + // auto merged_sets = txn->readset_; + // merged_sets.insert(txn->writeset_.begin(), txn->writeset_.end()); + for (const Key &key : txn->readset_) { + // Add to shared holders + if (!shared_holders.contains(key)) { + shared_holders[key] = {}; + } + shared_holders[key].insert(txn); + + // If the last_excl txn is not the current txn, add an edge + if (last_excl.contains(key) && last_excl[key] != txn && + last_excl[key]->Status() == INCOMPLETE && + !adj_list[last_excl[key]].contains(txn)) { + adj_list[last_excl[key]].insert(txn); + ind++; + } + } + + // If current transaction's indegree is 0, add it to the threadpool + if (ind == 0) { + tp_.AddTask([this, txn]() { this->CalvinContExecutorFunc(txn); }); + } else { + // Otherwise, add it to the indegree hashmap + indegree[txn] = ind; + } + indegree_lock.unlock(); + adj_list_lock.unlock(); + } + } +} + +void TxnProcessor::CalvinContExecutorFunc(Txn *txn) { + // Execute txn. + ExecuteTxn(txn); + + // Commit/abort txn according to program logic's commit/abort decision. + // Note: we do this within the worker thread instead of returning + // back to the scheduler thread. + + if (txn->Status() == COMPLETED_C) { + ApplyWrites(txn); + committed_txns_.Push(txn); + txn->status_ = COMMITTED; + } else if (txn->Status() == COMPLETED_A) { + txn->status_ = ABORTED; + } else { + // Invalid TxnStatus! + DIE("Completed Txn has invalid TxnStatus: " << txn->Status()); + } + + // Update indegrees of neighbors + // If any has indegree 0, add them back to the queue + // if (adj_list.find(txn) != adj_list.end()) { + // std::shared_lock + // adj_list_shared_lock(adj_list_lock); + // std::shared_lock + // indegree_shared_lock(indegree_lock); + + adj_list_lock.lock(); + indegree_lock.lock(); + auto neighbors = adj_list[txn]; + for (auto nei : neighbors) { + indegree[nei]--; + if (indegree[nei] == 0) { + tp_.AddTask([this, nei]() { this->CalvinContExecutorFunc(nei); }); + } + } + + adj_list_lock.unlock(); + indegree_lock.unlock(); + + // Return result to client. + txn_results_.Push(txn); +} + +/*********************************************** + * Calvin Continuous Execution -- Indiv Locks * + ***********************************************/ +void TxnProcessor::RunCalvinContIndivScheduler() { + Txn *txn; + + std::unordered_map> shared_holders; + std::unordered_map last_excl; + + while (!stopped_) { + while (txn_requests_.Pop(&txn)) { + std::vector sorted_keys; + sorted_keys.reserve(txn->readset_.size() + txn->writeset_.size()); + sorted_keys.insert(sorted_keys.end(), txn->readset_.begin(), + txn->readset_.end()); + sorted_keys.insert(sorted_keys.end(), txn->writeset_.begin(), + txn->writeset_.end()); + std::sort(sorted_keys.begin(), sorted_keys.end()); + + txn->indegree_mutex.lock(); + txn->indegree = 0; + txn->neighbors.clear(); + + // Handle writeset + for (const Key &key : txn->writeset_) { + if (shared_holders.contains(key)) { + for (auto conflicting_txn : shared_holders[key]) { + if (conflicting_txn != txn) { + if (conflicting_txn->neighbors_mutex.try_lock()) { + + if (conflicting_txn->Status() != COMMITTED && + conflicting_txn->Status() != ABORTED && + !conflicting_txn->neighbors.contains(txn)) { + // We came in before CalvinExecutorFunc took "snapshot" of + // neighbors + txn->indegree++; + conflicting_txn->neighbors.insert(txn); + } + + conflicting_txn->neighbors_mutex.unlock(); + } + } + } + shared_holders[key].clear(); + + } + + else if (last_excl.contains(key) && last_excl[key] != txn) { + // if (last_excl[key]->neighbors_mutex.try_lock()) { + if (last_excl[key]->neighbors_mutex.try_lock()) { + + if (last_excl[key]->Status() != COMMITTED && + last_excl[key]->Status() != ABORTED && + !last_excl[key]->neighbors.contains(txn)) { + // We came in before CalvinExecutorFunc took "snapshot" of + // neighbors + txn->indegree++; + last_excl[key]->neighbors.insert(txn); + } + + last_excl[key]->neighbors_mutex.unlock(); + } + } + + last_excl[key] = txn; + } + + // Handle readset + for (const Key &key : txn->readset_) { + if (!shared_holders.contains(key)) { + shared_holders[key] = {}; + } + shared_holders[key].insert(txn); + + if (last_excl.contains(key) && last_excl[key] != txn) { + if (last_excl[key]->neighbors_mutex.try_lock()) { + + if (last_excl[key]->Status() != COMMITTED && + last_excl[key]->Status() != ABORTED && + !last_excl[key]->neighbors.contains(txn)) { + // We came in before CalvinExecutorFunc took "snapshot" of + // neighbors + txn->indegree++; + last_excl[key]->neighbors.insert(txn); + } + + last_excl[key]->neighbors_mutex.unlock(); + } + } + } + + // If current transaction's indegree is 0, add it to the threadpool + if (txn->indegree == 0) { + tp_.AddTask([this, txn]() { this->CalvinContIndivExecutorFunc(txn); }); + } + txn->indegree_mutex.unlock(); + } + } +} + +void TxnProcessor::CalvinContIndivExecutorFunc(Txn *txn) { + // Execute txn. + // printf("Starting to execute txn %d\n", txn->unique_id_); + ExecuteTxn(txn); + + // Commit/abort txn according to program logic's commit/abort decision. + // Note: we do this within the worker thread instead of returning + // back to the scheduler thread. + if (txn->Status() == COMPLETED_C) { + ApplyWrites(txn); + committed_txns_.Push(txn); + txn->status_ = COMMITTED; + } else if (txn->Status() == COMPLETED_A) { + txn->status_ = ABORTED; + } else { + // Invalid TxnStatus! + DIE("Completed Txn has invalid TxnStatus: " << txn->Status()); + } + + // Update indegrees of neighbors + // if (txn->neighbors_mutex.try_lock()) { + txn->neighbors_mutex.lock(); + std::vector sorted_neighbors(txn->neighbors.begin(), + txn->neighbors.end()); + // std::sort(sorted_neighbors.begin(), sorted_neighbors.end()); + + for (Txn *nei : sorted_neighbors) { + // test with trylock here + nei->indegree_mutex.lock(); + nei->indegree--; + if (nei->indegree == 0) { + tp_.AddTask([this, nei]() { this->CalvinContIndivExecutorFunc(nei); }); + } + nei->indegree_mutex.unlock(); + } + + // Return result to client. + txn_results_.Push(txn); + txn->neighbors_mutex.unlock(); +} + +/*********************************************** + * Calvin Epoch Execution * + ***********************************************/ + +void TxnProcessor::RunCalvinEpochSequencer() { + Txn *txn; + // save time of last epoch for calvin sequencer + auto last_epoch_time = std::chrono::high_resolution_clock::now(); + // set up current epoch + Epoch *current_epoch = new Epoch(); + while (!stopped_) { + // Add the txn to the epoch. + if (txn_requests_.Pop(&txn)) { + current_epoch->push(txn); + } + + // check if we need to close the epoch + auto curr_time = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast( + curr_time - last_epoch_time); + if (duration.count() > 5) { + // new epoch is out of scope + last_epoch_time = curr_time; + + // make new epoch if last epoch has anything in it + if (!current_epoch->empty()) { + epoch_queue.Push(current_epoch); + current_epoch = new Epoch(); + } + } + } +} + +void *TxnProcessor::calvin_sequencer_helper(void *arg) { + reinterpret_cast(arg)->RunCalvinEpochSequencer(); + return NULL; +} + +void TxnProcessor::RunCalvinEpochScheduler() { + + // Start Calvin Sequencer + pthread_create(&calvin_sequencer_thread, NULL, calvin_sequencer_helper, + reinterpret_cast(this)); + // Start Calvin Epoch Executor + // pthread_create(&calvin_epoch_executor_thread, NULL, + // calvin_epoch_executor_helper, reinterpret_cast(this)); + // for(int i = 0; i < THREAD_COUNT; i++) { + // tp_.AddTask([this]() { this->CalvinEpochExecutorLMAO(); }); + // } + + Epoch *curr_epoch; + EpochDag *dag; + while (!stopped_) { + // Get the next epoch + if (epoch_queue.Pop(&curr_epoch)) { + // Create new DAG for this epoch + std::unordered_map> shared_holders; + std::unordered_map last_excl; + + dag = (EpochDag *)malloc(sizeof(EpochDag)); + + std::unordered_map> *adj_list = + new std::unordered_map>(); + std::unordered_map> *indegree = + new std::unordered_map>(); + std::queue *root_txns = new std::queue(); + + Txn *txn; + while (!curr_epoch->empty()) { + txn = curr_epoch->front(); + curr_epoch->pop(); + adj_list->emplace(txn, std::unordered_set()); + indegree->emplace(txn, 0); + + // Loop through readset + for (const Key &key : txn->readset_) { + // Add to shared holders + if (!shared_holders.contains(key)) { + shared_holders[key] = std::unordered_set(); + } + shared_holders[key].insert(txn); + + // If the last_excl txn is not the current txn, add an edge + + // add an edge between the last_excl txn and the current txn + // if we read a key that was last written by last_excl txn + if (last_excl.contains(key) && + !adj_list->at(last_excl[key]).contains(txn)) { + adj_list->at(last_excl[key]).insert(txn); + indegree->at(txn)++; + } + } + // Loop through writeset + for (const Key &key : txn->writeset_) { + // Add an edge between the current txn and all shared holders + if (shared_holders.contains(key)) { + for (auto conflicting_txn : shared_holders[key]) { + if (!adj_list->at(conflicting_txn).contains(txn)) { + adj_list->at(conflicting_txn).insert(txn); + indegree->at(txn)++; + } + } + shared_holders[key].clear(); + } + last_excl[key] = txn; + } + + // set as root if indegree of 0 + if (indegree->at(txn) == 0) { + root_txns->push(txn); + } + } + // finalize new epoch dag + dag->adj_list = adj_list; + dag->indegree = indegree; + dag->root_txns = root_txns; + // dag->indegree_locks = indegree_locks; + + // push dag to queue for executor to read + // epoch_dag_queue.Push(dag); + CalvinExecuteSingleEpoch(dag); + } + } +} + +void TxnProcessor::CalvinEpochExecutor() { + num_txns_left_in_epoch = 0; + while (!stopped_) { + if (epoch_dag_queue.Pop(¤t_epoch_dag)) { + if (num_txns_left_in_epoch != 0) { + std::cout << "Num transactions in epoch: " << num_txns_left_in_epoch + << std::endl; + std::cout << "UH OH--------------------------------UH OH" << std::endl; + } + num_txns_left_in_epoch = current_epoch_dag->adj_list->size(); + Txn *txn; + std::queue *root_txns = current_epoch_dag->root_txns; + + // add all root txns to threadpool + while (!root_txns->empty()) { + txn = root_txns->front(); + root_txns->pop(); + tp_.AddTask([this, txn]() { this->CalvinEpochExecutorFunc(txn); }); + } + + // wait for epoch to end executing + int sleep_duration = 1; // in microseconds + while (num_txns_left_in_epoch > 0) { + usleep(sleep_duration); + // Back off exponentially. + if (sleep_duration < 32) + sleep_duration *= 2; + } + delete current_epoch_dag->adj_list; + delete current_epoch_dag->indegree; + delete current_epoch_dag->root_txns; + free(current_epoch_dag); + current_epoch_dag = NULL; + } + } +} + +void TxnProcessor::CalvinExecuteSingleEpoch(EpochDag *epoch_dag) { + num_txns_left_in_epoch = 0; + // if (num_txns_left_in_epoch != 0) { + // std::cout << "Num transactions in epoch: " << num_txns_left_in_epoch + // << std::endl; + // std::cout << "UH OH--------------------------------UH OH" << std::endl; + // } + current_epoch_dag = epoch_dag; + num_txns_left_in_epoch = current_epoch_dag->adj_list->size(); + Txn *txn; + std::queue *root_txns = current_epoch_dag->root_txns; + + // add all root txns to threadpool + while (!root_txns->empty()) { + txn = root_txns->front(); + root_txns->pop(); + tp_.AddTask([this, txn]() { this->CalvinEpochExecutorFunc(txn); }); + } + + // wait for epoch to end executing + int sleep_duration = 1; // in microseconds + while (num_txns_left_in_epoch > 0) { + usleep(sleep_duration); + // Back off exponentially. + if (sleep_duration < 32) + sleep_duration *= 2; + } + delete current_epoch_dag->adj_list; + delete current_epoch_dag->indegree; + delete current_epoch_dag->root_txns; + free(current_epoch_dag); + current_epoch_dag = NULL; +} + +void *TxnProcessor::calvin_epoch_executor_helper(void *arg) { + reinterpret_cast(arg)->CalvinEpochExecutor(); + return NULL; +} + +void TxnProcessor::CalvinEpochExecutorFunc(Txn *txn) { + ExecuteTxn(txn); + + // Commit/abort txn according to program logic's commit/abort decision. + // Note: we do this within the worker thread instead of returning + // back to the scheduler thread. + if (txn->Status() == COMPLETED_C) { + ApplyWrites(txn); + committed_txns_.Push(txn); + txn->status_ = COMMITTED; + } else if (txn->Status() == COMPLETED_A) { + txn->status_ = ABORTED; + } else { + // Invalid TxnStatus! + DIE("Completed Txn has invalid TxnStatus: " << txn->Status()); + } + + // Update indegrees of neighbors + // If any has indegree 0, add them back to the queue + auto neighbors = current_epoch_dag->adj_list->at(txn); + for (Txn *blocked_txn : neighbors) { + if (current_epoch_dag->indegree->at(blocked_txn)-- == 1) { + tp_.AddTask([this, blocked_txn]() { + this->CalvinEpochExecutorFunc(blocked_txn); + }); + } + } + num_txns_left_in_epoch--; + + // Return result to client. + txn_results_.Push(txn); +} diff --git a/a2_final/src/txn/lock_manager.cc b/a2_final/src/txn/lock_manager.cc new file mode 100644 index 0000000..0974bd3 --- /dev/null +++ b/a2_final/src/txn/lock_manager.cc @@ -0,0 +1,262 @@ +#include "lock_manager.h" + +LockManagerA::LockManagerA(std::deque *ready_txns) { + // // printf("creating new lock manager?\n"); + ready_txns_ = ready_txns; +} + +bool LockManagerA::WriteLock(Txn *txn, const Key &key) { + // + // Implement this method! + + // get the queue for the key + if (lock_table_.find(key) == lock_table_.end()) { + // key isn't ins the table yet + lock_table_[key] = new std::deque(); + } + std::deque *lr_queue = lock_table_[key]; + + // calculate how many transactions were already present in queue + int num_before = lr_queue->size(); + + // create and add lock request for this transaction + lr_queue->push_back(LockRequest(LockMode::EXCLUSIVE, txn)); + + // APPARENTLY WE DONT ADD TO THE READY LIST????? + if (num_before > 0) { + // add transaction to waiting list + + if (txn_waits_.find(txn) == txn_waits_.end()) { + // txn was not in the map + // add transaction to map + txn_waits_[txn] = num_before; + } else { + // add transaction to map + txn_waits_[txn] += num_before; + } + } + return num_before == 0; +} + +bool LockManagerA::ReadLock(Txn *txn, const Key &key) { + // Since Part 1A implements ONLY exclusive locks, calls to ReadLock can + // simply use the same logic as 'WriteLock'. + return WriteLock(txn, key); +} + +void LockManagerA::Release(Txn *txn, const Key &key) { + // + // Implement this method! + + if (lock_table_.find(key) == lock_table_.end()) { + // key not in lock / can't actually release + return; + } + // get queue for the key + std::deque *lr_queue = lock_table_[key]; + + // find location of this transaction in the queue + size_t txn_index = lr_queue->size(); + for (size_t i = 0; i < lr_queue->size(); i++) { + if (lr_queue->at(i).txn_ == txn) { + txn_index = i; + break; + } + } + if (txn_index == lr_queue->size()) { + // this transaction doesn't have a lock on this key + return; + } + + // remove this transaction from the queue + lr_queue->erase(lr_queue->begin() + txn_index); + + // update following elements + for (size_t i = txn_index; i < lr_queue->size(); i++) { + // get transaction waiting for us to release a lock + Txn *update_txn = lr_queue->at(i).txn_; + // update number of transactions before it + txn_waits_[update_txn]--; + // if the transaction is no longer waiting for a lock + // remove it from txn_waits_ and add to read_txns_ + if (txn_waits_[update_txn] == 0) { + ready_txns_->push_back(update_txn); + txn_waits_.erase(update_txn); + } + } +} + +// NOTE: The owners input vector is NOT assumed to be empty. +LockMode LockManagerA::Status(const Key &key, std::vector *owners) { + // + // Implement this method! + owners->clear(); + + if (lock_table_.find(key) == lock_table_.end() || + lock_table_[key]->size() == 0) { + // the key isn't in the lock table or empty + return LockMode::UNLOCKED; + } else { + owners->push_back(lock_table_[key]->at(0).txn_); + return LockMode::EXCLUSIVE; + } +} + +LockManagerB::LockManagerB(std::deque *ready_txns) { + ready_txns_ = ready_txns; +} + +bool LockManagerB::WriteLock(Txn *txn, const Key &key) { + // printf("write locking key: %d\n", key); + + // + // Implement this method! + + // first let's get the correct Lock Request Queue + if (lock_table_.find(key) == lock_table_.end()) { + // queue doesn't exist yet + lock_table_[key] = new std::deque(); + } + + std::deque *lr_queue = lock_table_[key]; + + size_t num_before = lr_queue->size(); + + // add lock request to queue + lr_queue->push_back(LockRequest(LockMode::EXCLUSIVE, txn)); + + if (num_before > 0) { + // can't get lock yet + // add txn to waitlist + if (txn_waits_.find(txn) == txn_waits_.end()) { + txn_waits_[txn] = 0; + } + txn_waits_[txn] += num_before; + } + + return num_before == 0; +} + +bool LockManagerB::ReadLock(Txn *txn, const Key &key) { + // + // Implement this method! + // printf("read locking key: %d\n", key); + + if (lock_table_.find(key) == lock_table_.end()) { + // queue doesn't exist yet + lock_table_[key] = new std::deque(); + } + + // first let's get the correct Lock Request Queue + std::deque *lr_queue = lock_table_[key]; + + int num_exclusive_before = 0; + // check for exclusive transactions before this one + for (size_t i = 0; i < lr_queue->size(); i++) { + if (lr_queue->at(i).mode_ == LockMode::EXCLUSIVE) { + num_exclusive_before++; + } + } + + // add lock request to queue + lr_queue->push_back(LockRequest(LockMode::SHARED, txn)); + + if (num_exclusive_before > 0) { + // can't get lock yet + // add txn to waitlist + if (txn_waits_.find(txn) == txn_waits_.end()) { + txn_waits_[txn] = 0; + } + txn_waits_[txn] += num_exclusive_before; + } + + return num_exclusive_before == 0; +} + +void LockManagerB::Release(Txn *txn, const Key &key) { + // Implement this method! + + if (lock_table_.find(key) == lock_table_.end()) { + // don't need to do anything if the lock doesn't exist on the key + return; + } + + std::deque *lr_queue = lock_table_[key]; + LockMode released_type; + // find location of this transaction in the queue + size_t txn_index = lr_queue->size(); + for (size_t i = 0; i < lr_queue->size(); i++) { + if (lr_queue->at(i).txn_ == txn) { + txn_index = i; + released_type = lr_queue->at(i).mode_; + break; + } + } + + if (txn_index == lr_queue->size()) { + // this transaction doesn't have a lock on the key + return; + } + + // remove this transaction from the queue + lr_queue->erase(lr_queue->begin() + txn_index); + + // update following elements + for (size_t i = txn_index; i < lr_queue->size(); i++) { + + // get transaction waiting for us to release a lock + LockMode update_type = lr_queue->at(i).mode_; + Txn *update_txn = lr_queue->at(i).txn_; + + // update number of transactions before it if necessary + // shared locks only count exclusives before them + // exlusive lock count all before them + if (released_type == LockMode::EXCLUSIVE || + update_type == LockMode::EXCLUSIVE) { + if (txn_waits_.find(update_txn) == txn_waits_.end()) { + printf("Shouldn't be here in release lock :(\n"); + // + } + txn_waits_[update_txn]--; + // if the transaction is no longer waiting for a lock + // remove it from txn_waits_ and add to read_txns_ + if (txn_waits_[update_txn] == 0) { + ready_txns_->push_back(update_txn); + txn_waits_.erase(update_txn); + } + } + } +} + +// NOTE: The owners input vector is NOT assumed to be empty. +LockMode LockManagerB::Status(const Key &key, std::vector *owners) { + // Implement this method! + if (lock_table_.find(key) == lock_table_.end()) { + return UNLOCKED; + } + + owners->clear(); + + std::deque *lr_queue = lock_table_[key]; + + LockMode mode; + + if (lr_queue->size() == 0) { + // empty queue + mode = LockMode::UNLOCKED; + } else if (lr_queue->at(0).mode_ == LockMode::EXCLUSIVE) { + mode = LockMode::EXCLUSIVE; + owners->push_back(lr_queue->at(0).txn_); + } else { + mode = LockMode::SHARED; + for (size_t i = 0; i < lr_queue->size(); i++) { + LockRequest lr = lr_queue->at(i); + if (lr.mode_ == LockMode::EXCLUSIVE) { + break; + } else { + owners->push_back(lr.txn_); + } + } + } + return mode; +} diff --git a/a2_final/src/txn/lock_manager.h b/a2_final/src/txn/lock_manager.h new file mode 100644 index 0000000..6bd4f77 --- /dev/null +++ b/a2_final/src/txn/lock_manager.h @@ -0,0 +1,127 @@ +// Interface for lock managers in the system. + +#ifndef _LOCK_MANAGER_H_ +#define _LOCK_MANAGER_H_ + +#include +#include +#include +#include + +#include "utils/common.h" + +class Txn; + +// This interface supports locks being held in both read/shared and +// write/exclusive modes. +enum LockMode { + UNLOCKED = 0, + SHARED = 1, + EXCLUSIVE = 2, +}; + +class LockManager { +public: + virtual ~LockManager() {} + // Attempts to grant a read lock to the specified transaction, enqueueing + // request in lock table. Returns true if lock is immediately granted, else + // returns false. + // + // Requires: Neither ReadLock nor WriteLock has previously been called with + // this txn and key. + virtual bool ReadLock(Txn *txn, const Key &key) = 0; + + // Attempts to grant a write lock to the specified transaction, enqueueing + // request in lock table. Returns true if lock is immediately granted, else + // returns false. + // + // Requires: Neither ReadLock nor WriteLock has previously been called with + // this txn and key. + virtual bool WriteLock(Txn *txn, const Key &key) = 0; + + // Releases lock held by 'txn' on 'key', or cancels any pending request for + // a lock on 'key' by 'txn'. If 'txn' held an EXCLUSIVE lock on 'key' (or was + // the sole holder of a SHARED lock on 'key'), then the next request(s) in the + // request queue is granted. If the granted request(s) corresponds to a + // transaction that has now acquired ALL of its locks, that transaction is + // appended to the 'ready_txns_' queue. + // + // IMPORTANT NOTE: In order to know WHEN a transaction is ready to run, you + // may need to track its lock acquisition progress during the lock request + // process. + // (Hint: Use 'LockManager::txn_waits_' defined below.) + virtual void Release(Txn *txn, const Key &key) = 0; + + // Sets '*owners' to contain the txn IDs of all txns holding the lock, and + // returns the current LockMode of the lock: UNLOCKED if it is not currently + // held, SHARED or EXCLUSIVE if it is, depending on the current state. + virtual LockMode Status(const Key &key, std::vector *owners) = 0; + +protected: + // The LockManager's lock table tracks all lock requests. For a given key, if + // 'lock_table_' contains a nonempty deque, then the item with that key is + // locked and either: + // + // (a) first element in the deque specifies the owner if that item is a + // request for an EXCLUSIVE lock, or + // + // (b) a SHARED lock is held by all elements of the longest prefix of the + // deque containing only SHARED lock requests. + // + // For example, if lock_table_["key1"] points to a deque containing + // + // (&Txn1, SHARED), (&Txn2, SHARED), (&Txn3, EXCLUSIVE), (&Txn4, SHARED) + // + // then Txn1 and Txn2 currently hold a SHARED lock on the record with key + // "key1". Only when they BOTH release their locks will Txn3 acquire its + // exclusive lock on the record. (Note that since Txn4 comes after Txn3, it + // cannot acquire a lock until after Txn3 has released its lock, so it cannot + // share the lock with Txn1 and Txn2.) + // + // As a second example, if lock_table_["key1"] points to a deque containing + // + // (&Txn1, EXCLUSIVE), (&Txn2, SHARED), (&Txn3, SHARED), (Txn4, EXCLUSIVE) + // + // then Txn1 currently holds an EXCLUSIVE lock on "key1". When Txn1 releases + // its lock, Txn2 and Txn3 will simultaneously acquire SHARED locks on "key1". + struct LockRequest { + LockRequest(LockMode m, Txn *t) : txn_(t), mode_(m) {} + Txn *txn_; // Pointer to txn requesting the lock. + LockMode mode_; // Specifies whether this is a read or write lock request. + }; + std::unordered_map *> lock_table_; + + // Queue of pointers to transactions that: + // (a) were previously blocked on acquiring at least one lock, and + // (b) have now acquired all locks that they have requested. + std::deque *ready_txns_; + + // Tracks all txns still waiting on acquiring at least one lock. Entries in + // 'txn_waits_' are invalided by any call to Release() with the entry's + // txn. + std::unordered_map txn_waits_; +}; + +// Version of the LockManager implementing ONLY exclusive locks. +class LockManagerA : public LockManager { +public: + explicit LockManagerA(std::deque *ready_txns); + inline virtual ~LockManagerA() {} + virtual bool ReadLock(Txn *txn, const Key &key); + virtual bool WriteLock(Txn *txn, const Key &key); + virtual void Release(Txn *txn, const Key &key); + virtual LockMode Status(const Key &key, std::vector *owners); +}; + +// Version of the LockManager implementing both shared and exclusive locks. +class LockManagerB : public LockManager { +public: + explicit LockManagerB(std::deque *ready_txns); + inline virtual ~LockManagerB() {} + virtual bool ReadLock(Txn *txn, const Key &key); + virtual bool WriteLock(Txn *txn, const Key &key); + virtual void Release(Txn *txn, const Key &key); + virtual LockMode Status(const Key &key, std::vector *owners); +}; + +#endif // _LOCK_MANAGER_H_ diff --git a/a2_final/src/txn/lock_manager_test.cc b/a2_final/src/txn/lock_manager_test.cc new file mode 100644 index 0000000..1c1453a --- /dev/null +++ b/a2_final/src/txn/lock_manager_test.cc @@ -0,0 +1,189 @@ +#include "lock_manager.h" + +#include +#include + +#include "utils/testing.h" + +TEST(LockManagerA_SimpleLocking) { + std::deque ready_txns; + LockManagerA lm(&ready_txns); + std::vector owners; + + Txn *t1 = reinterpret_cast(1); + Txn *t2 = reinterpret_cast(2); + Txn *t3 = reinterpret_cast(3); + + // Txn 1 acquires read lock. + lm.ReadLock(t1, 101); + ready_txns.push_back(t1); // Txn 1 is ready. + EXPECT_EQ(EXCLUSIVE, lm.Status(101, &owners)); + EXPECT_EQ(1, owners.size()); + EXPECT_EQ(t1, owners[0]); + EXPECT_EQ(1, ready_txns.size()); + EXPECT_EQ(t1, ready_txns.at(0)); + + // Txn 2 requests write lock. Not granted. + lm.WriteLock(t2, 101); + EXPECT_EQ(EXCLUSIVE, lm.Status(101, &owners)); + EXPECT_EQ(1, owners.size()); + EXPECT_EQ(t1, owners[0]); + EXPECT_EQ(1, ready_txns.size()); + + // Txn 3 requests read lock. Not granted. + lm.ReadLock(t3, 101); + EXPECT_EQ(EXCLUSIVE, lm.Status(101, &owners)); + EXPECT_EQ(1, owners.size()); + EXPECT_EQ(t1, owners[0]); + EXPECT_EQ(1, ready_txns.size()); + + // Txn 1 releases lock. Txn 2 is granted write lock. + lm.Release(t1, 101); + EXPECT_EQ(EXCLUSIVE, lm.Status(101, &owners)); + EXPECT_EQ(1, owners.size()); + EXPECT_EQ(t2, owners[0]); + EXPECT_EQ(2, ready_txns.size()); + EXPECT_EQ(t2, ready_txns.at(1)); + + // Txn 2 releases lock. Txn 3 is granted read lock. + lm.Release(t2, 101); + EXPECT_EQ(EXCLUSIVE, lm.Status(101, &owners)); + EXPECT_EQ(1, owners.size()); + EXPECT_EQ(t3, owners[0]); + EXPECT_EQ(3, ready_txns.size()); + EXPECT_EQ(t3, ready_txns.at(2)); + + END; +} + +TEST(LockManagerA_LocksReleasedOutOfOrder) { + std::deque ready_txns; + LockManagerA lm(&ready_txns); + std::vector owners; + + Txn *t1 = reinterpret_cast(1); + Txn *t2 = reinterpret_cast(2); + Txn *t3 = reinterpret_cast(3); + Txn *t4 = reinterpret_cast(4); + + lm.ReadLock(t1, 101); // Txn 1 acquires read lock. + ready_txns.push_back(t1); // Txn 1 is ready. + lm.WriteLock(t2, 101); // Txn 2 requests write lock. Not granted. + lm.ReadLock(t3, 101); // Txn 3 requests read lock. Not granted. + lm.ReadLock(t4, 101); // Txn 4 requests read lock. Not granted. + + lm.Release(t2, 101); // Txn 2 cancels write lock request. + + // Txn 1 should now have a read lock and Txns 3 and 4 should be next in line. + EXPECT_EQ(EXCLUSIVE, lm.Status(101, &owners)); + EXPECT_EQ(1, owners.size()); + EXPECT_EQ(t1, owners[0]); + + // Txn 1 releases lock. Txn 3 is granted read lock. + lm.Release(t1, 101); + EXPECT_EQ(EXCLUSIVE, lm.Status(101, &owners)); + EXPECT_EQ(1, owners.size()); + EXPECT_EQ(t3, owners[0]); + EXPECT_EQ(2, ready_txns.size()); + EXPECT_EQ(t3, ready_txns.at(1)); + + // Txn 3 releases lock. Txn 4 is granted read lock. + lm.Release(t3, 101); + EXPECT_EQ(EXCLUSIVE, lm.Status(101, &owners)); + EXPECT_EQ(1, owners.size()); + EXPECT_EQ(t4, owners[0]); + EXPECT_EQ(3, ready_txns.size()); + EXPECT_EQ(t4, ready_txns.at(2)); + + END; +} + +TEST(LockManagerB_SimpleLocking) { + std::deque ready_txns; + LockManagerB lm(&ready_txns); + std::vector owners; + + Txn *t1 = reinterpret_cast(1); + Txn *t2 = reinterpret_cast(2); + Txn *t3 = reinterpret_cast(3); + + // Txn 1 acquires read lock. + lm.ReadLock(t1, 101); + ready_txns.push_back(t1); // Txn 1 is ready. + EXPECT_EQ(SHARED, lm.Status(101, &owners)); + EXPECT_EQ(1, owners.size()); + EXPECT_EQ(t1, owners[0]); + EXPECT_EQ(1, ready_txns.size()); + EXPECT_EQ(t1, ready_txns.at(0)); + + // Txn 2 requests write lock. Not granted. + lm.WriteLock(t2, 101); + EXPECT_EQ(SHARED, lm.Status(101, &owners)); + EXPECT_EQ(1, owners.size()); + EXPECT_EQ(t1, owners[0]); + EXPECT_EQ(1, ready_txns.size()); + + // Txn 3 requests read lock. Not granted. + lm.ReadLock(t3, 101); + EXPECT_EQ(SHARED, lm.Status(101, &owners)); + EXPECT_EQ(1, owners.size()); + EXPECT_EQ(t1, owners[0]); + EXPECT_EQ(1, ready_txns.size()); + + // Txn 1 releases lock. Txn 2 is granted write lock. + lm.Release(t1, 101); + EXPECT_EQ(EXCLUSIVE, lm.Status(101, &owners)); + EXPECT_EQ(1, owners.size()); + EXPECT_EQ(t2, owners[0]); + EXPECT_EQ(2, ready_txns.size()); + EXPECT_EQ(t2, ready_txns.at(1)); + + // Txn 2 releases lock. Txn 3 is granted read lock. + lm.Release(t2, 101); + EXPECT_EQ(SHARED, lm.Status(101, &owners)); + EXPECT_EQ(1, owners.size()); + EXPECT_EQ(t3, owners[0]); + EXPECT_EQ(3, ready_txns.size()); + EXPECT_EQ(t3, ready_txns.at(2)); + + END; +} + +TEST(LockManagerB_LocksReleasedOutOfOrder) { + std::deque ready_txns; + LockManagerB lm(&ready_txns); + std::vector owners; + + Txn *t1 = reinterpret_cast(1); + Txn *t2 = reinterpret_cast(2); + Txn *t3 = reinterpret_cast(3); + Txn *t4 = reinterpret_cast(4); + + lm.ReadLock(t1, 101); // Txn 1 acquires read lock. + ready_txns.push_back(t1); // Txn 1 is ready. + lm.WriteLock(t2, 101); // Txn 2 requests write lock. Not granted. + lm.ReadLock(t3, 101); // Txn 3 requests read lock. Not granted. + lm.ReadLock(t4, 101); // Txn 4 requests read lock. Not granted. + + lm.Release(t2, 101); // Txn 2 cancels write lock request. + + // Txns 1, 3 and 4 should now have a shared lock. + EXPECT_EQ(SHARED, lm.Status(101, &owners)); + EXPECT_EQ(3, owners.size()); + EXPECT_EQ(t1, owners[0]); + EXPECT_EQ(t3, owners[1]); + EXPECT_EQ(t4, owners[2]); + EXPECT_EQ(3, ready_txns.size()); + EXPECT_EQ(t1, ready_txns.at(0)); + EXPECT_EQ(t3, ready_txns.at(1)); + EXPECT_EQ(t4, ready_txns.at(2)); + + END; +} + +int main(int argc, char **argv) { + LockManagerA_SimpleLocking(); + LockManagerA_LocksReleasedOutOfOrder(); + LockManagerB_SimpleLocking(); + LockManagerB_LocksReleasedOutOfOrder(); +} diff --git a/a2_final/src/txn/mvcc_storage.cc b/a2_final/src/txn/mvcc_storage.cc new file mode 100644 index 0000000..c52a030 --- /dev/null +++ b/a2_final/src/txn/mvcc_storage.cc @@ -0,0 +1,119 @@ +#include "mvcc_storage.h" + +// Init the storage +void MVCCStorage::InitStorage() { + for (int i = 0; i < 1000000; i++) { + Write(i, 0, 0); + std::mutex *key_mutex = new std::mutex(); + mutexs_[i] = key_mutex; + } +} + +// Free memory. +MVCCStorage::~MVCCStorage() { + for (auto it = mvcc_data_.begin(); it != mvcc_data_.end(); ++it) { + delete it->second; + } + + mvcc_data_.clear(); + + for (auto it = mutexs_.begin(); it != mutexs_.end(); ++it) { + delete it->second; + } + + mutexs_.clear(); +} + +// Lock the key to protect its version_list. Remember to lock the key when you +// read/update the version_list +void MVCCStorage::Lock(Key key) { mutexs_[key]->lock(); } + +// Unlock the key. +void MVCCStorage::Unlock(Key key) { mutexs_[key]->unlock(); } + +// MVCC Read +// If there exists a record for the specified key, sets '*result' equal to +// the value associated with the key and returns true, else returns false; +// The third parameter is the txn_unique_id(txn timestamp), which is used for +// MVCC. +bool MVCCStorage::Read(Key key, Value *result, int txn_unique_id) { + // + // Implement this method! + + // Hint: Iterate the version_lists and return the version whose write + // timestamp (version_id) is the largest write timestamp less than or equal to + // txn_unique_id. + + // Check if the key exists in mvcc_data_ + if (mvcc_data_.count(key) == 0) { + return false; + } + + for (auto version : *mvcc_data_[key]) { + // Return the first version whose version_id is less than or equal to + // txn_unique_id This assumes that the version list is sorted in descending + // order + if (version->version_id_ <= txn_unique_id) { + *result = version->value_; + version->max_read_id_ = txn_unique_id; + return true; + } + } + + return false; +} + +// Check whether the txn executed on the latest version of the key. +bool MVCCStorage::CheckKey(Key key, int txn_unique_id) { + // + // Implement this method! + + // Hint: Before all writes are applied (and SSI reads are validated), we need + // to make sure that each key was accessed safely based on MVCC timestamp + // ordering protocol. This method only checks one key, so you should call this + // method for each key (as necessary). Return true if this key passes the + // check, return false if not. Note that you don't have to call Lock(key) in + // this method, just call Lock(key) before you call this method and call + // Unlock(key) afterward. + + // If key doesn't exist, or if deque is empty for some reason, return false + if (mvcc_data_.count(key) == 0 || mvcc_data_[key]->empty()) { + return false; + } + + // Assuming that the version list is sorted in descending order + return txn_unique_id >= mvcc_data_[key]->front()->version_id_; +} + +// MVCC Write, call this method only if CheckWrite return true. +// Inserts a new version with key and value +// The third parameter is the txn_unique_id(txn timestamp), which is used for +// MVCC. +void MVCCStorage::Write(Key key, Value value, int txn_unique_id) { + // + // Implement this method! + + // Hint: Insert a new version (malloc a Version and specify its + // value/version_id/max_read_id) into the version_lists. Note that + // InitStorage() also calls this method to init storage. Note that you don't + // have to call Lock(key) in this method, just call Lock(key) before you call + // this method and call Unlock(key) afterward. Note that the performance would + // be much better if you organize the versions in decreasing order. + + auto version = new Version(); + version->value_ = value; + version->version_id_ = txn_unique_id; + version->max_read_id_ = 0; + + if (mvcc_data_.count(key) == 0) { + mvcc_data_[key] = new std::deque(); + } + + // Insert the new version in descending order + auto it = mvcc_data_[key]->begin(); + while (it != mvcc_data_[key]->end() && (*it)->version_id_ > txn_unique_id) { + ++it; + } + mvcc_data_[key]->insert(it, version); +} + diff --git a/a2_final/src/txn/mvcc_storage.h b/a2_final/src/txn/mvcc_storage.h new file mode 100644 index 0000000..ae55ce0 --- /dev/null +++ b/a2_final/src/txn/mvcc_storage.h @@ -0,0 +1,58 @@ +#ifndef _MVCC_STORAGE_H_ +#define _MVCC_STORAGE_H_ + +#include "storage.h" +#include +#include + +// MVCC 'version' structure +struct Version { + Value value_; // The value of this version + int max_read_id_; // Largest timestamp of a transaction that read the version + int version_id_; // Timestamp of the transaction that created(wrote) the + // version +}; + +// MVCC storage +class MVCCStorage : public Storage { +public: + // If there exists a record for the specified key, sets '*result' equal to + // the value associated with the key and returns true, else returns false; + // The third parameter is the txn_unique_id(txn timestamp), which is used for + // MVCC. + virtual bool Read(Key key, Value *result, int txn_unique_id = 0); + + // Inserts a new version with key and value + // The third parameter is the txn_unique_id(txn timestamp), which is used for + // MVCC. + virtual void Write(Key key, Value value, int txn_unique_id = 0); + + // Returns the timestamp at which the record with the specified key was last + // updated (returns 0 if the record has never been updated). This is used for + // OCC. + virtual double Timestamp(Key key) { return 0; } + // Init storage + virtual void InitStorage(); + + // Lock the version_list of key + virtual void Lock(Key key); + + // Unlock the version_list of key + virtual void Unlock(Key key); + + // Check whether the txn executed on the latest version of the key. + virtual bool CheckKey(Key key, int txn_unique_id); + + virtual ~MVCCStorage(); + +private: + friend class TxnProcessor; + + // Storage for MVCC, each key has a linklist of versions + std::unordered_map *> mvcc_data_; + + // Mutexs for each key + std::unordered_map mutexs_; +}; + +#endif // _MVCC_STORAGE_H_ diff --git a/a2_final/src/txn/storage.cc b/a2_final/src/txn/storage.cc new file mode 100644 index 0000000..920c6ae --- /dev/null +++ b/a2_final/src/txn/storage.cc @@ -0,0 +1,29 @@ +#include "storage.h" + +bool Storage::Read(Key key, Value *result, int txn_unique_id) { + if (data_.count(key)) { + *result = data_[key]; + return true; + } else { + return false; + } +} + +// Write value and timestamps +void Storage::Write(Key key, Value value, int txn_unique_id) { + data_[key] = value; + timestamps_[key] = GetTime(); +} + +double Storage::Timestamp(Key key) { + if (timestamps_.count(key) == 0) + return 0; + return timestamps_[key]; +} + +// Init the storage +void Storage::InitStorage() { + for (int i = 0; i < 1000000; i++) { + Write(i, 0, 0); + } +} diff --git a/a2_final/src/txn/storage.h b/a2_final/src/txn/storage.h new file mode 100644 index 0000000..c0e7e3e --- /dev/null +++ b/a2_final/src/txn/storage.h @@ -0,0 +1,46 @@ +#ifndef _STORAGE_H_ +#define _STORAGE_H_ + +#include + +#include "txn.h" + +class Storage { +public: + // If there exists a record for the specified key, sets '*result' equal to + // the value associated with the key and returns true, else returns false; + // Note that the third parameter is only used for MVCC, the default vaule is + // 0. + virtual bool Read(Key key, Value *result, int txn_unique_id = 0); + + // Inserts the record , replacing any previous record with the + // same key. + // Note that the third parameter is only used for MVCC, the default vaule is + // 0. + virtual void Write(Key key, Value value, int txn_unique_id = 0); + + // Returns the timestamp at which the record with the specified key was last + // updated (returns 0 if the record has never been updated). This is used for + // OCC. + virtual double Timestamp(Key key); + + // Init storage + virtual void InitStorage(); + + virtual ~Storage() {} + // The following methods are only used for MVCC + virtual void Lock(Key key) {} + virtual void Unlock(Key key) {} + virtual bool CheckWrite(Key key, int txn_unique_id) { return true; } + +private: + friend class TxnProcessor; + + // Collection of pairs. Use this for single-version storage + std::unordered_map data_; + + // Timestamps at which each key was last updated. + std::unordered_map timestamps_; +}; + +#endif // _STORAGE_H_ diff --git a/a2_final/src/txn/txn.cc b/a2_final/src/txn/txn.cc new file mode 100644 index 0000000..5a1a923 --- /dev/null +++ b/a2_final/src/txn/txn.cc @@ -0,0 +1,56 @@ +#include "txn.h" + +bool Txn::Read(const Key &key, Value *value) { + // Check that key is in readset/writeset. + if (readset_.count(key) == 0 && writeset_.count(key) == 0) + DIE("Invalid read (key not in readset or writeset)."); + + // Reads have no effect if we have already aborted or committed. + if (status_ != INCOMPLETE) + return false; + + // 'reads_' has already been populated by TxnProcessor, so it should contain + // the target value iff the record appears in the database. + if (reads_.count(key)) { + *value = reads_[key]; + return true; + } else { + return false; + } +} + +void Txn::Write(const Key &key, const Value &value) { + // Check that key is in writeset. + if (writeset_.count(key) == 0) + DIE("Invalid write to key " << key << " (writeset)."); + + // Writes have no effect if we have already aborted or committed. + if (status_ != INCOMPLETE) + return; + + // Set key-value pair in write buffer. + writes_[key] = value; + + // Also set key-value pair in read results in case txn logic requires the + // record to be re-read. + reads_[key] = value; +} + +void Txn::CheckReadWriteSets() { + for (std::set::iterator it = writeset_.begin(); it != writeset_.end(); + ++it) { + if (readset_.count(*it) > 0) { + DIE("Overlapping read/write sets\n."); + } + } +} + +void Txn::CopyTxnInternals(Txn *txn) const { + txn->readset_ = std::set(this->readset_); + txn->writeset_ = std::set(this->writeset_); + txn->reads_ = std::map(this->reads_); + txn->writes_ = std::map(this->writes_); + txn->status_ = this->status_; + txn->unique_id_ = this->unique_id_; + txn->occ_start_idx_ = this->occ_start_idx_; +} diff --git a/a2_final/src/txn/txn.h b/a2_final/src/txn/txn.h new file mode 100644 index 0000000..051aec1 --- /dev/null +++ b/a2_final/src/txn/txn.h @@ -0,0 +1,108 @@ +#ifndef _TXN_H_ +#define _TXN_H_ + +#include +#include +#include +#include + +#include "utils/common.h" + +// Txns can have five distinct status values: +enum TxnStatus { + INCOMPLETE = 0, // Not yet executed + COMPLETED_C = 1, // Executed (with commit vote) + COMPLETED_A = 2, // Executed (with abort vote) + COMMITTED = 3, // Committed + ABORTED = 4, // Aborted +}; + +class Txn { +public: + // Commit vote defauls to false. Only by calling "commit" + Txn() : status_(INCOMPLETE) {} + virtual ~Txn() {} + virtual Txn *clone() const = 0; // Virtual constructor (copying) + + // Method containing all the transaction's method logic. + virtual void Run() = 0; + + // Returns the Txn's current execution status. + TxnStatus Status() { return status_; } + // Checks for overlap in read and write sets. If any key appears in both, + // an error occurs. + void CheckReadWriteSets(); + +protected: + // Copies the internals of this txn into a given transaction (i.e. + // the readset, writeset, and so forth). Be sure to modify this method + // to copy any new data structures you create. + void CopyTxnInternals(Txn *txn) const; + + friend class TxnProcessor; + + // Method to be used inside 'Execute()' function when reading records from + // the database. If record corresponding with specified 'key' exists, sets + // '*value' equal to the record value and returns true, else returns false. + // + // Requires: key appears in readset or writeset + // + // Note: Can ONLY be called from inside the 'Execute()' function. + bool Read(const Key &key, Value *value); + + // Method to be used inside 'Execute()' function when writing records to + // the database. + // + // Requires: key appears in writeset + // + // Note: Can ONLY be called from inside the 'Execute()' function. + void Write(const Key &key, const Value &value); + +// Macro to be used inside 'Execute()' function when deciding to COMMIT. +// +// Note: Can ONLY be called from inside the 'Execute()' function. +#define COMMIT \ + do { \ + status_ = COMPLETED_C; \ + return; \ + } while (0) + +// Macro to be used inside 'Execute()' function when deciding to ABORT. +// +// Note: Can ONLY be called from inside the 'Execute()' function. +#define ABORT \ + do { \ + status_ = COMPLETED_A; \ + return; \ + } while (0) + + // Set of all keys that may need to be read in order to execute the + // transaction. + std::set readset_; + + // Set of all keys that may be updated when executing the transaction. + std::set writeset_; + + // Results of reads performed by the transaction. + std::map reads_; + + // Key, Value pairs WRITTEN by the transaction. + std::map writes_; + + // Transaction's current execution status. + TxnStatus status_; + + // Unique, monotonically increasing transaction ID, assigned by TxnProcessor. + uint64 unique_id_; + + // Start index (used for OCC). + int64_t occ_start_idx_; + + std::unordered_set neighbors; + std::shared_mutex neighbors_mutex; + + std::mutex indegree_mutex; + int indegree; +}; + +#endif // _TXN_H_ diff --git a/a2_final/src/txn/txn_processor.cc b/a2_final/src/txn/txn_processor.cc new file mode 100644 index 0000000..52aa997 --- /dev/null +++ b/a2_final/src/txn/txn_processor.cc @@ -0,0 +1,596 @@ +#include +#include +#include +#include +#include + +#include "lock_manager.h" +#include "txn_processor.h" + +// Thread & queue counts for StaticThreadPool initialization. +#define THREAD_COUNT 8 + +using std::set; + +TxnProcessor::TxnProcessor(CCMode mode) + : mode_(mode), tp_(THREAD_COUNT), next_unique_id_(1) { + if (mode_ == LOCKING_EXCLUSIVE_ONLY) + lm_ = new LockManagerA(&ready_txns_); + else if (mode_ == LOCKING) + lm_ = new LockManagerB(&ready_txns_); + + // Create the storage + if (mode_ == MVCC || mode_ == MVCC_SSI) { + storage_ = new MVCCStorage(); + } else { + storage_ = new Storage(); + } + + storage_->InitStorage(); + stopped_ = false; + scheduler_thread_ = std::thread{&TxnProcessor::RunScheduler, this}; +} + +TxnProcessor::~TxnProcessor() { + // Wait for the scheduler thread to join back before destroying the object and + // its thread pool. + if (mode_ == CALVIN_EPOCH) { + pthread_join(calvin_sequencer_thread, NULL); + } + stopped_ = true; + scheduler_thread_.join(); + + if (mode_ == LOCKING_EXCLUSIVE_ONLY || mode_ == LOCKING) + delete lm_; + + delete storage_; +} + +void TxnProcessor::NewTxnRequest(Txn *txn) { + // Atomically assign the txn a new number and add it to the incoming txn + // requests queue. + txn->unique_id_ = next_unique_id_++; + txn_requests_.Push(txn); +} + +Txn *TxnProcessor::GetTxnResult() { + Txn *txn; + while (!txn_results_.Pop(&txn)) { + // No result yet. Wait a bit before trying again (to reduce contention on + // atomic queues). + usleep(1); + } + return txn; +} + +void TxnProcessor::RunScheduler() { + switch (mode_) { + case SERIAL: + RunSerialScheduler(); + break; + case LOCKING: + RunLockingScheduler(); + break; + case LOCKING_EXCLUSIVE_ONLY: + RunLockingScheduler(); + break; + case OCC: + RunOCCScheduler(); + break; + case P_OCC: + RunOCCParallelScheduler(); + break; + case MVCC: + RunMVCCScheduler(); + break; + case CALVIN: + RunCalvinContScheduler(); + break; + case CALVIN_I: + RunCalvinContIndivScheduler(); + break; + case CALVIN_EPOCH: + RunCalvinEpochScheduler(); + break; + } +} + +void TxnProcessor::RunSerialScheduler() { + Txn *txn; + while (!stopped_) { + // Get next txn request. + if (txn_requests_.Pop(&txn)) { + // Execute txn. + ExecuteTxn(txn); + + // Commit/abort txn according to program logic's commit/abort decision. + if (txn->Status() == COMPLETED_C) { + ApplyWrites(txn); + committed_txns_.Push(txn); + txn->status_ = COMMITTED; + } else if (txn->Status() == COMPLETED_A) { + txn->status_ = ABORTED; + } else { + // Invalid TxnStatus! + DIE("Completed Txn has invalid TxnStatus: " << txn->Status()); + } + + // Return result to client. + txn_results_.Push(txn); + } + } +} + +void TxnProcessor::RunLockingScheduler() { + Txn *txn; + while (!stopped_) { + // Start processing the next incoming transaction request. + if (txn_requests_.Pop(&txn)) { + bool blocked = false; + // Request read locks. + for (std::set::iterator it = txn->readset_.begin(); + it != txn->readset_.end(); ++it) { + if (!lm_->ReadLock(txn, *it)) { + blocked = true; + } + } + + // Request write locks. + for (std::set::iterator it = txn->writeset_.begin(); + it != txn->writeset_.end(); ++it) { + if (!lm_->WriteLock(txn, *it)) { + blocked = true; + } + } + + // If all read and write locks were immediately acquired, this txn is + // ready to be executed. + if (blocked == false) { + ready_txns_.push_back(txn); + } + } + + // Process and commit all transactions that have finished running. + while (completed_txns_.Pop(&txn)) { + // Commit/abort txn according to program logic's commit/abort decision. + if (txn->Status() == COMPLETED_C) { + ApplyWrites(txn); + committed_txns_.Push(txn); + txn->status_ = COMMITTED; + } else if (txn->Status() == COMPLETED_A) { + txn->status_ = ABORTED; + } else { + // Invalid TxnStatus! + DIE("Completed Txn has invalid TxnStatus: " << txn->Status()); + } + + // Release read locks. + for (std::set::iterator it = txn->readset_.begin(); + it != txn->readset_.end(); ++it) { + lm_->Release(txn, *it); + } + // Release write locks. + for (std::set::iterator it = txn->writeset_.begin(); + it != txn->writeset_.end(); ++it) { + lm_->Release(txn, *it); + } + + // Return result to client. + txn_results_.Push(txn); + } + + // Start executing all transactions that have newly acquired all their + // locks. + while (ready_txns_.size()) { + // Get next ready txn from the queue. + txn = ready_txns_.front(); + ready_txns_.pop_front(); + + // Start txn running in its own thread. + tp_.AddTask([this, txn]() { this->ExecuteTxn(txn); }); + } + } +} + +void TxnProcessor::ExecuteTxn(Txn *txn) { + // Get the current commited transaction index for the further validation. + txn->occ_start_idx_ = committed_txns_.Size(); + + // Read everything in from readset. + for (std::set::iterator it = txn->readset_.begin(); + it != txn->readset_.end(); ++it) { + // Save each read result iff record exists in storage. + Value result; + if (storage_->Read(*it, &result)) + txn->reads_[*it] = result; + } + + // Also read everything in from writeset. + for (std::set::iterator it = txn->writeset_.begin(); + it != txn->writeset_.end(); ++it) { + // Save each read result iff record exists in storage. + Value result; + if (storage_->Read(*it, &result)) + txn->reads_[*it] = result; + } + + // Execute txn's program logic. + txn->Run(); + + // Hand the txn back to the RunScheduler thread. + completed_txns_.Push(txn); +} + +void TxnProcessor::ApplyWrites(Txn *txn) { + // Write buffered writes out to storage. + for (std::map::iterator it = txn->writes_.begin(); + it != txn->writes_.end(); ++it) { + storage_->Write(it->first, it->second, txn->unique_id_); + } +} + +void TxnProcessor::RunOCCScheduler() { + Txn *txn; + while (!stopped_) { + // Get the next new txn request (if one is pending) + if (txn_requests_.Pop(&txn)) { + // Pass it to an execution thread + tp_.AddTask([this, txn]() { this->ExecuteTxn(txn); }); + } + + // Dealing with a finished transaction + while (completed_txns_.Pop(&txn)) { + // Validation phase + // Use the data structure in `txn_processor` class to check overlap with + // each record whose key appears in the txn's read and write sets + bool valid = true; + + // Check for overlap with newly committed transactions + // after the txn's occ_start_idx_ + for (int i = txn->occ_start_idx_ + 1; i < committed_txns_.Size(); i++) { + Txn *t = committed_txns_[i]; + + // check if write_set of t intersects with read_set of txn + for (auto key : txn->readset_) { + if (t->writeset_.find(key) != t->writeset_.end()) { + valid = false; + break; + } + } + } + + // If validation failed, cleanup txn and completely restart it + if (!valid) { + // Cleanup txn + txn->reads_.clear(); + txn->writes_.clear(); + txn->status_ = INCOMPLETE; + + // Restart txn + std::scoped_lock lock{mutex_}; + txn->unique_id_ = next_unique_id_++; + txn_requests_.Push(txn); + } else { + // Apply all writes + ApplyWrites(txn); + + // Mark transaction as committed + committed_txns_.Push(txn); + txn->status_ = COMMITTED; + + // Update relevant data structure + txn_results_.Push(txn); + } + } + } +} + +void TxnProcessor::ExecuteTxnParallel(Txn *txn) { + txn->occ_start_idx_ = committed_txns_.Size(); + + // Perform "read phase" of transaction + // Read everything in from readset. + for (std::set::iterator it = txn->readset_.begin(); + it != txn->readset_.end(); ++it) { + // Save each read result iff record exists in storage. + Value result; + if (storage_->Read(*it, &result)) + txn->reads_[*it] = result; + } + + // Also read everything in from writeset. + for (std::set::iterator it = txn->writeset_.begin(); + it != txn->writeset_.end(); ++it) { + // Save each read result iff record exists in storage. + Value result; + if (storage_->Read(*it, &result)) + txn->reads_[*it] = result; + } + + // Execute txn's program logic. + txn->Run(); + + // Start of critical section + // Make a copy of the active set + std::unique_lock lock{active_set_mutex_}; + auto finish_active = active_set_.GetSet(); + // Add this txn to the active set + active_set_.Insert(txn); + // End of critical section + lock.unlock(); + + // Validation phase + // Use the data structure in `txn_processor` class to check overlap with + // each record whose key appears in the txn's read and write sets + bool valid = true; + + // NOTE: This is not in the pseudocode in the project description + // Check for overlap with newly committed transactions + // after the txn's occ_start_idx_ + for (int i = txn->occ_start_idx_ + 1; i < committed_txns_.Size(); i++) { + Txn *t = committed_txns_[i]; + + // check if write_set of t intersects with read_set of txn + for (auto key : txn->readset_) { + if (t->writeset_.find(key) != t->writeset_.end()) { + valid = false; + break; + } + } + } + + // Check overlap with each record whose key appears in the txn's read and + // write sets NOTE: we only run this if the txn hasn't been invalidated by the + // previous check NOTE: this is the only validation implemented in the + // pseudocode in the project description + if (valid) { + for (auto t : finish_active) { + // if txn's write set intersects with t's write sets + for (auto key : txn->writeset_) { + if (t->writeset_.find(key) != t->writeset_.end()) { + valid = false; + break; + } + } + + // if txn's read set intersects with t's write sets + for (auto key : txn->readset_) { + if (t->writeset_.find(key) != t->writeset_.end()) { + valid = false; + break; + } + } + } + } + + // If validation failed, cleanup txn and completely restart it + if (!valid) { + // Remove this txn from the active set + std::unique_lock active_set_lock{active_set_mutex_}; + active_set_.Erase(txn); + active_set_lock.unlock(); + + // Cleanup txn + txn->reads_.clear(); + txn->writes_.clear(); + txn->status_ = INCOMPLETE; + + // Restart txn + std::scoped_lock lock{mutex_}; + txn->unique_id_ = next_unique_id_++; + txn_requests_.Push(txn); + } else { + // Apply all writes + ApplyWrites(txn); + + // Remove this txn from the active set + std::unique_lock active_set_lock{active_set_mutex_}; + active_set_.Erase(txn); + active_set_lock.unlock(); + + // Mark transaction as committed + committed_txns_.Push(txn); + txn->status_ = COMMITTED; + + // Update relevant data structure + txn_results_.Push(txn); + } +} + +void TxnProcessor::RunOCCParallelScheduler() { + Txn *txn; + while (!stopped_) { + // Get the next new transaction request (if one is pending) and pass it to + // an execution thread that executes the txn logic *and also* does the + // validation and write phases. + if (txn_requests_.Pop(&txn)) { + tp_.AddTask([this, txn]() { this->ExecuteTxnParallel(txn); }); + } + } +} + +set set_union(const std::set &s1, const set &s2) { + std::set result = s1; + result.insert(s2.begin(), s2.end()); + return result; +} + +void TxnProcessor::MVCCExecuteTxn(Txn *txn) { + // Read all necessary data for this transaction from storage + // (Note that unlike the version of MVCC from class, you should lock the key + // before each read) + + // Read everything in from readset and writeset. + for (auto key : set_union(txn->readset_, txn->writeset_)) { + // Lock the key + storage_->Lock(key); + + // Save each read result iff record exists in storage. + Value result; + if (storage_->Read(key, &result, txn->unique_id_)) + txn->reads_[key] = result; + + // Unlock the key + storage_->Unlock(key); + } + + // Execute txn's program logic. + txn->Run(); + + // Acquire all locks for keys in the write_set_ + for (auto key : txn->writeset_) { + storage_->Lock(key); + } + + // Call MVCCStorage::CheckWrite method to check all keys in the write_set_ + bool checkPassed = true; + for (auto key : txn->writeset_) { + if (!((MVCCStorage *)storage_)->CheckKey(key, txn->unique_id_)) { + checkPassed = false; + break; + } + } + + // If each key passed the check + if (checkPassed) { + // Apply the writes + ApplyWrites(txn); + + // Release all locks for keys in the write_set_ + for (auto key : txn->writeset_) { + storage_->Unlock(key); + } + + // Mark transaction as committed + committed_txns_.Push(txn); + txn->status_ = COMMITTED; + + // Update relevant data structure + txn_results_.Push(txn); + } else { // At least one key failed the check + // Release all locks for keys in the write_set_ + for (auto key : txn->writeset_) { + storage_->Unlock(key); + } + + // Cleanup txn + txn->reads_.clear(); + txn->writes_.clear(); + txn->status_ = INCOMPLETE; + + // Restart txn -- same as OCC + std::scoped_lock lock{mutex_}; + txn->unique_id_ = next_unique_id_++; + txn_requests_.Push(txn); + } +} + +void TxnProcessor::RunMVCCScheduler() { + // + // Implement this method! + + // Hint:Pop a txn from txn_requests_, and pass it to a thread to execute. + // Note that you may need to create another execute method, like + // TxnProcessor::MVCCExecuteTxn. + + Txn *txn; + while (!stopped_) { + // Get the next new transaction request (if one is pending) and pass it to + // an execution thread that executes the txn logic *and also* does the + // validation and write phases. + if (txn_requests_.Pop(&txn)) { + tp_.AddTask([this, txn]() { this->MVCCExecuteTxn(txn); }); + } + } +} + +void TxnProcessor::MVCCSSIExecuteTxn(Txn *txn) { + // Read all necessary data for this transaction from storage + // (Note that unlike the version of MVCC from class, you should lock the key + // before each read) + + // Read everything in from readset and writeset. + for (auto key : set_union(txn->readset_, txn->writeset_)) { + // Lock the key + storage_->Lock(key); + + // Save each read result iff record exists in storage. + Value result; + if (storage_->Read(key, &result, txn->unique_id_)) + txn->reads_[key] = result; + + // Unlock the key + storage_->Unlock(key); + } + + // Execute txn's program logic. + txn->Run(); + + // THIS IS DIFFERENT FROM MVCCExecuteTxn: we lock write_set AND read_set + // Acquire all locks for keys in the read_set_ and write_set_ + // (Lock any overlapping key only once.) + for (auto key : set_union(txn->writeset_, txn->readset_)) { + storage_->Lock(key); + } + + // Call MVCCStorage::CheckWrite method to check all keys in the write_set_ + bool checkPassed = true; + for (auto key : txn->writeset_) { + if (!((MVCCStorage *)storage_)->CheckKey(key, txn->unique_id_)) { + checkPassed = false; + break; + } + } + + // If each key passed the check + if (checkPassed) { + // Apply the writes + ApplyWrites(txn); + + // Release all locks for ALL keys (read_set_ and write_set_) + for (auto key : set_union(txn->writeset_, txn->readset_)) { + storage_->Unlock(key); + } + + // Mark transaction as committed + committed_txns_.Push(txn); + txn->status_ = COMMITTED; + + // Update relevant data structure + txn_results_.Push(txn); + } else { // At least one key failed the check + // Release all locks for ALL keys (read_set_ and write_set_) + for (auto key : set_union(txn->writeset_, txn->readset_)) { + storage_->Unlock(key); + } + + // Cleanup txn + txn->reads_.clear(); + txn->writes_.clear(); + txn->status_ = INCOMPLETE; + + // Restart txn -- same as OCC + std::scoped_lock lock{mutex_}; + txn->unique_id_ = next_unique_id_++; + txn_requests_.Push(txn); + } +} + +void TxnProcessor::RunMVCCSSIScheduler() { + // + // Implement this method! + + // Hint:Pop a txn from txn_requests_, and pass it to a thread to execute. + // Note that you may need to create another execute method, like + // TxnProcessor::MVCCSSIExecuteTxn. + + Txn *txn; + while (!stopped_) { + // Get the next new transaction request (if one is pending) and pass it to + // an execution thread that executes the txn logic *and also* does the + // validation and write phases. + if (txn_requests_.Pop(&txn)) { + tp_.AddTask([this, txn]() { this->MVCCSSIExecuteTxn(txn); }); + } + } +} diff --git a/a2_final/src/txn/txn_processor.h b/a2_final/src/txn/txn_processor.h new file mode 100644 index 0000000..f5fd4e1 --- /dev/null +++ b/a2_final/src/txn/txn_processor.h @@ -0,0 +1,228 @@ +#ifndef _TXN_PROCESSOR_H_ +#define _TXN_PROCESSOR_H_ + +#include +#include +#include +#include + +#include "lock_manager.h" +#include "mvcc_storage.h" +#include "storage.h" +#include "txn.h" +#include "utils/atomic.h" +#include "utils/common.h" +#include "utils/pool.h" +#include "utils/static_thread_pool.h" + +// The TxnProcessor supports five different execution modes, corresponding to +// the four parts of assignment 2, plus a simple serial (non-concurrent) mode. +enum CCMode { + SERIAL = 0, // Serial transaction execution (no concurrency) + LOCKING_EXCLUSIVE_ONLY, // Part 1A + LOCKING, // Part 1B + OCC, // Part 2 + P_OCC, // Part 3 + MVCC, // Part 4 + CALVIN, + CALVIN_I, + CALVIN_EPOCH, + MVCC_SSI, // Part 5 +}; + +// Returns a human-readable string naming of the providing mode. +std::string ModeToString(CCMode mode); + +class TxnProcessor { +public: + // The TxnProcessor's constructor starts the TxnProcessor running in the + // background. + explicit TxnProcessor(CCMode mode); + + // The TxnProcessor's destructor stops all background threads and deallocates + // all objects currently owned by the TxnProcessor, except for Txn objects. + ~TxnProcessor(); + + // Registers a new txn request to be executed by the TxnProcessor. + // Ownership of '*txn' is transfered to the TxnProcessor. + void NewTxnRequest(Txn *txn); + + // Returns a pointer to the next COMMITTED or ABORTED Txn. The caller takes + // ownership of the returned Txn. + Txn *GetTxnResult(); + + // Main loop implementing all concurrency control/thread scheduling. + void RunScheduler(); + + static void *StartScheduler(void *arg); + +private: + // Serial validation + bool SerialValidate(Txn *txn); + + // Parallel executtion/validation for OCC + void ExecuteTxnParallel(Txn *txn); + + // Serial version of scheduler. + void RunSerialScheduler(); + + // Locking version of scheduler. + void RunLockingScheduler(); + + // OCC version of scheduler. + void RunOCCScheduler(); + + // OCC version of scheduler with parallel validation. + void RunOCCParallelScheduler(); + + // MVCC version of scheduler. + void RunMVCCScheduler(); + + // MVCC SSI version of scheduler. + void RunMVCCSSIScheduler(); + + // Performs all reads required to execute the transaction, then executes the + // transaction logic. + void ExecuteTxn(Txn *txn); + + // Applies all writes performed by '*txn' to 'storage_'. + // + // Requires: txn->Status() is COMPLETED_C. + void ApplyWrites(Txn *txn); + + // The following functions are for MVCC. + void MVCCExecuteTxn(Txn *txn); + + // The following functions are for MVCC_SSI. + + void MVCCSSIExecuteTxn(Txn *txn); + + void MVCCSSICheckReads(Txn *txn); + + // The following functions are for MVCC & MVCC_SSI. + bool MVCCCheckWrites(Txn *txn); + + void MVCCLockWriteKeys(Txn *txn); + + void MVCCUnlockWriteKeys(Txn *txn); + + // Concurrency control mechanism the TxnProcessor is currently using. + CCMode mode_; + + // Thread pool managing all threads used by TxnProcessor. + StaticThreadPool tp_; + + // Data storage used for all modes. + Storage *storage_; + + // Next valid unique_id, and a mutex to guard incoming txn requests. + std::atomic next_unique_id_; + std::mutex mutex_; + + // Queue of incoming transaction requests. + AtomicQueue txn_requests_; + + // Queue of txns that have acquired all locks and are ready to be executed. + // + // Does not need to be atomic because RunScheduler is the only thread that + // will ever access this queue. + std::deque ready_txns_; + + // Queue of completed (but not yet committed/aborted) transactions. + AtomicQueue completed_txns_; + + // Vector of committed transactions that are used to check any overlap + // during OCC validation phase. + AtomicVector committed_txns_; + + // Queue of transaction results (already committed or aborted) to be returned + // to client. + AtomicQueue txn_results_; + + // Set of transactions that are currently in the process of parallel + // validation. + AtomicSet active_set_; + + // Used it for critical section in parallel occ. + std::mutex active_set_mutex_; + + // Lock Manager used for LOCKING concurrency implementations. + LockManager *lm_; + + // Used for stopping the continuous loop that runs in the scheduler thread + std::atomic stopped_; + + // Gives us access to the scheduler thread so that we can wait for it to join + // later. + std::thread scheduler_thread_; + + // ===================== START OF CALVIN ===================== + + /*********************************************** + * Calvin Continuous Execution -- Global Locks * + ***********************************************/ + + // putting calvin sequencer as public for pthread + void RunCalvinEpochSequencer(); + + // putting calvin epoch executor as public for pthread + void CalvinEpochExecutor(); + + std::unordered_map> adj_list; + std::unordered_map> + indegree; // indegree needs to be atomic + std::queue *root_txns; + + std::shared_mutex adj_list_lock; + std::shared_mutex indegree_lock; + + void RunCalvinContScheduler(); + void CalvinContExecutorFunc(Txn *txn); + + /*********************************************** + * Calvin Continuous Execution -- Indiv Locks * + ***********************************************/ + void RunCalvinContIndivScheduler(); + void CalvinContIndivExecutorFunc(Txn *txn); + + /*********************************************** + * Calvin Epoch Execution * + ***********************************************/ + // 1) Sequencer + + // thread for calvin sequencer + pthread_t calvin_sequencer_thread; + // thread for calvin sequencer + pthread_t calvin_epoch_executor_thread; + // defining epoch for ease of use + typedef std::queue Epoch; + // queue of epochs for calvin scheduler + AtomicQueue epoch_queue; + + // helper function for pthreads + static void *calvin_sequencer_helper(void *arg); + + // 2) Scheduler + struct EpochDag { + std::unordered_map> *adj_list; + std::unordered_map> *indegree; + std::queue *root_txns; + }; + EpochDag *current_epoch_dag; + AtomicQueue epoch_dag_queue; + std::atomic num_txns_left_in_epoch; + pthread_cond_t epoch_finished_cond; + pthread_mutex_t epoch_finished_mutex; + void RunCalvinEpochScheduler(); + + // 3) Executor + // helper function to call calvin epoch executor in pthread + static void *calvin_epoch_executor_helper(void *arg); + + void CalvinEpochExecutorFunc(Txn *txn); + void CalvinExecuteSingleEpoch(EpochDag *epoch_dag); + + // ===================== END OF CALVIN ======================= +}; + +#endif // _TXN_PROCESSOR_H_ diff --git a/a2_final/src/txn/txn_processor_test.cc b/a2_final/src/txn/txn_processor_test.cc new file mode 100644 index 0000000..3c787d9 --- /dev/null +++ b/a2_final/src/txn/txn_processor_test.cc @@ -0,0 +1,384 @@ +#include +#include + +#include "txn/txn_types.h" +#include "txn_processor.h" + +// Returns a human-readable string naming of the providing mode. +std::string ModeToString(CCMode mode) { + switch (mode) { + case SERIAL: + return " Serial "; + case LOCKING_EXCLUSIVE_ONLY: + return " Locking A"; + case LOCKING: + return " Locking B"; + case OCC: + return " OCC "; + case P_OCC: + return " OCC-P "; + case MVCC: + return " MVCC "; + case CALVIN: + return " Calvin "; + case CALVIN_I: + return " Calvin_I "; + case CALVIN_EPOCH: + return " Calvin_E "; + default: + return "INVALID MODE"; + } +} + +class LoadGen { +public: + virtual ~LoadGen() {} + virtual Txn *NewTxn() = 0; +}; + +class RMWLoadGen : public LoadGen { +public: + RMWLoadGen(int dbsize, int rsetsize, int wsetsize, double wait_time) + : dbsize_(dbsize), rsetsize_(rsetsize), wsetsize_(wsetsize), + wait_time_(wait_time) {} + + virtual Txn *NewTxn() { + return new RMW(dbsize_, rsetsize_, wsetsize_, wait_time_); + } + +private: + int dbsize_; + int rsetsize_; + int wsetsize_; + double wait_time_; +}; + +class RMWLoadGen2 : public LoadGen { +public: + RMWLoadGen2(int dbsize, int rsetsize, int wsetsize, double wait_time) + : dbsize_(dbsize), rsetsize_(rsetsize), wsetsize_(wsetsize), + wait_time_(wait_time) {} + + virtual Txn *NewTxn() { + // 80% of transactions are READ only transactions and run for the full + // transaction duration. The rest are very fast (< 0.1ms), high-contention + // updates. + if (rand() % 100 < 80) + return new RMW(dbsize_, rsetsize_, 0, wait_time_); + else + return new RMW(dbsize_, 0, wsetsize_, 0); + } + +private: + int dbsize_; + int rsetsize_; + int wsetsize_; + double wait_time_; +}; + +class RMWDynLoadGen : public LoadGen { +public: + RMWDynLoadGen(int dbsize, int rsetsize, int wsetsize, + std::vector wait_times) + : dbsize_(dbsize), rsetsize_(rsetsize), wsetsize_(wsetsize) { + wait_times_ = wait_times; + } + + virtual Txn *NewTxn() { + // Mix transactions with different time durations (wait_times_) + if (rand() % 100 < 30) + return new RMW(dbsize_, rsetsize_, wsetsize_, wait_times_[0]); + else if (rand() % 100 < 60) + return new RMW(dbsize_, rsetsize_, wsetsize_, wait_times_[1]); + else + return new RMW(dbsize_, rsetsize_, wsetsize_, wait_times_[2]); + } + +private: + int dbsize_; + int rsetsize_; + int wsetsize_; + std::vector wait_times_; +}; + +class RMWDynLoadGen2 : public LoadGen { +public: + RMWDynLoadGen2(int dbsize, int rsetsize, int wsetsize, + std::vector wait_times) + : dbsize_(dbsize), rsetsize_(rsetsize), wsetsize_(wsetsize) { + wait_times_ = wait_times; + } + + virtual Txn *NewTxn() { + // 80% of transactions are READ only transactions and run for the different + // transaction duration. The rest are very fast (< 0.1ms), high-contention + // updates. + if (rand() % 100 < 80) { + // Mix transactions with different time durations (wait_times_) + if (rand() % 100 < 30) + return new RMW(dbsize_, rsetsize_, 0, wait_times_[0]); + else if (rand() % 100 < 60) + return new RMW(dbsize_, rsetsize_, 0, wait_times_[1]); + else + return new RMW(dbsize_, rsetsize_, 0, wait_times_[2]); + } else { + return new RMW(dbsize_, 0, wsetsize_, 0); + } + } + +private: + int dbsize_; + int rsetsize_; + int wsetsize_; + std::vector wait_times_; +}; + +void Benchmark(const std::vector &lg) { + // Number of transaction requests that can be active at any given time. + int active_txns = 100; + std::deque doneTxns; + + // For each MODE... + for (CCMode mode = SERIAL; mode <= CALVIN_I; + mode = static_cast(mode + 1)) { + // Print out mode name. + std::cout << ModeToString(mode) << std::flush; + + // For each experiment, run 2 times and get the average. + for (uint32 exp = 0; exp < lg.size(); exp++) { + double throughput[2]; + for (uint32 round = 0; round < 2; round++) { + int txn_count = 0; + + // Create TxnProcessor in next mode. + TxnProcessor *p = new TxnProcessor(mode); + + // Record start time. + double start = GetTime(); + + // Start specified number of txns running. + for (int i = 0; i < active_txns; i++) + p->NewTxnRequest(lg[exp]->NewTxn()); + + // Keep 100 active txns at all times for the first full second. + while (GetTime() < start + 0.5) { + Txn *txn = p->GetTxnResult(); + doneTxns.push_back(txn); + txn_count++; + p->NewTxnRequest(lg[exp]->NewTxn()); + } + + // Wait for all of them to finish. + for (int i = 0; i < active_txns; i++) { + Txn *txn = p->GetTxnResult(); + doneTxns.push_back(txn); + txn_count++; + } + + // Record end time. + double end = GetTime(); + + throughput[round] = txn_count / (end - start); + + for (auto it = doneTxns.begin(); it != doneTxns.end(); ++it) { + delete *it; + } + + doneTxns.clear(); + delete p; + } + + // Print throughput + std::cout << "\t" << (throughput[0] + throughput[1]) / 2 << "\t" + << std::flush; + } + + std::cout << std::endl; + } +} + +int main(int argc, char **argv) { + std::cout + << "\t\t----------------------------------------------------------------" + "---" + << std::endl; + std::cout << "\t\t Average Transaction Duration" << std::endl; + std::cout + << "\t\t----------------------------------------------------------------" + "---" + << std::endl; + std::cout << "\t\t0.1ms\t\t1ms\t\t10ms\t\t(0.1ms, 1ms, 10ms)" << std::endl; + std::cout + << "\t\t----------------------------------------------------------------" + "---" + << std::endl; + + std::vector lg; + + std::cout << "\t\t Low contention Read only (5 records)" + << std::endl; + std::cout + << "\t\t----------------------------------------------------------------" + "---" + << std::endl; + lg.push_back(new RMWLoadGen(1000000, 5, 0, 0.0001)); + lg.push_back(new RMWLoadGen(1000000, 5, 0, 0.001)); + lg.push_back(new RMWLoadGen(1000000, 5, 0, 0.01)); + lg.push_back(new RMWDynLoadGen(1000000, 5, 0, {0.0001, 0.001, 0.01})); + + Benchmark(lg); + std::cout << std::endl; + + for (uint32 i = 0; i < lg.size(); i++) + delete lg[i]; + lg.clear(); + + std::cout << "\t\t Low contention Read only (30 records)" + << std::endl; + std::cout + << "\t\t----------------------------------------------------------------" + "---" + << std::endl; + lg.push_back(new RMWLoadGen(1000000, 30, 0, 0.0001)); + lg.push_back(new RMWLoadGen(1000000, 30, 0, 0.001)); + lg.push_back(new RMWLoadGen(1000000, 30, 0, 0.01)); + lg.push_back(new RMWDynLoadGen(1000000, 30, 0, {0.0001, 0.001, 0.01})); + + Benchmark(lg); + std::cout << std::endl; + + for (uint32 i = 0; i < lg.size(); i++) + delete lg[i]; + lg.clear(); + + std::cout << "\t\t High contention Read only (5 records)" + << std::endl; + std::cout + << "\t\t----------------------------------------------------------------" + "---" + << std::endl; + lg.push_back(new RMWLoadGen(100, 5, 0, 0.0001)); + lg.push_back(new RMWLoadGen(100, 5, 0, 0.001)); + lg.push_back(new RMWLoadGen(100, 5, 0, 0.01)); + lg.push_back(new RMWDynLoadGen(100, 5, 0, {0.0001, 0.001, 0.01})); + + Benchmark(lg); + std::cout << std::endl; + + for (uint32 i = 0; i < lg.size(); i++) + delete lg[i]; + lg.clear(); + + std::cout << "\t\t High contention Read only (30 records)" + << std::endl; + std::cout + << "\t\t----------------------------------------------------------------" + "---" + << std::endl; + lg.push_back(new RMWLoadGen(100, 30, 0, 0.0001)); + lg.push_back(new RMWLoadGen(100, 30, 0, 0.001)); + lg.push_back(new RMWLoadGen(100, 30, 0, 0.01)); + lg.push_back(new RMWDynLoadGen(100, 30, 0, {0.0001, 0.001, 0.01})); + + Benchmark(lg); + std::cout << std::endl; + + for (uint32 i = 0; i < lg.size(); i++) + delete lg[i]; + lg.clear(); + + std::cout << "\t\t Low contention read-write (5 records)" + << std::endl; + std::cout + << "\t\t----------------------------------------------------------------" + "---" + << std::endl; + lg.push_back(new RMWLoadGen(1000000, 0, 5, 0.0001)); + lg.push_back(new RMWLoadGen(1000000, 0, 5, 0.001)); + lg.push_back(new RMWLoadGen(1000000, 0, 5, 0.01)); + lg.push_back(new RMWDynLoadGen(1000000, 0, 5, {0.0001, 0.001, 0.01})); + + Benchmark(lg); + std::cout << std::endl; + + for (uint32 i = 0; i < lg.size(); i++) + delete lg[i]; + lg.clear(); + + std::cout << "\t\t Low contention read-write (10 records)" + << std::endl; + std::cout + << "\t\t----------------------------------------------------------------" + "---" + << std::endl; + lg.push_back(new RMWLoadGen(1000000, 0, 10, 0.0001)); + lg.push_back(new RMWLoadGen(1000000, 0, 10, 0.001)); + lg.push_back(new RMWLoadGen(1000000, 0, 10, 0.01)); + lg.push_back(new RMWDynLoadGen(1000000, 0, 10, {0.0001, 0.001, 0.01})); + + Benchmark(lg); + std::cout << std::endl; + + for (uint32 i = 0; i < lg.size(); i++) + delete lg[i]; + lg.clear(); + + std::cout << "\t\t High contention read-write (5 records)" + << std::endl; + std::cout + << "\t\t----------------------------------------------------------------" + "---" + << std::endl; + lg.push_back(new RMWLoadGen(100, 0, 5, 0.0001)); + lg.push_back(new RMWLoadGen(100, 0, 5, 0.001)); + lg.push_back(new RMWLoadGen(100, 0, 5, 0.01)); + lg.push_back(new RMWDynLoadGen(100, 0, 5, {0.0001, 0.001, 0.01})); + + Benchmark(lg); + std::cout << std::endl; + + for (uint32 i = 0; i < lg.size(); i++) + delete lg[i]; + lg.clear(); + + std::cout << "\t\t High contention read-write (10 records)" + << std::endl; + std::cout + << "\t\t----------------------------------------------------------------" + "---" + << std::endl; + lg.push_back(new RMWLoadGen(100, 0, 10, 0.0001)); + lg.push_back(new RMWLoadGen(100, 0, 10, 0.001)); + lg.push_back(new RMWLoadGen(100, 0, 10, 0.01)); + lg.push_back(new RMWDynLoadGen(100, 0, 10, {0.0001, 0.001, 0.01})); + + Benchmark(lg); + std::cout << std::endl; + + for (uint32 i = 0; i < lg.size(); i++) + delete lg[i]; + lg.clear(); + + // 80% of transactions are READ only transactions and run for the full + // transaction duration. The rest are very fast (< 0.1ms), high-contention + // updates. + std::cout << "\t\t High contention mixed read only/read-write" + << std::endl; + std::cout + << "\t\t----------------------------------------------------------------" + "---" + << std::endl; + lg.push_back(new RMWLoadGen2(50, 30, 10, 0.0001)); + lg.push_back(new RMWLoadGen2(50, 30, 10, 0.001)); + lg.push_back(new RMWLoadGen2(50, 30, 10, 0.01)); + lg.push_back(new RMWDynLoadGen2(50, 30, 10, {0.0001, 0.001, 0.01})); + + Benchmark(lg); + std::cout << std::endl; + + for (uint32 i = 0; i < lg.size(); i++) + delete lg[i]; + lg.clear(); + + return 0; +} diff --git a/a2_final/src/txn/txn_types.h b/a2_final/src/txn/txn_types.h new file mode 100644 index 0000000..9d7c76b --- /dev/null +++ b/a2_final/src/txn/txn_types.h @@ -0,0 +1,152 @@ +#ifndef _TXN_TYPES_H_ +#define _TXN_TYPES_H_ + +#include +#include +#include + +#include "txn.h" + +// Immediately commits. +class Noop : public Txn { +public: + Noop() {} + virtual void Run() { COMMIT; } + Noop *clone() const { // Virtual constructor (copying) + Noop *clone = new Noop(); + this->CopyTxnInternals(clone); + return clone; + } +}; + +// Reads all keys in the map 'm', if all results correspond to the values in +// the provided map, commits, else aborts. +class Expect : public Txn { +public: + Expect(const std::map &m) : m_(m) { + for (std::map::iterator it = m_.begin(); it != m_.end(); ++it) + readset_.insert(it->first); + } + + Expect *clone() const { // Virtual constructor (copying) + Expect *clone = new Expect(std::map(m_)); + this->CopyTxnInternals(clone); + return clone; + } + + virtual void Run() { + Value result; + for (std::map::iterator it = m_.begin(); it != m_.end(); ++it) { + if (!Read(it->first, &result) || result != it->second) { + ABORT; + } + } + COMMIT; + } + +private: + std::map m_; +}; + +// Inserts all pairs in the map 'm'. +class Put : public Txn { +public: + Put(const std::map &m) : m_(m) { + for (std::map::iterator it = m_.begin(); it != m_.end(); ++it) + writeset_.insert(it->first); + } + + Put *clone() const { // Virtual constructor (copying) + Put *clone = new Put(std::map(m_)); + this->CopyTxnInternals(clone); + return clone; + } + + virtual void Run() { + for (std::map::iterator it = m_.begin(); it != m_.end(); ++it) + Write(it->first, it->second); + COMMIT; + } + +private: + std::map m_; +}; + +// Read-modify-write transaction. +class RMW : public Txn { +public: + explicit RMW(double time = 0) : time_(time) {} + RMW(const std::set &writeset, double time = 0) : time_(time) { + writeset_ = writeset; + } + RMW(const std::set &readset, const std::set &writeset, + double time = 0) + : time_(time) { + readset_ = readset; + writeset_ = writeset; + } + + // Constructor with randomized read/write sets + RMW(int dbsize, int readsetsize, int writesetsize, double time = 0) + : time_(time) { + // Make sure we can find enough unique keys. + DCHECK(dbsize >= readsetsize + writesetsize); + + // Find readsetsize unique read keys. + for (int i = 0; i < readsetsize; i++) { + Key key; + do { + key = rand() % dbsize; + } while (readset_.count(key)); + readset_.insert(key); + } + + // Find writesetsize unique write keys. + for (int i = 0; i < writesetsize; i++) { + Key key; + do { + key = rand() % dbsize; + } while (readset_.count(key) || writeset_.count(key)); + writeset_.insert(key); + } + } + + RMW *clone() const { // Virtual constructor (copying) + RMW *clone = new RMW(time_); + this->CopyTxnInternals(clone); + return clone; + } + + virtual void Run() { + Value result; + // Read everything in readset. + for (std::set::iterator it = readset_.begin(); it != readset_.end(); + ++it) + Read(*it, &result); + + // Run while loop to simulate the txn logic(duration is time_). + double begin = GetTime(); + while (GetTime() - begin < time_) { + for (int i = 0; i < 1000; i++) { + int x = 100; + x = x + 2; + x = x * x; + } + } + + // Increment length of everything in writeset. + for (std::set::iterator it = writeset_.begin(); it != writeset_.end(); + ++it) { + result = 0; + Read(*it, &result); + Write(*it, result + 1); + } + + COMMIT; + } + +private: + double time_; +}; + +#endif // _TXN_TYPES_H_ diff --git a/a2_final/src/txn/txn_types_test.cc b/a2_final/src/txn/txn_types_test.cc new file mode 100644 index 0000000..746453c --- /dev/null +++ b/a2_final/src/txn/txn_types_test.cc @@ -0,0 +1,76 @@ +#include "txn.h" + +#include + +#include "txn_processor.h" +#include "txn_types.h" +#include "utils/testing.h" + +TEST(NoopTest) { + TxnProcessor p(SERIAL); + + Txn *t = new Noop(); + EXPECT_EQ(INCOMPLETE, t->Status()); + + p.NewTxnRequest(t); + p.GetTxnResult(); + + EXPECT_EQ(COMMITTED, t->Status()); + delete t; + + END; +} + +TEST(PutTest) { + TxnProcessor p(SERIAL); + Txn *t; + + std::map m1 = {{1, 2}}; + p.NewTxnRequest(new Put(m1)); + delete p.GetTxnResult(); + + std::map m2 = {{0, 2}}; + p.NewTxnRequest(new Expect(m2)); // Should abort (no key '0' exists) + t = p.GetTxnResult(); + EXPECT_EQ(ABORTED, t->Status()); + delete t; + + std::map m3 = {{1, 1}}; + p.NewTxnRequest(new Expect(m3)); // Should abort (wrong value for key) + t = p.GetTxnResult(); + EXPECT_EQ(ABORTED, t->Status()); + delete t; + + std::map m4 = {{1, 2}}; + p.NewTxnRequest(new Expect(m4)); // Should commit + t = p.GetTxnResult(); + EXPECT_EQ(COMMITTED, t->Status()); + delete t; + + END; +} + +TEST(PutMultipleTest) { + TxnProcessor p(SERIAL); + Txn *t; + + std::map m; + for (int i = 0; i < 1000; i++) + m[i] = i * i; + + p.NewTxnRequest(new Put(m)); + delete p.GetTxnResult(); + + p.NewTxnRequest(new Expect(m)); + t = p.GetTxnResult(); + EXPECT_EQ(COMMITTED, t->Status()); + delete t; + + END; +} + +int main(int argc, char **argv) { + NoopTest(); + PutTest(); + PutMultipleTest(); +} diff --git a/a2_final/src/utils/atomic.h b/a2_final/src/utils/atomic.h new file mode 100644 index 0000000..e4208f4 --- /dev/null +++ b/a2_final/src/utils/atomic.h @@ -0,0 +1,209 @@ +#ifndef _DB_UTILS_ATOMIC_H_ +#define _DB_UTILS_ATOMIC_H_ + +#include +#include +#include +#include +#include +#include +#include + +/// @class AtomicMap +/// +/// Atomically readable, atomically mutable unordered associative container. +/// Implemented as a std::unordered_map guarded by a pthread rwlock. +/// Supports CRUD operations only. Iterators are NOT supported. +template class AtomicMap { +public: + AtomicMap() {} + // Returns the number of key-value pairs currently stored in the map. + int Size() { + std::shared_lock lock{mutex_}; + return map_.size(); + } + + // Returns true if the map contains a pair with key equal to 'key'. + bool Contains(const K &key) { + std::shared_lock lock{mutex_}; + return map_.contains(key); + } + + // If the map contains a pair with key 'key', sets '*value' equal to the + // associated value and returns true, else returns false. + bool Lookup(const K &key, V *value) { + std::shared_lock lock{mutex_}; + if (map_.contains(key)) { + *value = map_[key]; + return true; + } else { + return false; + } + } + + // Atomically inserts the pair (key, value) into the map (clobbering any + // previous pair with key equal to 'key'. + void Insert(const K &key, const V &value) { + std::scoped_lock lock{mutex_}; + map_[key] = value; + } + + // Synonym for 'Insert(key, value)'. + void Set(const K &key, const V &value) { Insert(key, value); } + // Atomically erases any pair with key 'key' from the map. + void Erase(const K &key) { + std::scoped_lock lock{mutex_}; + map_.erase(key); + } + +private: + std::unordered_map map_; + std::shared_mutex mutex_; +}; + +/// @class AtomicSet +/// +/// Atomically readable, atomically mutable container. +/// Implemented as a std::set guarded by a pthread rwlock. +/// Supports CRUD operations only. Iterators are NOT supported. +template class AtomicSet { +public: + AtomicSet() {} + // Returns the number of key-value pairs currently stored in the map. + int Size() { + std::shared_lock lock{mutex_}; + return set_.size(); + } + + // Returns true if the set contains V value. + bool Contains(const V &value) { + std::shared_lock lock{mutex_}; + return set_.contains(value); + } + + // Atomically inserts the value into the set. + void Insert(const V &value) { + std::scoped_lock lock{mutex_}; + set_.insert(value); + } + + // Atomically erases the object value from the set. + void Erase(const V &value) { + std::scoped_lock lock{mutex_}; + set_.erase(value); + } + + V GetFirst() { + std::scoped_lock lock{mutex_}; + V first = *(set_.begin()); + return first; + } + + // Returns a copy of the underlying set. + std::set GetSet() { + std::shared_lock lock{mutex_}; + return {set_}; + } + +private: + std::set set_; + std::shared_mutex mutex_; +}; + +/// @class AtomicQueue +/// +/// Queue with atomic push and pop operations. +/// +/// @TODO(alex): This should use lower-contention synchronization. +template class AtomicQueue { +public: + AtomicQueue() { mutex_ = std::make_unique(); } + // Returns the number of elements currently in the queue. + int Size() { + std::scoped_lock lock{*mutex_}; + int size = queue_.size(); + return size; + } + + // Atomically pushes 'item' onto the queue. + void Push(const T &item) { + std::scoped_lock lock{*mutex_}; + queue_.push(item); + } + + // If the queue is non-empty, (atomically) sets '*result' equal to the front + // element, pops the front element from the queue, and returns true, + // otherwise returns false. + bool Pop(T *result) { + std::scoped_lock lock{*mutex_}; + if (!queue_.empty()) { + *result = queue_.front(); + queue_.pop(); + return true; + } else { + return false; + } + } + + // If mutex is immediately acquired, pushes and returns true, else immediately + // returns false. + bool PushNonBlocking(const T &item) { + std::unique_lock lock{*mutex_, std::try_to_lock}; + if (lock) { + queue_.push(item); + return true; + } else { + return false; + } + } + + // If mutex is immediately acquired AND queue is nonempty, pops and returns + // true, else returns false. + bool PopNonBlocking(T *result) { + std::unique_lock lock{*mutex_, std::try_to_lock}; + if (lock && !queue_.empty()) { + *result = queue_.front(); + queue_.pop(); + return true; + } else { + return false; + } + } + +private: + std::queue queue_; + std::unique_ptr mutex_; +}; + +template class AtomicVector { +public: + AtomicVector() {} + // Returns the number of elements currently stored in the vector. + int Size() { + std::shared_lock lock{mutex_}; + int size = vec_.size(); + return size; + } + + // Atomically accesses the value associated with the id. + T &operator[](int id) { + std::shared_lock lock{mutex_}; + T &value = vec_[id]; + return value; + } + + // Atomically inserts the value into the vector. + void Push(const T &value) { + std::scoped_lock lock{mutex_}; + vec_.push_back(value); + } + + // CMSC 624: TODO(students) + // Feel free to add more methods as needed. + +private: + std::vector vec_; + std::shared_mutex mutex_; +}; + +#endif // _DB_UTILS_ATOMIC_H_ diff --git a/a2_final/src/utils/atomic_queue.h b/a2_final/src/utils/atomic_queue.h new file mode 100644 index 0000000..de0e47b --- /dev/null +++ b/a2_final/src/utils/atomic_queue.h @@ -0,0 +1,49 @@ +#include +#include + +template class atomic_queue { +private: + std::queue queue_; + std::mutex mutex_; + +public: + bool pop(T &f) { + std::scoped_lock lock{mutex_}; + if (std::empty(queue_)) + return false; + + f = std::move(queue_.front()); + queue_.pop(); + + return true; + } + + bool push(T &&f) { + std::scoped_lock lock{mutex_}; + queue_.emplace(f); + return true; + } + + bool try_push(T &&f) { + std::unique_lock lock{mutex_, std::try_to_lock}; + + if (!lock) + return false; + + queue_.emplace(f); + return true; + } + + bool try_pop(T &f) { + std::unique_lock lock{mutex_, std::try_to_lock}; + + if (!lock || std::empty(queue_)) { + return false; + } + + f = std::move(queue_.front()); + queue_.pop(); + + return true; + } +}; diff --git a/a2_final/src/utils/common.h b/a2_final/src/utils/common.h new file mode 100644 index 0000000..cd4ab02 --- /dev/null +++ b/a2_final/src/utils/common.h @@ -0,0 +1,70 @@ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// debug mode +#define DEBUG true + +// assert if in debug mode +#define DCHECK(ARG) \ + if (DEBUG) { \ + assert(ARG); \ + } + +// print message and die +#define DIE(MSG) \ + do { \ + std::cerr << __FILE__ << ":" << __LINE__ << ": " << MSG << std::endl; \ + exit(1); \ + } while (0); + +// Abbreviated signed int types. +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; + +// Abbreviated unsigned int types. +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; + +// Key and value types +typedef uint64 Key; +typedef uint64 Value; + +// Returns the number of seconds since midnight according to local system time, +// to the nearest microsecond. +static inline double GetTime() { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec + tv.tv_usec / 1e6; +} + +// Returns a random double in [0, max] (flat distribution). +static inline double RandomDouble(double max) { + return max * (static_cast(rand()) / static_cast(RAND_MAX)); +} + +// Sleep for 'duration' seconds. +static inline void Sleep(double duration) { usleep(1000000 * duration); } +// Returns a human-readable string representation of an int. +static inline std::string IntToString(int n) { + char s[64]; + snprintf(s, sizeof(s), "%d", n); + return std::string(s); +} + +// Converts a human-readable numeric string to an int. +static inline int StringToInt(const std::string &s) { return atoi(s.c_str()); } +#endif // _COMMON_H_ diff --git a/a2_final/src/utils/pool.h b/a2_final/src/utils/pool.h new file mode 100644 index 0000000..80c3f26 --- /dev/null +++ b/a2_final/src/utils/pool.h @@ -0,0 +1,69 @@ +#include +#include +#include + +#include "atomic_queue.h" + +using task = std::function; + +#define TRY_FACTOR 10 + +class thread_pool { +private: + std::atomic counter_{}; + std::atomic stopped_ = false; + unsigned num_threads_{}; + std::vector> queues_; + std::vector threads_; + + void run(unsigned tid) { + while (!stopped_) { + task f; + + // Check Our Queue + if (!queues_[tid].pop(f)) { + for (unsigned i = 0; i < num_threads_; i++) { + // Try and Steal Other work + if (queues_[i].try_pop(f)) { + break; + } + } + } + + if (f) + f(); + } + } + +public: + thread_pool(unsigned num_threads) + : num_threads_(num_threads), queues_(num_threads), threads_(num_threads) { + for (unsigned i = 0; i < num_threads; i++) { + threads_[i] = std::thread{&thread_pool::run, this, i}; + } + } + + ~thread_pool() { + stopped_ = true; + for (unsigned i = 0; i < num_threads_; i++) { + threads_[i].join(); + } + } + + void AddTask(task &&f) { + unsigned tid = counter_++; + + // Try to Assign Round Robin + if (!queues_[tid % num_threads_].try_push(std::forward(f))) { + for (unsigned i = 0; i < num_threads_; i++) { + // Try and Push to another queue + if (queues_[i % num_threads_].try_push(std::forward(f))) { + return; + } + } + + // Otherwise push in order + queues_[tid % num_threads_].push(std::forward(f)); + } + } +}; diff --git a/a2_final/src/utils/static_thread_pool.h b/a2_final/src/utils/static_thread_pool.h new file mode 100644 index 0000000..0d7e05f --- /dev/null +++ b/a2_final/src/utils/static_thread_pool.h @@ -0,0 +1,86 @@ +#ifndef _DB_UTILS_STATIC_THREAD_POOL_H_ +#define _DB_UTILS_STATIC_THREAD_POOL_H_ + +#include +#include +#include +#include +#include + +#include "assert.h" +#include "stdlib.h" +#include "utils/atomic.h" +#include "utils/thread_pool.h" + +class StaticThreadPool : public ThreadPool { +public: + StaticThreadPool(int nthreads) : thread_count_(nthreads), stopped_(false) { + threads_.resize(nthreads); + queues_.resize(nthreads); + + for (int i = 0; i < nthreads; i++) { + threads_[i] = std::thread{&StaticThreadPool::RunThread, this, i}; + } + } + ~StaticThreadPool() { + stopped_ = true; + for (int i = 0; i < thread_count_; i++) { + threads_[i].join(); + } + } + + bool Active() { return !stopped_; } + + virtual void AddTask(Task &&task) { + assert(!stopped_); + while (!queues_[rand() % thread_count_].PushNonBlocking( + std::forward(task))) { + } + } + + virtual void AddTask(const Task &task) { + assert(!stopped_); + while (!queues_[rand() % thread_count_].PushNonBlocking(task)) { + } + } + + virtual int ThreadCount() { return thread_count_; } + +private: + // Function executed by each pthread. + void RunThread(int queue_id) { + Task task; + int sleep_duration = 1; // in microseconds + while (true) { + if (this->queues_[queue_id].PopNonBlocking(&task)) { + task(); + // Reset backoff. + sleep_duration = 1; + } else { + usleep(sleep_duration); + // Back off exponentially. + if (sleep_duration < 32) + sleep_duration *= 2; + } + + if (this->stopped_.load(std::memory_order_relaxed)) { + // Go through ALL queues looking for a remaining task. + while (this->queues_[queue_id].Pop(&task)) { + task(); + } + + break; + } + } + } + + int thread_count_; + std::vector threads_; + + // Task queues. + std::vector> queues_; + + std::atomic stopped_; +}; + +#endif // _DB_UTILS_STATIC_THREAD_POOL_H_ diff --git a/a2_final/src/utils/testing.h b/a2_final/src/utils/testing.h new file mode 100644 index 0000000..751630b --- /dev/null +++ b/a2_final/src/utils/testing.h @@ -0,0 +1,70 @@ +#ifndef __TESTING_H_ +#define __TESTING_H_ + +#include +#include + +// Global variable tracking whether current test has failed. +bool __failed_; + +#define WARN(MSG) printf("%s:%d: %s\n", __FILE__, __LINE__, MSG) +#define CHECK(T, MSG) \ + do { \ + if (!(T)) { \ + __failed_ = true; \ + WARN(MSG); \ + } \ + } while (0) + +#define LINE std::cout << "[ " << __FUNCTION__ << " ] " + +#define EXPECT_TRUE(T) \ + do { \ + if (!(T)) { \ + __failed_ = true; \ + std::cout << "EXPECT_TRUE(" << #T << ") failed at " << __FILE__ << ":" \ + << __LINE__ << "\n"; \ + } \ + } while (0) + +#define EXPECT_FALSE(T) \ + do { \ + if (T) { \ + __failed_ = true; \ + std::cout << "EXPECT_FALSE(" << #T << ") failed at " << __FILE__ << ":" \ + << __LINE__ << "\n"; \ + } \ + } while (0) + +#define EXPECT_EQ(A, B) \ + do { \ + if ((A) != (B)) { \ + __failed_ = true; \ + std::cout << "EXPECT_EQ(" << #A << ", " << #B \ + << ") \033[1;31mfailed\033[0m at " << __FILE__ << ":" \ + << __LINE__ << "\n" \ + << "Expected:\n" \ + << A << "\n" \ + << "Actual:\n" \ + << B << "\n" \ + << std::flush; \ + } \ + } while (0) + +#define TEST(TESTNAME) \ + void TESTNAME() { \ + __failed_ = false; \ + LINE << "\033[1;32mBEGIN\033[0m\n"; \ + do + +#define END \ + if (__failed_) { \ + LINE << "\033[1;31mFAIL\033[0m\n" << std::flush; \ + } else { \ + LINE << "\033[1;32mPASS\033[0m\n" << std::flush; \ + } \ + } \ + while (0) \ + ; + +#endif // __TESTING_H_ diff --git a/a2_final/src/utils/thread_pool.h b/a2_final/src/utils/thread_pool.h new file mode 100644 index 0000000..6288327 --- /dev/null +++ b/a2_final/src/utils/thread_pool.h @@ -0,0 +1,21 @@ +#ifndef _DB_UTILS_THREAD_POOL_H_ +#define _DB_UTILS_THREAD_POOL_H_ + +#include + +class ThreadPool { +public: + using Task = std::function; + + virtual ~ThreadPool() {} + // Causes 'task' to be scheduled for background by a thread in the threadpool. + virtual void AddTask(Task &&task) = 0; + + virtual void AddTask(const Task &task) = 0; + + // Returns the number of active physical pthreads currently consituting the + // threadpool. + virtual int ThreadCount() = 0; +}; + +#endif // _DB_UTILS_THREAD_POOL_H_ From eb5cb5ccc70f66181d51cb6b3d4b74644a9dbc22 Mon Sep 17 00:00:00 2001 From: Rakrish Dhakal <41878376+hsirkar@users.noreply.github.com> Date: Thu, 6 Mar 2025 07:48:09 -0500 Subject: [PATCH 2/2] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 861ea15..8ffc898 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,14 @@ # CMSC624 Final Project +The name of this repository is rather vague, but it contains the source code for +the "From DAGs to Riches: Improving Transaction Throughput in a Deterministic System" paper, which +was produced as, you guessed it, the final project for CMSC624. + +Link to presentation: (insert link here) +Link to paper: (insert link here) + +# Contributors + Pranav Sivaraman Rakrish Dhakal Alex Movsesyan