Merge lp:~tjoneslo/akiban-server/add-user-monitor into lp:~akiban-technologies/akiban-server/trunk

Proposed by Thomas Jones-Low
Status: Merged
Approved by: Nathan Williams
Approved revision: 2644
Merged at revision: 2646
Proposed branch: lp:~tjoneslo/akiban-server/add-user-monitor
Merge into: lp:~akiban-technologies/akiban-server/trunk
Diff against target: 432 lines (+233/-3)
10 files modified
src/main/java/com/akiban/server/service/is/ServerSchemaTablesServiceImpl.java (+60/-0)
src/main/java/com/akiban/server/service/monitor/MonitorService.java (+18/-0)
src/main/java/com/akiban/server/service/monitor/MonitorServiceImpl.java (+41/-1)
src/main/java/com/akiban/server/service/monitor/SessionMonitor.java (+3/-0)
src/main/java/com/akiban/server/service/monitor/SessionMonitorBase.java (+12/-0)
src/main/java/com/akiban/server/service/monitor/UserMonitor.java (+32/-0)
src/main/java/com/akiban/server/service/security/SecurityServiceImpl.java (+13/-1)
src/main/java/com/akiban/server/service/security/UserMonitorImpl.java (+51/-0)
src/main/java/com/akiban/sql/pg/PostgresServerConnection.java (+1/-0)
src/test/java/com/akiban/server/service/is/SchemaTableServiceIT.java (+2/-1)
To merge this branch: bzr merge lp:~tjoneslo/akiban-server/add-user-monitor
Reviewer Review Type Date Requested Status
Nathan Williams Approve
Thomas Jones-Low Needs Resubmitting
Review via email: mp+161017@code.launchpad.net

Description of the change

Add a UserMonitor with IS.SERVER_USERS to show how much work each user is doing.

This creates a UserMonitor which is registered with the MontitorService and attached to the SessionMonitor when the user logs in. Currently this only works on the Postgres and InternalJDBC connections. If not using password or SSL security (i.e, security is none) there are no UserMonitors created.

This is mostly infrastructure. The only thing the UserMonitor counts currently is number of SQL statements executed. This can easily be extended, and will be at a later time.

This includes a new I_S.SERVER_USERS table to display the data gathered by the UserMonitor to the user. This table is sensitive to the restricted access security that the SERVER_SESSIONS (and other) tables are.

To post a comment you must log in.
Revision history for this message
Nathan Williams (nwilliams) wrote :

Tiny nit. Diff line 170 can just remove, instead of contains and remove. The string based contract being looser (i.e. not asserting) is fine though.

I'm not sure we'll want to blow away the monitor, diff line 322, if a user is deleted in general. Long term random guess: they still need billed. But I'm hand waving and we can always adjust as we figure out how we want to use it.

review: Needs Fixing
Revision history for this message
Thomas Jones-Low (tjoneslo) wrote :

There's a whole chunk of how we capture the session monitor (including the user monitor) data when the user logs out that needs to be captured before the logout is completed. Or the server is restarted. These are known issues that need to be addressed.

I've made the deregister cleaner per your request.

