Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Java CI with Maven

on:
push:
branches:
- master # Trigger only on push to master branch (e.g., after merging a PR)
pull_request:
branches:
- master
jobs:
build:

runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3
Comment on lines +15 to +17
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix indentation for steps entries
The list under steps: should be indented by 6 spaces (not 4) to satisfy YAML syntax.
Apply this diff:

-    steps:
-    - name: Checkout code
+      steps:
+      - name: Checkout code

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 actionlint (1.7.7)

17-17: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🪛 YAMLlint (1.37.1)

[warning] 16-16: wrong indentation: expected 6 but found 4

(indentation)

🤖 Prompt for AI Agents
In .github/workflows/ci.yml around lines 15 to 17, the entries under the steps
key are indented with 4 spaces instead of the required 6 spaces for proper YAML
syntax. Adjust the indentation of all lines under steps to be 6 spaces to ensure
correct parsing of the workflow file.


- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: '21' # Or 11, 21, etc.
distribution: 'temurin' # Recommended distribution

- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-


- name: Build and test with Maven
run: mvn test -Dtest=BtreeBenchmark
Comment on lines +15 to +35
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Restructure steps for correct YAML and improved clarity.
Consolidate each step to group name, uses, and with under the same list item with proper 6-space indentation.

Apply this diff:

-    steps:
-    - name: Checkout code
-      uses: actions/checkout@v3
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v3

-    - name: Set up JDK
-      uses: actions/setup-java@v3
-      with:
-        java-version: '21'
-        distribution: 'temurin'
+      - name: Set up JDK
+        uses: actions/setup-java@v3
+        with:
+          java-version: '21'
+          distribution: 'temurin'

-    - name: Cache Maven packages
-      uses: actions/cache@v3
-      with:
-        path: ~/.m2
-        key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
-        restore-keys: |
-          ${{ runner.os }}-maven-
+      - name: Cache Maven packages
+        uses: actions/cache@v3
+        with:
+          path: ~/.m2
+          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+          restore-keys: |
+            ${{ runner.os }}-maven-

-    - name: Build and test with Maven
-      run: mvn test -Dtest=BtreeBenchmark
+      - name: Build and test with Maven
+        run: mvn test -Dtest=BtreeBenchmark
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: '21' # Or 11, 21, etc.
distribution: 'temurin' # Recommended distribution
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Build and test with Maven
run: mvn test -Dtest=BtreeBenchmark
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: '21' # Or 11, 21, etc.
distribution: 'temurin' # Recommended distribution
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Build and test with Maven
run: mvn test -Dtest=BtreeBenchmark
🧰 Tools
🪛 actionlint (1.7.7)

17-17: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


20-20: the runner of "actions/setup-java@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


26-26: the runner of "actions/cache@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🪛 YAMLlint (1.37.1)

[warning] 16-16: wrong indentation: expected 6 but found 4

(indentation)

🤖 Prompt for AI Agents
In .github/workflows/ci.yml between lines 15 and 35, the steps are not properly
indented and grouped, causing YAML structure issues. Fix this by ensuring each
step is a single list item with the keys 'name', 'uses', and 'with' properly
nested under it with consistent 6-space indentation. This will improve clarity
and ensure the workflow runs correctly.

