Skip to content

Commit 5f7cb5b

Browse files
authored
Merge pull request #11 from little-pan/0.3.29-server-status
Added SQL metric for "show status" statement
2 parents 0721ac1 + 86f9ae7 commit 5f7cb5b

7 files changed

Lines changed: 171 additions & 19 deletions

File tree

src/main/java/org/sqlite/server/SQLiteProcessor.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.sqlite.server.func.StringResultFunc;
3838
import org.sqlite.server.func.TimestampFunc;
3939
import org.sqlite.server.func.UserFunc;
40+
import org.sqlite.server.sql.SQLMetric;
4041
import org.sqlite.server.sql.meta.Catalog;
4142
import org.sqlite.server.sql.meta.CreateDatabaseStatement;
4243
import org.sqlite.server.sql.meta.DropDatabaseStatement;
@@ -98,6 +99,8 @@ public abstract class SQLiteProcessor extends SQLContext implements AutoCloseabl
9899
protected SQLiteLocalDb localDb;
99100
protected Stack<TransactionStatement> savepointStack;
100101

102+
protected long sqlStartNanoTime;
103+
101104
protected SQLiteProcessor(SQLiteServer server, SocketChannel channel, int id)
102105
throws NetworkException {
103106
this.createTime = System.currentTimeMillis();
@@ -383,6 +386,49 @@ protected void prepareTransaction(TransactionStatement txSql) {
383386
trace(log, "{}, '{}' readOnly {}", tx, this, this.readOnly);
384387
}
385388

389+
@Override
390+
protected void preExecute(SQLStatement s) {
391+
final SQLMetric metric = this.worker.sqlMetric;
392+
393+
switch(s.getCommand()) {
394+
case "SELECT":
395+
metric.selectStmts++;
396+
break;
397+
case "UPDATE":
398+
metric.updateStmts++;
399+
break;
400+
case "INSERT":
401+
metric.insertStmts++;
402+
break;
403+
case "DELETE":
404+
metric.deleteStmts++;
405+
break;
406+
default:
407+
break;
408+
}
409+
metric.totalStmts++;
410+
411+
long longTime = this.server.getLongQueryNanoTime();
412+
if (longTime > 0L) {
413+
this.sqlStartNanoTime = System.nanoTime();
414+
} else {
415+
this.sqlStartNanoTime = 0L;
416+
}
417+
}
418+
419+
@Override
420+
protected void postExecute(SQLStatement s) {
421+
long longTime = this.server.getLongQueryNanoTime();
422+
final SQLMetric metric = this.worker.getSQLMetric();
423+
424+
if (longTime > 0L && this.sqlStartNanoTime > 0L) {
425+
if (System.nanoTime() - this.sqlStartNanoTime > longTime) {
426+
metric.slowStmts++;
427+
}
428+
}
429+
this.sqlStartNanoTime = 0L;
430+
}
431+
386432
@Override
387433
protected void pushSavepoint(TransactionStatement txSql) {
388434
this.savepointStack.push(txSql);

src/main/java/org/sqlite/server/SQLiteServer.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import org.sqlite.server.func.TimestampFunc;
5151
import org.sqlite.server.func.VersionFunc;
5252
import org.sqlite.server.pg.PgServer;
53+
import org.sqlite.server.sql.SQLMetric;
5354
import org.sqlite.server.sql.meta.Catalog;
5455
import org.sqlite.server.sql.meta.User;
5556
import org.sqlite.server.util.IoUtils;
@@ -77,6 +78,7 @@ public abstract class SQLiteServer implements AutoCloseable {
7778
public static final String HOST_DEFAULT = "localhost";
7879
public static final int AUTH_TIMEOUT_DEFAULT = 15000;
7980
public static final int PORT_DEFAULT = 3272;
81+
public static final int LONG_QUERY_TIME_DEFAULT = 2000;
8082
public static final int MAX_CONNS_DEFAULT = 50;
8183
public static final int MAX_WORKER_COUNT = 128;
8284
public static final int OPEN_TIMEOUT_DEFAULT = 30000;
@@ -112,6 +114,8 @@ public abstract class SQLiteServer implements AutoCloseable {
112114
protected int authTimeout = AUTH_TIMEOUT_DEFAULT;
113115
protected int sleepTimeout = SLEEP_TIMEOUT_DEFAULT;
114116
protected int sleepInTxTimeout = SLEEP_IN_TX_TIMEOUT_DEFAULT;
117+
protected long longQueryNanoTime = LONG_QUERY_TIME_DEFAULT * 1000000L;
118+
115119
protected JournalMode journalMode = JOURNAL_MODE_DEFAULT;
116120
protected SynchronousMode synchronous = SYNCHRONOUS_DEFAULT;
117121
private final ConcurrentMap<String, SQLContext> dbWriteLocks;
@@ -439,6 +443,8 @@ public void init(String... args) {
439443
this.authMethod = toLowerEnglish(args[++i]);
440444
} else if ("--max-allowed-packet".equals(a)) {
441445
this.maxAllowedPacket = Long.decode(args[++i]);
446+
} else if("--long-query-time".equals(a)) {
447+
this.longQueryNanoTime = Long.decode(args[++i]) * 1000000L;
442448
} else if ("--help".equals(a) || "-h".equals(a) || "-?".equals(a)) {
443449
help = true;
444450
}
@@ -791,6 +797,10 @@ public File getDbFile(String dbName) {
791797
return new File(this.dataDir, dbName);
792798
}
793799

800+
public long getLongQueryNanoTime() {
801+
return this.longQueryNanoTime;
802+
}
803+
794804
protected SQLiteMetaDb getMetaDb() {
795805
return this.metaDb;
796806
}
@@ -840,6 +850,25 @@ public int getSleepInTxTimeout() {
840850
return this.sleepInTxTimeout;
841851
}
842852

853+
public SQLMetric getSQLMetric() {
854+
final SQLiteWorker[] workers = this.workers;
855+
final SQLMetric metric = new SQLMetric();
856+
857+
for (final SQLiteWorker worker: workers) {
858+
if (worker != null) {
859+
SQLMetric m = worker.getSQLMetric();
860+
metric.deleteStmts += m.deleteStmts;
861+
metric.insertStmts += m.insertStmts;
862+
metric.selectStmts += m.selectStmts;
863+
metric.updateStmts += m.updateStmts;
864+
metric.totalStmts += m.totalStmts;
865+
metric.slowStmts += m.slowStmts;
866+
}
867+
}
868+
869+
return metric;
870+
}
871+
843872
public boolean inDataDir(String filename) {
844873
return inDataDir(filename, this.dataDir);
845874
}
@@ -1052,6 +1081,7 @@ protected String getBootHelp() {
10521081
" --help|-h|-? \tShow this message\n" +
10531082
" --host|-H <host> \tSQLite server listen host or IP, default "+HOST_DEFAULT+"\n"+
10541083
" --journal-mode <mode> \tSQLite journal mode, default "+JOURNAL_MODE_DEFAULT+"\n"+
1084+
" --long-query-time <millis> \tLong SQL query time, default "+LONG_QUERY_TIME_DEFAULT+"ms\n"+
10551085
" --max-allowed-packet <number> \tMax allowed packet size, default " + MAX_ALLOWED_PACKET_DEFAULT+"B\n"+
10561086
" --max-conns <number> \tMax client connections limit, default "+MAX_CONNS_DEFAULT+"\n"+
10571087
" --open-timeout <millis> \tOpen SQLite database timeout, default "+OPEN_TIMEOUT_DEFAULT+"ms\n"+

src/main/java/org/sqlite/server/SQLiteWorker.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import org.slf4j.Logger;
3030
import org.slf4j.LoggerFactory;
31+
import org.sqlite.server.sql.SQLMetric;
3132
import org.sqlite.server.sql.meta.User;
3233
import org.sqlite.server.util.IoUtils;
3334
import org.sqlite.server.util.SlotAllocator;
@@ -62,6 +63,8 @@ public class SQLiteWorker implements Runnable {
6263
private final SlotAllocator<SQLiteProcessor> processors;
6364
private final SlotAllocator<SQLiteProcessor> busyProcs;
6465

66+
protected final SQLMetric sqlMetric = new SQLMetric();
67+
6568
public SQLiteWorker(SQLiteServer server, int id) {
6669
this.server = server;
6770
this.id = id;
@@ -502,6 +505,10 @@ protected long minSelectTimeout(final long curr, final long idleCheckIntv) {
502505

503506
return timeout;
504507
}
508+
509+
public SQLMetric getSQLMetric() {
510+
return this.sqlMetric;
511+
}
505512

506513
SQLiteProcessor getProcessor(int pid) {
507514
SlotAllocator<SQLiteProcessor> processors = this.processors;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Copyright 2019 little-pan. A SQLite server based on the C/S architecture.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.sqlite.server.sql;
17+
18+
/** SQL statement metric.
19+
*
20+
* @author little-pan
21+
* @since 2019-12-21
22+
*
23+
*/
24+
public class SQLMetric {
25+
26+
// Imprecise is intentional for performance
27+
public volatile long selectStmts;
28+
public volatile long updateStmts;
29+
public volatile long insertStmts;
30+
public volatile long deleteStmts;
31+
public volatile long totalStmts;
32+
33+
public volatile long slowStmts;
34+
35+
public SQLMetric() {
36+
37+
}
38+
39+
}

src/main/java/org/sqlite/server/sql/local/ShowStatusStatement.java

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@
2828
import java.util.Date;
2929

3030
import org.sqlite.server.SQLiteProcessor;
31+
import org.sqlite.server.SQLiteServer;
32+
import org.sqlite.server.sql.SQLMetric;
3133

32-
/** "SHOW STATUS" statement that shows server current status, includes memory,
34+
/** "SHOW STATUS" statement that shows server current status, includes SQL, memory,
3335
* thread, runtime and OS information.
3436
*
3537
* @author little-pan
@@ -47,7 +49,8 @@ public ShowStatusStatement(String sql) {
4749
@Override
4850
protected String getSQL(String localSchema) throws SQLException {
4951
final String f =
50-
"select Mem_Committed, Mem_Max, Mem_Used, "
52+
"select Select_Stmts, Update_Stmts, Insert_Stmts, Delete_Stmts, Total_Stmts, Slow_Stmts, "
53+
+ "Mem_Committed, Mem_Max, Mem_Used, "
5154
+ "OS_Arch, OS_Name, OS_Version, "
5255
+ "RT_Name, RT_Start_Time, RT_Uptime, RT_Vendor, RT_Version, "
5356
+ "Thread_Count, Thread_Daemon_Count, Thread_Peak_Count, Thread_Started_Count, "
@@ -64,9 +67,15 @@ protected void init() throws SQLException {
6467
String f, sql;
6568
// CREATE TABLE
6669
f = "create table if not exists '%s'.%s("
67-
+ "`Mem_Committed` bigint null,"
68-
+ "`Mem_Max` bigint not null,"
69-
+ "`Mem_Used` bigint not null,"
70+
+ "`Select_Stmts` bigint,"
71+
+ "`Update_Stmts` bigint,"
72+
+ "`Insert_Stmts` bigint,"
73+
+ "`Delete_Stmts` bigint,"
74+
+ "`Total_Stmts` bigint,"
75+
+ "`Slow_Stmts` bigint,"
76+
+ "`Mem_Committed` bigint,"
77+
+ "`Mem_Max` bigint,"
78+
+ "`Mem_Used` bigint,"
7079
+ "`OS_Arch` varchar(80),"
7180
+ "`OS_Name` varchar(64),"
7281
+ "`OS_Version` varchar(64),"
@@ -96,12 +105,15 @@ public void preExecute(int maxRows) throws SQLException, IllegalStateException {
96105

97106
// Collect processor state
98107
SQLiteProcessor processor = super.getContext();
108+
SQLiteServer server = processor.getServer();
99109
// INSERT new data for query
100-
f = "insert into '%s'.%s(`Mem_Committed`, `Mem_Max`, `Mem_Used`, `OS_Arch`, `OS_Name`, `OS_Version`, "
110+
f = "insert into '%s'.%s(`Select_Stmts`, `Update_Stmts`, `Insert_Stmts`, `Delete_Stmts`, "
111+
+ "`Total_Stmts`, `Slow_Stmts`,"
112+
+ "`Mem_Committed`, `Mem_Max`, `Mem_Used`, `OS_Arch`, `OS_Name`, `OS_Version`, "
101113
+ "`RT_Name`, `RT_Start_Time`, `RT_Uptime`, `RT_Vendor`, `RT_Version`, "
102114
+ "`Thread_Count`, `Thread_Daemon_Count`, `Thread_Peak_Count`, `Thread_Started_Count`, "
103115
+ "`Sys_Load_Average`)"
104-
+ "values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
116+
+ "values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
105117
sql = format(f, localSchema, TBL_NAME);
106118
try (PreparedStatement ps = processor.getConnection().prepareStatement(sql)) {
107119
MemoryMXBean memMxBean = ManagementFactory.getMemoryMXBean();
@@ -114,6 +126,15 @@ public void preExecute(int maxRows) throws SQLException, IllegalStateException {
114126
int i = 0;
115127
long v = -1;
116128

129+
// SQL metric
130+
SQLMetric sqlMetric = server.getSQLMetric();
131+
ps.setLong(++i, sqlMetric.selectStmts);
132+
ps.setLong(++i, sqlMetric.updateStmts);
133+
ps.setLong(++i, sqlMetric.insertStmts);
134+
ps.setLong(++i, sqlMetric.deleteStmts);
135+
ps.setLong(++i, sqlMetric.totalStmts);
136+
ps.setLong(++i, sqlMetric.slowStmts);
137+
117138
// Memory committed
118139
if (heapMemUsage.getCommitted() > 0) {
119140
v = heapMemUsage.getCommitted();

src/main/java/org/sqlite/sql/SQLContext.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,9 @@ public void setTransaction(Transaction transaction) throws IllegalStateException
112112
public abstract String getDbName();
113113

114114
public abstract File getDataDir();
115+
116+
protected abstract void preExecute(SQLStatement s);
117+
118+
protected abstract void postExecute(SQLStatement s);
115119

116120
}

src/main/java/org/sqlite/sql/SQLStatement.java

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -220,19 +220,24 @@ protected boolean doExecute(int maxRows) throws SQLException {
220220
}
221221

222222
context.trace(log, "execute sql \"{}\"", this);
223-
if (this.prepared) {
224-
// Execute batch prepared statement in an implicit transaction for ACID
225-
if (shouldBeginImplicitTx(autoCommit, writable)) {
226-
execute("begin immediate");
227-
Transaction tx = new Transaction(context, true);
228-
context.setTransaction(tx);
229-
context.trace(log, "tx: begin an implicit {}", tx);
223+
context.preExecute(this);
224+
try {
225+
if (this.prepared) {
226+
// Execute batch prepared statement in an implicit transaction for ACID
227+
if (shouldBeginImplicitTx(autoCommit, writable)) {
228+
execute("begin immediate");
229+
Transaction tx = new Transaction(context, true);
230+
context.setTransaction(tx);
231+
context.trace(log, "tx: begin an implicit {}", tx);
232+
}
233+
PreparedStatement ps = getPreparedStatement();
234+
resultSet = ps.execute();
235+
} else {
236+
String sql = getExecutableSQL();
237+
resultSet = this.jdbcStatement.execute(sql);
230238
}
231-
PreparedStatement ps = getPreparedStatement();
232-
resultSet = ps.execute();
233-
} else {
234-
String sql = getExecutableSQL();
235-
resultSet = this.jdbcStatement.execute(sql);
239+
} finally {
240+
context.postExecute(this);
236241
}
237242

238243
final Transaction tx = context.getTransaction();

0 commit comments

Comments
 (0)