review: Needs Resubmitting
Revision history for this message
Nathan Williams (nwilliams) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/main/java/com/akiban/server/service/is/ServerSchemaTablesServiceImpl.java'
--- src/main/java/com/akiban/server/service/is/ServerSchemaTablesServiceImpl.java 2013-04-23 22:45:16 +0000
+++ src/main/java/com/akiban/server/service/is/ServerSchemaTablesServiceImpl.java 2013-04-26 00:32:25 +0000
@@ -44,6 +44,7 @@
44import com.akiban.server.service.monitor.PreparedStatementMonitor;44import com.akiban.server.service.monitor.PreparedStatementMonitor;
45import com.akiban.server.service.monitor.ServerMonitor;45import com.akiban.server.service.monitor.ServerMonitor;
46import com.akiban.server.service.monitor.SessionMonitor;46import com.akiban.server.service.monitor.SessionMonitor;
47import com.akiban.server.service.monitor.UserMonitor;
47import com.akiban.server.service.security.SecurityService;48import com.akiban.server.service.security.SecurityService;
48import com.akiban.server.service.session.Session;49import com.akiban.server.service.session.Session;
49import com.akiban.server.store.SchemaManager;50import com.akiban.server.store.SchemaManager;
@@ -67,6 +68,7 @@
67 static final TableName SERVER_TAPS = new TableName (SCHEMA_NAME, "server_taps");68 static final TableName SERVER_TAPS = new TableName (SCHEMA_NAME, "server_taps");
68 static final TableName SERVER_PREPARED_STATEMENTS = new TableName (SCHEMA_NAME, "server_prepared_statements");69 static final TableName SERVER_PREPARED_STATEMENTS = new TableName (SCHEMA_NAME, "server_prepared_statements");
69 static final TableName SERVER_CURSORS = new TableName (SCHEMA_NAME, "server_cursors");70 static final TableName SERVER_CURSORS = new TableName (SCHEMA_NAME, "server_cursors");
71 static final TableName SERVER_USERS = new TableName (SCHEMA_NAME, "server_users");
7072
71 private final MonitorService monitor;73 private final MonitorService monitor;
72 private final ConfigurationService configService;74 private final ConfigurationService configService;
@@ -109,6 +111,8 @@
109 attach (ais, true, SERVER_PREPARED_STATEMENTS, PreparedStatements.class);111 attach (ais, true, SERVER_PREPARED_STATEMENTS, PreparedStatements.class);
110 //SERVER_CURSORS112 //SERVER_CURSORS
111 attach (ais, true, SERVER_CURSORS, Cursors.class);113 attach (ais, true, SERVER_CURSORS, Cursors.class);
114 //SERVER_USERS
115 attach(ais, true, SERVER_USERS, Users.class);
112 }116 }
113117
114 @Override118 @Override
@@ -136,6 +140,18 @@
136 }140 }
137 }141 }
138142
143 protected Collection<UserMonitor> getAccessibleUsers (Session session) {
144 if (securityService.hasRestrictedAccess(session)) {
145 return monitor.getUserMonitors();
146 } else {
147 UserMonitor um = monitor.getUserMonitor(session);
148 if (um == null) {
149 return Collections.emptyList();
150 } else {
151 return Collections.singletonList(um);
152 }
153 }
154 }
139 private class InstanceSummary extends BasicFactoryBase {155 private class InstanceSummary extends BasicFactoryBase {
140156
141 public InstanceSummary(TableName sourceTable) {157 public InstanceSummary(TableName sourceTable) {
@@ -565,6 +581,46 @@
565 }581 }
566 }582 }
567583
584 private class Users extends BasicFactoryBase {
585
586 public Users(TableName sourceTable) {
587 super(sourceTable);
588 }
589
590 @Override
591 public GroupScan getGroupScan(MemoryAdapter adapter) {
592 return new Scan (adapter.getSession(), getRowType(adapter));
593 }
594
595 @Override
596 public long rowCount() {
597 return monitor.getUserMonitors().size();
598 }
599
600 private class Scan extends BaseScan {
601 final Iterator<UserMonitor> users;
602
603 public Scan(Session session, RowType rowType) {
604 super(rowType);
605 users = getAccessibleUsers(session).iterator();
606 }
607
608 @Override
609 public Row next() {
610 if (!users.hasNext()) {
611 return null;
612 }
613 UserMonitor user = users.next();
614 ValuesRow row = new ValuesRow (rowType,
615 user.getUserName(),
616 user.getStatementCount(),
617 ++rowCounter);
618 return row;
619 }
620 }
621 }
622
623
568 static AkibanInformationSchema createTablesToRegister() {624 static AkibanInformationSchema createTablesToRegister() {
569 NewAISBuilder builder = AISBBasedBuilder.create();625 NewAISBuilder builder = AISBBasedBuilder.create();
570 626
@@ -635,6 +691,10 @@
635 .colTimestamp("creation_time", true)691 .colTimestamp("creation_time", true)
636 .colBigInt("row_count", true);692 .colBigInt("row_count", true);
637693
694 builder.userTable(SERVER_USERS)
695 .colString("user_name", IDENT_MAX, false)
696 .colBigInt("statement_count", false);
697
638 return builder.ais(false);698 return builder.ais(false);
639 }699 }
640}700}
641701
=== modified file 'src/main/java/com/akiban/server/service/monitor/MonitorService.java'
--- src/main/java/com/akiban/server/service/monitor/MonitorService.java 2013-04-23 22:45:16 +0000
+++ src/main/java/com/akiban/server/service/monitor/MonitorService.java 2013-04-26 00:32:25 +0000
@@ -58,4 +58,22 @@
5858
59 /** Log last statement from given monitor. */59 /** Log last statement from given monitor. */
60 void logQuery(SessionMonitor sessionMonitor);60 void logQuery(SessionMonitor sessionMonitor);
61
62 /** Register the given User monitor. */
63 void registerUserMonitor (UserMonitor userMonitor);
64
65 /** Deregister the given user montitor. */
66 void deregisterUserMonitor (UserMonitor userMonitor);
67
68 /** Deregister the montor for the given user */
69 void deregisterUserMonitor (String userName);
70
71 /** Get the user monitor for the given user name. */
72 UserMonitor getUserMonitor(String userName);
73
74 /** Get the user monitor for the session user */
75 UserMonitor getUserMonitor(Session session);
76
77 /** Get all the user monitors. */
78 Collection<UserMonitor> getUserMonitors();
61}79}
6280
=== modified file 'src/main/java/com/akiban/server/service/monitor/MonitorServiceImpl.java'
--- src/main/java/com/akiban/server/service/monitor/MonitorServiceImpl.java 2013-04-23 22:45:16 +0000
+++ src/main/java/com/akiban/server/service/monitor/MonitorServiceImpl.java 2013-04-26 00:32:25 +0000
@@ -62,6 +62,8 @@
62 private BufferedWriter queryOut;62 private BufferedWriter queryOut;
6363
64 private long execTimeThreshold;64 private long execTimeThreshold;
65
66 private Map<String, UserMonitor> users;
6567
66 @Inject68 @Inject
67 public MonitorServiceImpl(ConfigurationService config) {69 public MonitorServiceImpl(ConfigurationService config) {
@@ -76,6 +78,7 @@
7678
77 sessionAllocator = new AtomicInteger();79 sessionAllocator = new AtomicInteger();
78 sessions = new ConcurrentHashMap<>();80 sessions = new ConcurrentHashMap<>();
81 users = new ConcurrentHashMap<>();
7982
80 String enableLog = config.getProperty(QUERY_LOG_PROPERTY);83 String enableLog = config.getProperty(QUERY_LOG_PROPERTY);
81 this.queryLogEnabled = new AtomicBoolean(Boolean.parseBoolean(enableLog));84 this.queryLogEnabled = new AtomicBoolean(Boolean.parseBoolean(enableLog));
@@ -310,5 +313,42 @@
310 logger.debug("Query log file ready for writing.");313 logger.debug("Query log file ready for writing.");
311 return true;314 return true;
312 }315 }
313316
317 /** Register the given User monitor. */
318 @Override
319 public void registerUserMonitor (UserMonitor userMonitor) {
320 UserMonitor monitor = users.put(userMonitor.getUserName(), userMonitor);
321 assert (monitor == null || monitor == userMonitor);
322 }
323
324 /** Deregister the monitor for the given user */
325 @Override
326 public void deregisterUserMonitor (String userName) {
327 users.remove(userName);
328 }
329
330 /** Deregister the given user monitor. */
331 @Override
332 public void deregisterUserMonitor (UserMonitor userMonitor) {
333 UserMonitor monitor = users.remove(userMonitor.getUserName());
334 assert (monitor== null || monitor == userMonitor);
335 }
336
337 /** Get the user monitor for the given user name. */
338 @Override
339 public UserMonitor getUserMonitor(String userName) {
340 return users.get(userName);
341 }
342
343 /** Get the user monitor for the session user */
344 @Override
345 public UserMonitor getUserMonitor(Session session) {
346 return session.get(SESSION_KEY).getUserMonitor();
347 }
348
349 /** Get all the user monitors. */
350 @Override
351 public Collection<UserMonitor> getUserMonitors() {
352 return users.values();
353 }
314}354}
315355
=== modified file 'src/main/java/com/akiban/server/service/monitor/SessionMonitor.java'
--- src/main/java/com/akiban/server/service/monitor/SessionMonitor.java 2013-03-22 20:05:57 +0000
+++ src/main/java/com/akiban/server/service/monitor/SessionMonitor.java 2013-04-26 00:32:25 +0000
@@ -76,4 +76,7 @@
7676
77 /** Get any prepared statements. */77 /** Get any prepared statements. */
78 List<PreparedStatementMonitor> getPreparedStatements();78 List<PreparedStatementMonitor> getPreparedStatements();
79
80 /** Get the user monitor for this session */
81 UserMonitor getUserMonitor();
79}82}
8083
=== modified file 'src/main/java/com/akiban/server/service/monitor/SessionMonitorBase.java'
--- src/main/java/com/akiban/server/service/monitor/SessionMonitorBase.java 2013-03-22 20:05:57 +0000
+++ src/main/java/com/akiban/server/service/monitor/SessionMonitorBase.java 2013-04-26 00:32:25 +0000
@@ -32,6 +32,7 @@
32 private long currentStatementEndTime = -1;32 private long currentStatementEndTime = -1;
33 private int rowsProcessed = 0;33 private int rowsProcessed = 0;
34 private int statementCount = 0;34 private int statementCount = 0;
35 private UserMonitor user = null;
3536
36 protected SessionMonitorBase(int sessionID) {37 protected SessionMonitorBase(int sessionID) {
37 this.sessionID = sessionID;38 this.sessionID = sessionID;
@@ -65,6 +66,9 @@
65 public void endStatement(int rowsProcessed) {66 public void endStatement(int rowsProcessed) {
66 currentStatementEndTime = System.currentTimeMillis();67 currentStatementEndTime = System.currentTimeMillis();
67 this.rowsProcessed = rowsProcessed;68 this.rowsProcessed = rowsProcessed;
69 if (user != null) {
70 user.statementRun();
71 }
68 }72 }
6973
70 // Caller can sequence all stages and avoid any gaps at the cost of more complicated74 // Caller can sequence all stages and avoid any gaps at the cost of more complicated
@@ -167,5 +171,13 @@
167 public List<PreparedStatementMonitor> getPreparedStatements() {171 public List<PreparedStatementMonitor> getPreparedStatements() {
168 return Collections.emptyList();172 return Collections.emptyList();
169 }173 }
174
175 public void setUserMonitor(UserMonitor monitor) {
176 this.user = monitor;
177 }
178
179 public UserMonitor getUserMonitor() {
180 return this.user;
181 }
170182
171}183}
172184
=== added file 'src/main/java/com/akiban/server/service/monitor/UserMonitor.java'
--- src/main/java/com/akiban/server/service/monitor/UserMonitor.java 1970-01-01 00:00:00 +0000
+++ src/main/java/com/akiban/server/service/monitor/UserMonitor.java 2013-04-26 00:32:25 +0000
@@ -0,0 +1,32 @@
1/**
2 * Copyright (C) 2009-2013 Akiban Technologies, Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17package com.akiban.server.service.monitor;
18
19public interface UserMonitor {
20
21 /** User name of the user being monitored */
22 String getUserName();
23
24 /** The number of queries executed. */
25 long getStatementCount();
26
27 /** Get total time in nanoseconds not spent idle. */
28 long getNonIdleTimeNanos();
29
30 /** Flag a new statment has been processed */
31 void statementRun();
32}
033
=== modified file 'src/main/java/com/akiban/server/service/security/SecurityServiceImpl.java'
--- src/main/java/com/akiban/server/service/security/SecurityServiceImpl.java 2013-04-23 22:45:16 +0000
+++ src/main/java/com/akiban/server/service/security/SecurityServiceImpl.java 2013-04-26 00:32:25 +0000
@@ -27,6 +27,8 @@
27import com.akiban.server.error.SecurityException;27import com.akiban.server.error.SecurityException;
28import com.akiban.server.service.Service;28import com.akiban.server.service.Service;
29import com.akiban.server.service.config.ConfigurationService;29import com.akiban.server.service.config.ConfigurationService;
30import com.akiban.server.service.monitor.MonitorService;
31import com.akiban.server.service.monitor.UserMonitor;
30import com.akiban.server.service.session.Session;32import com.akiban.server.service.session.Session;
31import com.akiban.server.store.SchemaManager;33import com.akiban.server.store.SchemaManager;
32import com.akiban.sql.server.ServerCallContextStack;34import com.akiban.sql.server.ServerCallContextStack;
@@ -81,6 +83,7 @@
8183
82 private final ConfigurationService configService;84 private final ConfigurationService configService;
83 private final SchemaManager schemaManager;85 private final SchemaManager schemaManager;
86 private final MonitorService monitor;
8487
85 private boolean restrictUserSchema;88 private boolean restrictUserSchema;
8689
@@ -88,9 +91,11 @@
8891
89 @Inject92 @Inject
90 public SecurityServiceImpl(ConfigurationService configService,93 public SecurityServiceImpl(ConfigurationService configService,
91 SchemaManager schemaManager) {94 SchemaManager schemaManager,
95 MonitorService monitor) {
92 this.configService = configService;96 this.configService = configService;
93 this.schemaManager = schemaManager;97 this.schemaManager = schemaManager;
98 this.monitor = monitor;
94 }99 }
95100
96 // Connections are not thread safe, and prepared statements remember a Session,101 // Connections are not thread safe, and prepared statements remember a Session,
@@ -273,6 +278,7 @@
273 throw new SecurityException("Failed to delete user");278 throw new SecurityException("Failed to delete user");
274 }279 }
275 conn.commit();280 conn.commit();
281 monitor.deregisterUserMonitor(name);
276 }282 }
277 catch (SQLException ex) {283 catch (SQLException ex) {
278 throw new SecurityException("Error deleting user", ex);284 throw new SecurityException("Error deleting user", ex);
@@ -336,6 +342,9 @@
336 if (session != null) {342 if (session != null) {
337 session.put(SESSION_KEY, user);343 session.put(SESSION_KEY, user);
338 }344 }
345 if (monitor.getUserMonitor(user.getName()) == null) {
346 monitor.registerUserMonitor(new UserMonitorImpl(user.getName()));
347 }
339 return user;348 return user;
340 }349 }
341350
@@ -367,6 +376,9 @@
367 if (session != null) {376 if (session != null) {
368 session.put(SESSION_KEY, user);377 session.put(SESSION_KEY, user);
369 }378 }
379 if (monitor.getUserMonitor(user.getName()) == null) {
380 monitor.registerUserMonitor(new UserMonitorImpl(user.getName()));
381 }
370 return user;382 return user;
371 }383 }
372384
373385
=== added file 'src/main/java/com/akiban/server/service/security/UserMonitorImpl.java'
--- src/main/java/com/akiban/server/service/security/UserMonitorImpl.java 1970-01-01 00:00:00 +0000
+++ src/main/java/com/akiban/server/service/security/UserMonitorImpl.java 2013-04-26 00:32:25 +0000
@@ -0,0 +1,51 @@
1/**
2 * Copyright (C) 2009-2013 Akiban Technologies, Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17package com.akiban.server.service.security;
18
19import java.util.concurrent.atomic.AtomicLong;
20
21import com.akiban.server.service.monitor.UserMonitor;
22
23public class UserMonitorImpl implements UserMonitor {
24 private final String userName;
25 protected final AtomicLong count = new AtomicLong();
26
27 public UserMonitorImpl (String name) {
28 this.userName = name;
29 }
30 @Override
31 public String getUserName() {
32 return userName;
33 }
34
35 @Override
36 public long getStatementCount() {
37 return count.get();
38 }
39
40 @Override
41 public void statementRun() {
42 count.incrementAndGet();
43 }
44
45 @Override
46 public long getNonIdleTimeNanos() {
47 // TODO Auto-generated method stub
48 return 0;
49 }
50
51}
052
=== modified file 'src/main/java/com/akiban/sql/pg/PostgresServerConnection.java'
--- src/main/java/com/akiban/sql/pg/PostgresServerConnection.java 2013-04-23 22:45:16 +0000
+++ src/main/java/com/akiban/sql/pg/PostgresServerConnection.java 2013-04-26 00:32:25 +0000
@@ -522,6 +522,7 @@
522 }522 }
523 logger.debug("Login {}", (principal != null) ? principal : user);523 logger.debug("Login {}", (principal != null) ? principal : user);
524 authenticationOkay(user);524 authenticationOkay(user);
525 sessionMonitor.setUserMonitor(reqs.monitor().getUserMonitor(user));
525 }526 }
526 527
527 protected void authenticationOkay(String user) throws IOException {528 protected void authenticationOkay(String user) throws IOException {
528529
=== modified file 'src/test/java/com/akiban/server/service/is/SchemaTableServiceIT.java'
--- src/test/java/com/akiban/server/service/is/SchemaTableServiceIT.java 2013-03-22 20:05:57 +0000
+++ src/test/java/com/akiban/server/service/is/SchemaTableServiceIT.java 2013-04-26 00:32:25 +0000
@@ -98,7 +98,7 @@
98 98
99 @Test99 @Test
100 public void serverExamine() {100 public void serverExamine() {
101 assertEquals ("Table count", 10, ServerSchemaTablesServiceImpl.createTablesToRegister().getUserTables().size());101 assertEquals ("Table count", 11, ServerSchemaTablesServiceImpl.createTablesToRegister().getUserTables().size());
102 assertNotNull (ais.getUserTable(ServerSchemaTablesServiceImpl.ERROR_CODES));102 assertNotNull (ais.getUserTable(ServerSchemaTablesServiceImpl.ERROR_CODES));
103 assertNotNull (ais.getUserTable(ServerSchemaTablesServiceImpl.SERVER_INSTANCE_SUMMARY));103 assertNotNull (ais.getUserTable(ServerSchemaTablesServiceImpl.SERVER_INSTANCE_SUMMARY));
104 assertNotNull (ais.getUserTable(ServerSchemaTablesServiceImpl.SERVER_SERVERS));104 assertNotNull (ais.getUserTable(ServerSchemaTablesServiceImpl.SERVER_SERVERS));
@@ -109,5 +109,6 @@
109 assertNotNull (ais.getUserTable(ServerSchemaTablesServiceImpl.SERVER_TAPS));109 assertNotNull (ais.getUserTable(ServerSchemaTablesServiceImpl.SERVER_TAPS));
110 assertNotNull (ais.getUserTable(ServerSchemaTablesServiceImpl.SERVER_PREPARED_STATEMENTS));110 assertNotNull (ais.getUserTable(ServerSchemaTablesServiceImpl.SERVER_PREPARED_STATEMENTS));
111 assertNotNull (ais.getUserTable(ServerSchemaTablesServiceImpl.SERVER_CURSORS));111 assertNotNull (ais.getUserTable(ServerSchemaTablesServiceImpl.SERVER_CURSORS));
112 assertNotNull (ais.getUserTable(ServerSchemaTablesServiceImpl.SERVER_USERS));
112 }113 }
113}114}

Subscribers

People subscribed via source and target branches