Add JMH data access benchmark app
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
target
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# data-access-benchmark
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn package -q
|
||||||
|
java --enable-native-access=ALL-UNNAMED --sun-misc-unsafe-memory-access=allow -jar target/benchmarks.jar
|
||||||
|
```
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||||
|
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.benchmark</groupId>
|
||||||
|
<artifactId>data-access-benchmark</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<jmh.version>1.37</jmh.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- JMH -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjdk.jmh</groupId>
|
||||||
|
<artifactId>jmh-core</artifactId>
|
||||||
|
<version>${jmh.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjdk.jmh</groupId>
|
||||||
|
<artifactId>jmh-generator-annprocess</artifactId>
|
||||||
|
<version>${jmh.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Gson -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>2.10.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Kryo binary serialization -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.esotericsoftware</groupId>
|
||||||
|
<artifactId>kryo</artifactId>
|
||||||
|
<version>5.6.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- SQLite JDBC driver -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xerial</groupId>
|
||||||
|
<artifactId>sqlite-jdbc</artifactId>
|
||||||
|
<version>3.45.1.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- ORMLite -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.j256.ormlite</groupId>
|
||||||
|
<artifactId>ormlite-jdbc</artifactId>
|
||||||
|
<version>6.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Silence SLF4J "no binding" warning -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-nop</artifactId>
|
||||||
|
<version>2.0.13</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.11.0</version>
|
||||||
|
<configuration>
|
||||||
|
<source>17</source>
|
||||||
|
<target>17</target>
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>org.openjdk.jmh</groupId>
|
||||||
|
<artifactId>jmh-generator-annprocess</artifactId>
|
||||||
|
<version>${jmh.version}</version>
|
||||||
|
</path>
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<!-- Builds a self-contained benchmark jar -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.5.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<finalName>benchmarks</finalName>
|
||||||
|
<transformers>
|
||||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||||
|
<mainClass>org.openjdk.jmh.Main</mainClass>
|
||||||
|
</transformer>
|
||||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||||
|
</transformers>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>META-INF/*.SF</exclude>
|
||||||
|
<exclude>META-INF/*.DSA</exclude>
|
||||||
|
<exclude>META-INF/*.RSA</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.benchmark.benchmarks;
|
||||||
|
|
||||||
|
import com.benchmark.fixtures.DataFixtures;
|
||||||
|
import com.benchmark.fixtures.DataGenerator;
|
||||||
|
import com.benchmark.fixtures.FixtureFactory;
|
||||||
|
import com.benchmark.model.User;
|
||||||
|
import org.openjdk.jmh.annotations.*;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@State(Scope.Thread)
|
||||||
|
@BenchmarkMode({Mode.AverageTime, Mode.Throughput})
|
||||||
|
@OutputTimeUnit(TimeUnit.MICROSECONDS)
|
||||||
|
@Warmup(iterations = 3, time = 1)
|
||||||
|
@Measurement(iterations = 5, time = 1)
|
||||||
|
@Fork(1)
|
||||||
|
@Threads(Threads.MAX)
|
||||||
|
public class DataAccessBenchmark {
|
||||||
|
|
||||||
|
@Param({"gson", "kryo", "sqlite-jdbc", "sqlite-ormlite"})
|
||||||
|
private String fixtureType;
|
||||||
|
|
||||||
|
private DataFixtures fixture;
|
||||||
|
|
||||||
|
private static final long TARGET_ID = 500L;
|
||||||
|
|
||||||
|
@Setup(Level.Trial)
|
||||||
|
public void setup() throws Exception {
|
||||||
|
fixture = FixtureFactory.create(fixtureType);
|
||||||
|
fixture.setup(DataGenerator.generate(1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public User readSingleUser() throws Exception {
|
||||||
|
return fixture.findById(TARGET_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TearDown(Level.Trial)
|
||||||
|
public void teardown() throws Exception {
|
||||||
|
fixture.teardown();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.benchmark.fixtures;
|
||||||
|
|
||||||
|
import com.benchmark.model.User;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface DataFixtures {
|
||||||
|
void setup(List<User> users) throws Exception;
|
||||||
|
User findById(long id) throws Exception;
|
||||||
|
void teardown() throws Exception;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.benchmark.fixtures;
|
||||||
|
|
||||||
|
import com.benchmark.model.User;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DataGenerator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates {@code count} deterministic User objects with IDs 1..count.
|
||||||
|
*/
|
||||||
|
public static List<User> generate(int count) {
|
||||||
|
List<User> users = new ArrayList<>(count);
|
||||||
|
for (int i = 1; i <= count; i++) {
|
||||||
|
users.add(new User(
|
||||||
|
i,
|
||||||
|
"User" + i,
|
||||||
|
"user" + i + "@example.com",
|
||||||
|
20 + (i % 60),
|
||||||
|
1_000_000L + i
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.benchmark.fixtures;
|
||||||
|
|
||||||
|
public class FixtureFactory {
|
||||||
|
|
||||||
|
public static DataFixtures create(String type) {
|
||||||
|
return switch (type) {
|
||||||
|
case "gson" -> new GsonFileFixture();
|
||||||
|
case "kryo" -> new KryoFileFixture();
|
||||||
|
case "sqlite-jdbc" -> new SqliteJdbcFixture();
|
||||||
|
case "sqlite-ormlite" -> new SqliteOrmLiteFixture();
|
||||||
|
default -> throw new IllegalArgumentException("Unknown fixture type: " + type);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.benchmark.fixtures;
|
||||||
|
|
||||||
|
import com.benchmark.model.User;
|
||||||
|
import com.benchmark.util.FileUtil;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GsonFileFixture implements DataFixtures {
|
||||||
|
|
||||||
|
private Gson gson;
|
||||||
|
private Path dataDir;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setup(List<User> users) throws IOException {
|
||||||
|
gson = new Gson();
|
||||||
|
dataDir = Files.createTempDirectory("benchmark-gson-");
|
||||||
|
for (User user : users) {
|
||||||
|
Path file = FileUtil.userJsonPath(dataDir, user.getId());
|
||||||
|
Files.writeString(file, gson.toJson(user));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User findById(long id) throws IOException {
|
||||||
|
Path file = FileUtil.userJsonPath(dataDir, id);
|
||||||
|
String json = Files.readString(file);
|
||||||
|
return gson.fromJson(json, User.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void teardown() throws IOException {
|
||||||
|
if (dataDir != null && Files.exists(dataDir)) {
|
||||||
|
Files.walk(dataDir)
|
||||||
|
.sorted(Comparator.reverseOrder())
|
||||||
|
.forEach(p -> p.toFile().delete());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.benchmark.fixtures;
|
||||||
|
|
||||||
|
import com.benchmark.model.User;
|
||||||
|
import com.benchmark.util.FileUtil;
|
||||||
|
import com.esotericsoftware.kryo.Kryo;
|
||||||
|
import com.esotericsoftware.kryo.io.Input;
|
||||||
|
import com.esotericsoftware.kryo.io.Output;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class KryoFileFixture implements DataFixtures {
|
||||||
|
|
||||||
|
private Kryo kryo;
|
||||||
|
private Path dataDir;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setup(List<User> users) throws IOException {
|
||||||
|
kryo = new Kryo();
|
||||||
|
kryo.setRegistrationRequired(false);
|
||||||
|
kryo.register(User.class);
|
||||||
|
|
||||||
|
dataDir = Files.createTempDirectory("benchmark-kryo-");
|
||||||
|
for (User user : users) {
|
||||||
|
Path file = FileUtil.userBinPath(dataDir, user.getId());
|
||||||
|
try (Output output = new Output(new FileOutputStream(file.toFile()))) {
|
||||||
|
kryo.writeObject(output, user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User findById(long id) throws IOException {
|
||||||
|
Path file = FileUtil.userBinPath(dataDir, id);
|
||||||
|
try (Input input = new Input(new FileInputStream(file.toFile()))) {
|
||||||
|
return kryo.readObject(input, User.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void teardown() throws IOException {
|
||||||
|
if (dataDir != null && Files.exists(dataDir)) {
|
||||||
|
Files.walk(dataDir)
|
||||||
|
.sorted(Comparator.reverseOrder())
|
||||||
|
.forEach(p -> p.toFile().delete());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.benchmark.fixtures;
|
||||||
|
|
||||||
|
import com.benchmark.model.User;
|
||||||
|
import com.benchmark.util.DbUtil;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SqliteJdbcFixture implements DataFixtures {
|
||||||
|
|
||||||
|
private Connection connection;
|
||||||
|
private PreparedStatement selectStmt;
|
||||||
|
private Path dbFile;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setup(List<User> users) throws SQLException, Exception {
|
||||||
|
dbFile = Files.createTempFile("benchmark-jdbc-", ".db");
|
||||||
|
connection = DriverManager.getConnection("jdbc:sqlite:" + dbFile.toAbsolutePath());
|
||||||
|
DbUtil.createSchema(connection);
|
||||||
|
|
||||||
|
connection.setAutoCommit(false);
|
||||||
|
try (PreparedStatement ps = connection.prepareStatement(
|
||||||
|
"INSERT INTO users(id, name, email, age, created_at) VALUES(?,?,?,?,?)")) {
|
||||||
|
for (User user : users) {
|
||||||
|
ps.setLong(1, user.getId());
|
||||||
|
ps.setString(2, user.getName());
|
||||||
|
ps.setString(3, user.getEmail());
|
||||||
|
ps.setInt(4, user.getAge());
|
||||||
|
ps.setLong(5, user.getCreatedAt());
|
||||||
|
ps.addBatch();
|
||||||
|
}
|
||||||
|
ps.executeBatch();
|
||||||
|
}
|
||||||
|
connection.commit();
|
||||||
|
connection.setAutoCommit(true);
|
||||||
|
|
||||||
|
selectStmt = connection.prepareStatement(
|
||||||
|
"SELECT id, name, email, age, created_at FROM users WHERE id = ?");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User findById(long id) throws SQLException {
|
||||||
|
selectStmt.setLong(1, id);
|
||||||
|
try (ResultSet rs = selectStmt.executeQuery()) {
|
||||||
|
return rs.next() ? DbUtil.mapRow(rs) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void teardown() throws Exception {
|
||||||
|
if (selectStmt != null) selectStmt.close();
|
||||||
|
if (connection != null) connection.close();
|
||||||
|
if (dbFile != null) Files.deleteIfExists(dbFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.benchmark.fixtures;
|
||||||
|
|
||||||
|
import com.benchmark.model.User;
|
||||||
|
import com.j256.ormlite.dao.Dao;
|
||||||
|
import com.j256.ormlite.dao.DaoManager;
|
||||||
|
import com.j256.ormlite.jdbc.JdbcConnectionSource;
|
||||||
|
import com.j256.ormlite.table.TableUtils;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SqliteOrmLiteFixture implements DataFixtures {
|
||||||
|
|
||||||
|
private JdbcConnectionSource connectionSource;
|
||||||
|
private Dao<User, Long> dao;
|
||||||
|
private Path dbFile;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setup(List<User> users) throws Exception {
|
||||||
|
dbFile = Files.createTempFile("benchmark-ormlite-", ".db");
|
||||||
|
connectionSource = new JdbcConnectionSource("jdbc:sqlite:" + dbFile.toAbsolutePath());
|
||||||
|
TableUtils.createTableIfNotExists(connectionSource, User.class);
|
||||||
|
dao = DaoManager.createDao(connectionSource, User.class);
|
||||||
|
|
||||||
|
dao.callBatchTasks(() -> {
|
||||||
|
for (User user : users) {
|
||||||
|
dao.create(user);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User findById(long id) throws Exception {
|
||||||
|
return dao.queryForId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void teardown() throws Exception {
|
||||||
|
if (connectionSource != null) connectionSource.close();
|
||||||
|
if (dbFile != null) Files.deleteIfExists(dbFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.benchmark.model;
|
||||||
|
|
||||||
|
import com.j256.ormlite.field.DatabaseField;
|
||||||
|
import com.j256.ormlite.table.DatabaseTable;
|
||||||
|
|
||||||
|
@DatabaseTable(tableName = "users")
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
@DatabaseField(id = true)
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@DatabaseField
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@DatabaseField
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@DatabaseField
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
@DatabaseField(columnName = "created_at")
|
||||||
|
private long createdAt;
|
||||||
|
|
||||||
|
/** Required by Gson and ORMLite. */
|
||||||
|
public User() {}
|
||||||
|
|
||||||
|
public User(long id, String name, String email, int age, long createdAt) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.email = email;
|
||||||
|
this.age = age;
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getId() { return id; }
|
||||||
|
public String getName() { return name; }
|
||||||
|
public String getEmail() { return email; }
|
||||||
|
public int getAge() { return age; }
|
||||||
|
public long getCreatedAt() { return createdAt; }
|
||||||
|
|
||||||
|
public void setId(long id) { this.id = id; }
|
||||||
|
public void setName(String name) { this.name = name; }
|
||||||
|
public void setEmail(String email) { this.email = email; }
|
||||||
|
public void setAge(int age) { this.age = age; }
|
||||||
|
public void setCreatedAt(long createdAt) { this.createdAt = createdAt; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.benchmark.runner;
|
||||||
|
|
||||||
|
import com.benchmark.benchmarks.DataAccessBenchmark;
|
||||||
|
import org.openjdk.jmh.runner.Runner;
|
||||||
|
import org.openjdk.jmh.runner.options.Options;
|
||||||
|
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||||
|
|
||||||
|
public class BenchmarkMain {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
Options opt = new OptionsBuilder()
|
||||||
|
.include(DataAccessBenchmark.class.getSimpleName())
|
||||||
|
.jvmArgsPrepend(
|
||||||
|
"--enable-native-access=ALL-UNNAMED",
|
||||||
|
"--sun-misc-unsafe-memory-access=allow"
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
new Runner(opt).run();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.benchmark.util;
|
||||||
|
|
||||||
|
import com.benchmark.model.User;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
|
||||||
|
public class DbUtil {
|
||||||
|
|
||||||
|
public static void createSchema(Connection conn) throws SQLException {
|
||||||
|
try (Statement stmt = conn.createStatement()) {
|
||||||
|
stmt.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
email TEXT NOT NULL,
|
||||||
|
age INTEGER NOT NULL,
|
||||||
|
created_at INTEGER NOT NULL
|
||||||
|
)
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static User mapRow(ResultSet rs) throws SQLException {
|
||||||
|
return new User(
|
||||||
|
rs.getLong("id"),
|
||||||
|
rs.getString("name"),
|
||||||
|
rs.getString("email"),
|
||||||
|
rs.getInt("age"),
|
||||||
|
rs.getLong("created_at")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.benchmark.util;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class FileUtil {
|
||||||
|
|
||||||
|
public static Path userJsonPath(Path dir, long id) {
|
||||||
|
return dir.resolve(id + ".json");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Path userBinPath(Path dir, long id) {
|
||||||
|
return dir.resolve(id + ".bin");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user