2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.vscode
bin
storage
storage/*.btree
target
lib
165 changes: 165 additions & 0 deletions src/test/btree/BtreeBenchmark.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ public void setUp() {
btree = new Btree(keyType, valueType, btreeFilePath, Globals.INVALID_PAGE_ID, bufferPool);
}

public void setUp2() {
CleanUp();
// Initialize the DiskManager
diskManager = new BasicDiskManager();
// Initialize the buffer pool with a size of 10 pages
bufferPool = new BufferPool(MAX_PAGES, K, diskManager);
keyType = new Template(Integer.class);
valueType = new Template(Integer.class);
// Initialize the B-tree
btree = new Btree(keyType, valueType, btreeFilePath, Globals.INVALID_PAGE_ID, bufferPool);
}

@After
public void CleanUp() {
// monitor.interrupt();
Expand All @@ -60,6 +72,7 @@ private Compositekey makeCompositekey(int age, int salary, Template type) {
return key;
}


private Compositekey makeCompositekey(int val, Template type) {
Compositekey key = new Compositekey(type);
key.set(0, val, Integer.class);
Expand Down Expand Up @@ -554,4 +567,156 @@ public void testBtreeBenchmark3() throws Exception {
Arrays.stream(overallThroughputs).average().getAsDouble());
System.out.println("└───────────────────────────────────────────────────────────");
}


@Test
public void testBtreeBenchmark4() throws Exception {
int keysnumber = 2_000_000;
double[] totalExecutionTimes = new double[ITERATIONS];
double[] totalInsertTimes = new double[ITERATIONS];
double[] avgInsertTimes = new double[ITERATIONS];
double[] insertThroughputs = new double[ITERATIONS];
double[] totalSearchTimes = new double[ITERATIONS];
double[] avgSearchTimes = new double[ITERATIONS];
double[] searchThroughputs = new double[ITERATIONS];
double[] overallThroughputs = new double[ITERATIONS];

for (int iteration = 0; iteration < ITERATIONS; iteration++) {
setUp2(); // Reset the environment for each iteration
int writersCnt = 200;
int readersCnt = 200;
List<Thread> threads = new ArrayList<>();
int op = 10000;


double[] insertTimes = new double[2 * keysnumber];
double[] searchTimes = new double[keysnumber];

threads = new ArrayList<>();
double startTime = (double) System.currentTimeMillis();
double startTimeW = (double) System.currentTimeMillis();
// Insert operations
for (int i = 0; i < writersCnt; i++) {
final int end = op * (i + 1);
Thread writer =
new Thread(
() -> {
for (int key = end - op; key < end; key++) {
try {
long insertStartTime = System.currentTimeMillis();
btree.insert(
makeCompositekey(key, keyType),
makeCompositekey(key, valueType));
long insertEndTime = System.currentTimeMillis();
insertTimes[key] = (insertEndTime - insertStartTime);
} catch (Exception e) {
e.printStackTrace();
fail();
}
}
});
threads.add(writer);
}

Collections.shuffle(threads);
for (Thread thread : threads) {
thread.start();
}

for (Thread thread : threads) {
thread.join();
}

double insertTotalTime = System.currentTimeMillis() - startTimeW;
totalInsertTimes[iteration] = insertTotalTime;
avgInsertTimes[iteration] = Arrays.stream(insertTimes).average().getAsDouble();
insertThroughputs[iteration] = 2 * keysnumber / insertTotalTime * 1000;

Comment on lines +592 to +634
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Incorrect array sizing & throughput maths in testBtreeBenchmark4
testBtreeBenchmark4() performs insert-only work, yet:

  • insertTimes is sized to 2 * keysnumber (line 592) – half of this array remains zero-filled, biasing the average downward.
  • Throughput uses 2 * keysnumber (line 633) – overstating throughput by 100 %.

Fix both to reflect the real number of operations:

-      double[] insertTimes = new double[2 * keysnumber];
+      double[] insertTimes = new double[keysnumber];

-      insertThroughputs[iteration] = 2 * keysnumber / insertTotalTime * 1000;
+      insertThroughputs[iteration] = 1.0 * keysnumber / insertTotalTime * 1000;

Without this change, the reported benchmarks are misleading and could mask performance regressions.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
double[] insertTimes = new double[2 * keysnumber];
double[] searchTimes = new double[keysnumber];
threads = new ArrayList<>();
double startTime = (double) System.currentTimeMillis();
double startTimeW = (double) System.currentTimeMillis();
// Insert operations
for (int i = 0; i < writersCnt; i++) {
final int end = op * (i + 1);
Thread writer =
new Thread(
() -> {
for (int key = end - op; key < end; key++) {
try {
long insertStartTime = System.currentTimeMillis();
btree.insert(
makeCompositekey(key, keyType),
makeCompositekey(key, valueType));
long insertEndTime = System.currentTimeMillis();
insertTimes[key] = (insertEndTime - insertStartTime);
} catch (Exception e) {
e.printStackTrace();
fail();
}
}
});
threads.add(writer);
}
Collections.shuffle(threads);
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
thread.join();
}
double insertTotalTime = System.currentTimeMillis() - startTimeW;
totalInsertTimes[iteration] = insertTotalTime;
avgInsertTimes[iteration] = Arrays.stream(insertTimes).average().getAsDouble();
insertThroughputs[iteration] = 2 * keysnumber / insertTotalTime * 1000;
double[] insertTimes = new double[keysnumber];
double[] searchTimes = new double[keysnumber];
threads = new ArrayList<>();
double startTime = (double) System.currentTimeMillis();
double startTimeW = (double) System.currentTimeMillis();
// Insert operations
for (int i = 0; i < writersCnt; i++) {
final int end = op * (i + 1);
Thread writer =
new Thread(
() -> {
for (int key = end - op; key < end; key++) {
try {
long insertStartTime = System.currentTimeMillis();
btree.insert(
makeCompositekey(key, keyType),
makeCompositekey(key, valueType));
long insertEndTime = System.currentTimeMillis();
insertTimes[key] = (insertEndTime - insertStartTime);
} catch (Exception e) {
e.printStackTrace();
fail();
}
}
});
threads.add(writer);
}
Collections.shuffle(threads);
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
thread.join();
}
double insertTotalTime = System.currentTimeMillis() - startTimeW;
totalInsertTimes[iteration] = insertTotalTime;
avgInsertTimes[iteration] = Arrays.stream(insertTimes).average().getAsDouble();
insertThroughputs[iteration] = 1.0 * keysnumber / insertTotalTime * 1000;
🤖 Prompt for AI Agents
In src/test/btree/BtreeBenchmark.java around lines 592 to 634, the insertTimes
array is incorrectly sized to 2 * keysnumber, causing half the array to remain
zero and biasing the average insert time. Also, the throughput calculation
incorrectly multiplies keysnumber by 2, overstating throughput. Fix this by
resizing insertTimes to keysnumber and adjusting the throughput calculation to
use keysnumber instead of 2 * keysnumber to accurately reflect the number of
insert operations performed.

// Search operations
threads = new ArrayList<>();
double startTime2 = System.currentTimeMillis();

for (int i = 0; i < readersCnt; i++) {
final int end = op * (i + 1);
Thread reader =
new Thread(
() -> {
for (int key = end - op; key < end; key++) {
try {
long searchStartTime = System.currentTimeMillis();
Compositekey val =
btree.get(makeCompositekey(key, keyType));
long searchEndTime = System.currentTimeMillis();
searchTimes[key] = (searchEndTime - searchStartTime);
// assertEquals(0, val.compareTo(makeCompositekey(key, valueType)));
} catch (Exception e) {
System.out.println("thread " + end / op + ": expected ->" + key);
e.printStackTrace();
fail();
}
}
});
threads.add(reader);
}

Collections.shuffle(threads);
for (Thread thread : threads) {
thread.start();
}

for (Thread thread : threads) {
thread.join();
}

double searchTotalTime = System.currentTimeMillis() - startTime2;
totalSearchTimes[iteration] = searchTotalTime;
avgSearchTimes[iteration] = Arrays.stream(searchTimes).average().getAsDouble();
searchThroughputs[iteration] = keysnumber / searchTotalTime * 1000;

double endTime = System.currentTimeMillis();
totalExecutionTimes[iteration] = (endTime - startTime) / 1000.0;
overallThroughputs[iteration] = (keysnumber * 3) / (insertTotalTime + searchTotalTime) * 1000;

CleanUp(); // Clean up after each iteration
System.out.println("Iteration " + (iteration + 1) + " completed");
}

// Calculate and display averages
System.out.println("┌───────────────────────────────────────────────────────────");
System.out.printf(
"\033[1;36m B-TREE BENCHMARK RESULTS (%d ITERATIONS) \033[0m\n",
ITERATIONS);
System.out.println("┬───────────────────────────────────────────────────────────");
System.out.printf(
" \033[1mAverage total execution time:\033[0m %8.2f seconds\n",
Arrays.stream(totalExecutionTimes).average().getAsDouble());
System.out.println("┼───────────────────────────────────────────────────────────");
System.out.printf(" \033[1;32mInsert+Delete operations:\033[0m\n");
System.out.printf(
" - Average total time: %8.2f seconds\n",
Arrays.stream(totalInsertTimes).average().getAsDouble() / 1000);
System.out.printf(
" - Average operation time: %8.2f ms per operation\n",
Arrays.stream(avgInsertTimes).average().getAsDouble());
System.out.printf(
" - Average throughput: %8.2f operations per second\n",
Arrays.stream(insertThroughputs).average().getAsDouble());
System.out.println("┼───────────────────────────────────────────────────────────");
System.out.printf(" \033[1;33mSearch operations:\033[0m\n");
System.out.printf(
" - Average total time: %8.2f seconds\n",
Arrays.stream(totalSearchTimes).average().getAsDouble() / 1000);
System.out.printf(
" - Average operation time: %8.2f ms per operation\n",
Arrays.stream(avgSearchTimes).average().getAsDouble());
System.out.printf(
" - Average throughput: %8.2f operations per second\n",
Arrays.stream(searchThroughputs).average().getAsDouble());
System.out.println("┼───────────────────────────────────────────────────────────");
System.out.printf(
" \033[1;35mAverage overall throughput:\033[0m %8.2f operations per second\n",
Arrays.stream(overallThroughputs).average().getAsDouble());
System.out.println("└───────────────────────────────────────────────────────────");
}

}
1 change: 1 addition & 0 deletions storage/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
place holder