Changeset 2571


Ignore:
Timestamp:
Aug 13, 2014, 11:31:28 AM (7 years ago)
Author:
Nicklas Nordborg
Message:

References #617: Re-use server connections within a transaction

Implemented for the SFTP protocol. The action factory initializes the cache if a DbControl is provided and also register an action to clean up when the transaction is ended, Then, the connection manager saves connections in the cache which are re-used in subsequent requests to the same host.

Location:
extensions/net.sf.basedb.xfiles/trunk/src/net/sf/basedb/xfiles
Files:
3 added
3 edited

Legend:

Unmodified
Added
Removed
  • extensions/net.sf.basedb.xfiles/trunk/src/net/sf/basedb/xfiles/MultiCloseable.java

    r2518 r2571  
    33import java.io.Closeable;
    44import java.io.IOException;
     5import java.util.Collection;
    56
    67/**
     
    2122  public static void closeAll(Closeable... toClose)
    2223  {
     24    if (toClose == null) return;
     25    for (Closeable c : toClose)
     26    {
     27      close(c);
     28    }
     29  }
     30 
     31  /**
     32    Utility method for closing several closeable without throwing an exception.
     33    @param toClose A collection with Closeable objects
     34    @since 1.1
     35  */
     36  public static void closeAll(Collection<? extends Closeable> toClose)
     37  {
     38    if (toClose == null) return;
    2339    for (Closeable c : toClose)
    2440    {
     
    4460 
    4561  private final Closeable[] toClose;
     62  private boolean isClosed;
    4663 
    4764  public MultiCloseable(Closeable... toClose)
     
    5370  public void close()
    5471  {
    55     closeAll(toClose);
     72    if (!isClosed) closeAll(toClose);
     73    isClosed = true;
    5674  }
    5775
  • extensions/net.sf.basedb.xfiles/trunk/src/net/sf/basedb/xfiles/sftp/SftpConnectionManager.java

    r2522 r2571  
    2727import java.net.URI;
    2828import java.util.Date;
    29 import java.util.EnumSet;
    30 
    31 import net.schmizz.sshj.SSHClient;
     29
    3230import net.schmizz.sshj.sftp.FileAttributes;
    33 import net.schmizz.sshj.sftp.OpenMode;
    3431import net.schmizz.sshj.sftp.RemoteFile;
    35 import net.schmizz.sshj.sftp.SFTPClient;
    3632import net.sf.basedb.util.uri.CloseResourceInputStream;
    3733import net.sf.basedb.util.uri.ConnectionParameters;
    3834import net.sf.basedb.util.uri.ResumableConnectionManager;
    3935import net.sf.basedb.util.uri.UriMetadata;
     36import net.sf.basedb.xfiles.ConnectionCache;
    4037import net.sf.basedb.xfiles.MultiCloseable;
    4138import net.sf.basedb.xfiles.XFiles;
     
    5451{
    5552
     53  static ConnectionCache<SSHClientWrapper> CONNECTION_CACHE = new ConnectionCache<SSHClientWrapper>(new SftpConnectionParametersComparator());
     54 
    5655  private final URI uri;
    5756  private final ConnectionParameters parameters;
     
    8786    URI uri = getURI();
    8887    InputStream stream = null;
    89     SSHClient ssh = null;
    90     SFTPClient sftp = null;
     88    SSHClientWrapper wrapper = null;
    9189    RemoteFile remote = null;
    9290    try
    9391    {
    94       ssh = connect(uri, parameters);
    95       sftp = ssh.newSFTPClient();
    96       remote = sftp.open(uri.getPath(), EnumSet.of(OpenMode.READ));
     92      wrapper = connect(uri, parameters);
     93      remote = wrapper.openUri(uri);
    9794      // Constructor is only accepting an 'int' parameter so we need to use skip() instead
    9895      InputStream tmp = remote.new RemoteFileInputStream();
     
    10097      stream = new CloseResourceInputStream(
    10198        new BufferedInputStream(tmp, XFiles.DEFAULT_BUFFER_SIZE),
    102         new MultiCloseable(remote, sftp, ssh));
     99        new MultiCloseable(remote, wrapper));
    103100    }
    104101    finally
    105102    {
    106       // If no stream has been created we close everything immediately
    107       if (stream == null)
    108       {
    109         MultiCloseable.closeAll(remote, sftp, ssh);
     103      // If no stream has been created we close the remote immediately
     104      if (stream == null && remote != null)
     105      {
     106        MultiCloseable.closeAll(remote, wrapper);
    110107      }
    111108    }
     
    122119      URI uri = getURI();
    123120      metadata = new UriMetadata(uri);
    124      
    125121      // Connect to the remote server and load file information
    126       SSHClient ssh = null;
    127       SFTPClient sftp = null;
     122      SSHClientWrapper wrapper = null;
    128123      RemoteFile remote = null;
    129124      try
    130125      {
    131         ssh = connect(uri, parameters);
    132         sftp = ssh.newSFTPClient();
    133         remote = sftp.open(uri.getPath(), EnumSet.of(OpenMode.READ));
     126        wrapper = connect(uri, parameters);
     127        remote = wrapper.openUri(uri);
    134128        // Load the metadata
    135129        loadMetadata(metadata, remote);
     
    138132      {
    139133        // Clean up
    140         MultiCloseable.closeAll(remote, sftp, ssh);
     134        MultiCloseable.closeAll(remote, wrapper);
    141135      }
    142136    }
     
    146140 
    147141 
    148   public SSHClient connect(URI uri, ConnectionParameters parameters)
    149     throws IOException
    150   {
    151     SSHClient ssh = null;
    152     boolean connected = false;
     142  public SSHClientWrapper connect(URI uri, ConnectionParameters parameters)
     143    throws IOException
     144  {
     145    SSHClientWrapper wrapper = CONNECTION_CACHE.getClient(parameters);
     146    boolean connected = wrapper != null && wrapper.ssh.isConnected();
     147   
    153148    try
    154149    {
    155       ssh = new SSHClient();
    156       if (parameters == null)
    157       {
    158         throw new IOException("No file server specified for " + uri);
    159       }
    160       else if (parameters.getSshFingerprint() == null)
    161       {
    162         throw new IOException("No SSH fingerprint in connection parameters for "+ uri);
    163       }
    164       else if (parameters.getUsername() == null)
    165       {
    166         throw new IOException("No username in connection parameters for "+ uri);
    167       }
    168       else if (parameters.getPassword() == null)
    169       {
    170         throw new IOException("No password in connection parameters for "+ uri);
    171       }
    172       ssh.addHostKeyVerifier(parameters.getSshFingerprint());
    173       ssh.setConnectTimeout(2000);
    174       int port = uri.getPort();
    175       if (port == -1) port = XFiles.DEFAULT_SSH_PORT;
    176       ssh.connect(uri.getHost(), port);
    177       ssh.authPassword(parameters.getUsername(), parameters.getPassword());
    178       connected = true;
     150      if (!connected)
     151      {
     152        if (parameters == null)
     153        {
     154          throw new IOException("No file server specified for " + uri);
     155        }
     156        else if (parameters.getSshFingerprint() == null)
     157        {
     158          throw new IOException("No SSH fingerprint in connection parameters for "+ uri);
     159        }
     160        else if (parameters.getUsername() == null)
     161        {
     162          throw new IOException("No username in connection parameters for "+ uri);
     163        }
     164        else if (parameters.getPassword() == null)
     165        {
     166          throw new IOException("No password in connection parameters for "+ uri);
     167        }
     168       
     169        wrapper = new SSHClientWrapper(uri, parameters);
     170        connected = true;
     171      }
    179172    }
    180173    finally
    181174    {
    182       if (!connected) MultiCloseable.close(ssh);
    183     }
    184     return ssh;
     175      if (!connected)
     176      {
     177         MultiCloseable.close(wrapper);
     178         wrapper = null;
     179      }
     180    }
     181    return wrapper;
    185182  }
    186183 
  • extensions/net.sf.basedb.xfiles/trunk/src/net/sf/basedb/xfiles/sftp/SftpConnectionManagerActionFactory.java

    r2518 r2571  
    2222package net.sf.basedb.xfiles.sftp;
    2323
     24import net.sf.basedb.core.DbControl;
    2425import net.sf.basedb.core.plugin.About;
    2526import net.sf.basedb.util.extensions.ActionFactory;
     
    6667      initFactory(context);
    6768    }
     69    DbControl dc = context.getClientContext().getDbControl();
     70    if (dc != null && !dc.isClosed())
     71    {
     72      // Initialize a connection cache hooked up to the current transaction
     73      SftpConnectionManager.CONNECTION_CACHE.init(dc);
     74    }
    6875    return new ConnectionManagerFactory[] { factory };
    6976  }
Note: See TracChangeset for help on using the changeset viewer.