LCOV - code coverage report
Current view: top level - sshd - SshScope.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 82 85 96.5 %
Date: 2022-11-19 15:00:39 Functions: 31 33 93.9 %

          Line data    Source code
       1             : // Copyright (C) 2009 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.sshd;
      16             : 
      17             : import com.google.gerrit.metrics.proc.ThreadMXBeanFactory;
      18             : import com.google.gerrit.metrics.proc.ThreadMXBeanInterface;
      19             : import com.google.gerrit.server.CurrentUser;
      20             : import com.google.gerrit.server.IdentifiedUser;
      21             : import com.google.gerrit.server.RequestCleanup;
      22             : import com.google.gerrit.server.util.RequestContext;
      23             : import com.google.gerrit.server.util.ThreadLocalRequestContext;
      24             : import com.google.gerrit.server.util.ThreadLocalRequestScopePropagator;
      25             : import com.google.gerrit.server.util.time.TimeUtil;
      26             : import com.google.inject.Inject;
      27             : import com.google.inject.Key;
      28             : import com.google.inject.OutOfScopeException;
      29             : import com.google.inject.Provider;
      30             : import com.google.inject.Scope;
      31             : import java.util.HashMap;
      32             : import java.util.Map;
      33             : 
      34             : /** Guice scopes for state during an SSH connection. */
      35             : public class SshScope {
      36          17 :   private static final Key<RequestCleanup> RC_KEY = Key.get(RequestCleanup.class);
      37          17 :   private static final ThreadMXBeanInterface threadMxBean = ThreadMXBeanFactory.create();
      38             : 
      39             :   class Context implements RequestContext {
      40             : 
      41          17 :     private final RequestCleanup cleanup = new RequestCleanup();
      42          17 :     private final Map<Key<?>, Object> map = new HashMap<>();
      43             :     private final SshSession session;
      44             :     private final String commandLine;
      45             : 
      46             :     private final long created;
      47             :     private volatile long started;
      48             :     private volatile long finished;
      49             :     private volatile long startedTotalCpu;
      50             :     private volatile long finishedTotalCpu;
      51             :     private volatile long startedUserCpu;
      52             :     private volatile long finishedUserCpu;
      53             :     private volatile long startedMemory;
      54             :     private volatile long finishedMemory;
      55             : 
      56             :     private IdentifiedUser identifiedUser;
      57             : 
      58          17 :     private Context(SshSession s, String c, long at) {
      59          17 :       session = s;
      60          17 :       commandLine = c;
      61          17 :       created = started = finished = at;
      62          17 :       startedTotalCpu = threadMxBean.getCurrentThreadCpuTime();
      63          17 :       startedUserCpu = threadMxBean.getCurrentThreadUserTime();
      64          17 :       startedMemory = threadMxBean.getCurrentThreadAllocatedBytes();
      65          17 :       map.put(RC_KEY, cleanup);
      66          17 :     }
      67             : 
      68             :     private Context(Context p, SshSession s, String c) {
      69           6 :       this(s, c, p.created);
      70           6 :       started = p.started;
      71           6 :       finished = p.finished;
      72           6 :       startedTotalCpu = p.startedTotalCpu;
      73           6 :       finishedTotalCpu = p.finishedTotalCpu;
      74           6 :       startedUserCpu = p.startedUserCpu;
      75           6 :       finishedUserCpu = p.finishedUserCpu;
      76           6 :       startedMemory = p.startedMemory;
      77           6 :       finishedMemory = p.finishedMemory;
      78           6 :     }
      79             : 
      80             :     void start() {
      81           9 :       started = TimeUtil.nowMs();
      82           9 :       startedTotalCpu = threadMxBean.getCurrentThreadCpuTime();
      83           9 :       startedUserCpu = threadMxBean.getCurrentThreadUserTime();
      84           9 :       startedMemory = threadMxBean.getCurrentThreadAllocatedBytes();
      85           9 :     }
      86             : 
      87             :     void finish() {
      88           9 :       finished = TimeUtil.nowMs();
      89           9 :       finishedTotalCpu = threadMxBean.getCurrentThreadCpuTime();
      90           9 :       finishedUserCpu = threadMxBean.getCurrentThreadUserTime();
      91           9 :       finishedMemory = threadMxBean.getCurrentThreadAllocatedBytes();
      92           9 :     }
      93             : 
      94             :     public long getCreated() {
      95          17 :       return created;
      96             :     }
      97             : 
      98             :     public long getWait() {
      99           9 :       return started - created;
     100             :     }
     101             : 
     102             :     public long getExec() {
     103           9 :       return finished - started;
     104             :     }
     105             : 
     106             :     public long getTotalCpu() {
     107           9 :       return (finishedTotalCpu - startedTotalCpu) / 1_000_000;
     108             :     }
     109             : 
     110             :     public long getUserCpu() {
     111           9 :       return (finishedUserCpu - startedUserCpu) / 1_000_000;
     112             :     }
     113             : 
     114             :     public long getAllocatedMemory() {
     115           9 :       return finishedMemory - startedMemory;
     116             :     }
     117             : 
     118             :     String getCommandLine() {
     119           5 :       return commandLine;
     120             :     }
     121             : 
     122             :     SshSession getSession() {
     123          17 :       return session;
     124             :     }
     125             : 
     126             :     @Override
     127             :     public CurrentUser getUser() {
     128          10 :       CurrentUser user = session.getUser();
     129          10 :       if (user != null && user.isIdentifiedUser()) {
     130          10 :         if (identifiedUser == null) {
     131          10 :           identifiedUser = userFactory.create(user.getAccountId());
     132          10 :           identifiedUser.setAccessPath(user.getAccessPath());
     133             :         }
     134          10 :         return identifiedUser;
     135             :       }
     136           1 :       return user;
     137             :     }
     138             : 
     139             :     synchronized <T> T get(Key<T> key, Provider<T> creator) {
     140             :       @SuppressWarnings("unchecked")
     141          17 :       T t = (T) map.get(key);
     142          17 :       if (t == null) {
     143          17 :         t = creator.get();
     144          17 :         map.put(key, t);
     145             :       }
     146          17 :       return t;
     147             :     }
     148             : 
     149             :     synchronized Context subContext(SshSession newSession, String newCommandLine) {
     150           6 :       Context ctx = new Context(this, newSession, newCommandLine);
     151           6 :       ctx.cleanup.add(cleanup);
     152           6 :       return ctx;
     153             :     }
     154             :   }
     155             : 
     156          17 :   static class ContextProvider implements Provider<Context> {
     157             :     @Override
     158             :     public Context get() {
     159          17 :       return requireContext();
     160             :     }
     161             :   }
     162             : 
     163          17 :   public static class SshSessionProvider implements Provider<SshSession> {
     164             :     @Override
     165             :     public SshSession get() {
     166          17 :       return requireContext().getSession();
     167             :     }
     168             :   }
     169             : 
     170             :   static class Propagator extends ThreadLocalRequestScopePropagator<Context> {
     171             :     private final SshScope sshScope;
     172             : 
     173             :     @Inject
     174             :     Propagator(SshScope sshScope, ThreadLocalRequestContext local) {
     175           2 :       super(REQUEST, current, local);
     176           2 :       this.sshScope = sshScope;
     177           2 :     }
     178             : 
     179             :     @Override
     180             :     protected Context continuingContext(Context ctx) {
     181             :       // The cleanup is not chained, since the RequestScopePropagator executors
     182             :       // the Context's cleanup when finished executing.
     183           2 :       return sshScope.newContinuingContext(ctx);
     184             :     }
     185             :   }
     186             : 
     187          17 :   private static final ThreadLocal<Context> current = new ThreadLocal<>();
     188             : 
     189             :   private static Context requireContext() {
     190          17 :     final Context ctx = current.get();
     191          17 :     if (ctx == null) {
     192           0 :       throw new OutOfScopeException("Not in command/request");
     193             :     }
     194          17 :     return ctx;
     195             :   }
     196             : 
     197             :   private final ThreadLocalRequestContext local;
     198             :   private final IdentifiedUser.RequestFactory userFactory;
     199             : 
     200             :   @Inject
     201          17 :   SshScope(ThreadLocalRequestContext local, IdentifiedUser.RequestFactory userFactory) {
     202          17 :     this.local = local;
     203          17 :     this.userFactory = userFactory;
     204          17 :   }
     205             : 
     206             :   Context newContext(SshSession s, String cmd) {
     207          17 :     return new Context(s, cmd, TimeUtil.nowMs());
     208             :   }
     209             : 
     210             :   private Context newContinuingContext(Context ctx) {
     211           2 :     return new Context(ctx, ctx.getSession(), ctx.getCommandLine());
     212             :   }
     213             : 
     214             :   Context set(Context ctx) {
     215          17 :     Context old = current.get();
     216          17 :     current.set(ctx);
     217          17 :     local.setContext(ctx);
     218          17 :     return old;
     219             :   }
     220             : 
     221             :   /** Returns exactly one instance per command executed. */
     222          17 :   public static final Scope REQUEST =
     223          17 :       new Scope() {
     224             :         @Override
     225             :         public <T> Provider<T> scope(Key<T> key, Provider<T> creator) {
     226          17 :           return new Provider<>() {
     227             :             @Override
     228             :             public T get() {
     229          17 :               return requireContext().get(key, creator);
     230             :             }
     231             : 
     232             :             @Override
     233             :             public String toString() {
     234           0 :               return String.format("%s[%s]", creator, REQUEST);
     235             :             }
     236             :           };
     237             :         }
     238             : 
     239             :         @Override
     240             :         public String toString() {
     241           0 :           return "SshScopes.REQUEST";
     242             :         }
     243             :       };
     244             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750