CORAL Component documentation: ConnectionService

Giacomo Govi

CERN

March 2006


1. Introduction

1.1. Purpose of the component

The ConnectionService package is a plugin module providing connection management, connection pooling, connection retry and replica failover policies.

This module provides implementation of some user-level interfaces of the RelationalAccess package: IConnectionService, IConnectionServiceConfiguration, ISessionProxy, ISessionProperties, IWebCacheControl.

1.2. Repository of the component

:pserver:anonymoys@coral.cvs.cern.ch:/cvs/coral/coral/ConnectionService

2. ConnectionService Semantics

2.1. Architecture and object hierarchy

The ConnectionService API is based on two main: the IConnectionService class, which acts as a central service to open the session on the database backends, and the ISessionProxy, providing proxy objects to the physical database sessions. With the ConnectionService API, the user can configure most of the parameters required for the setting up of specific service implementation (authentication, database back-end instantiation, connection string resolution, monitoring) and specific policies for the handling of connection pooling, retries and failover. The configuration is accessible on a specific interface, the IConnectionServiceConfiguration. More specific parameter access are provided by the ISessionProperties (for a few session-specific quantities), the IWebCacheControl (for setting up of Web-cache related policies), the IMonitoringReporter (for the access to monitoring data).

2.2. Service connection via session proxy

The ISessionProxy provides access to the database schema and the transaction control.

To obtain ISessionProxy object, one must provide a connection string specifying the service to be accessed. The string can explicitly describe a physical database service (when formed according to the specific rules supported by the CORAL relational service). Alternatively, the string can be an user-defined label, mapped logically to one or more explicit (physical) connection strings (replicas). The mapping between logical connection strings and their replicas is maintained and handled through the ILookupService interface, with its concrete implementations.

2.3. Re-connection

The user can use the ISessionProxy interface in a similar way as a physical ISession object (see example below). The underlying connection is handled internally and is guaranteed to be open for the lifetime of the ISessionProxy instance. In order to maximize the reliability, an automatic recover policy based on reconnect and failover is applied in case of failure of the connection.

2.4. Connection pooling

One of the main task of the ConnectionService is the efficient connection management. The aim is to allow the re-use of already opened connections, in order to minimize on the database server side the CPU consumption required by the creation of new connection. For this pourpose, the connections are kept in two pools:

  • the ACTIVE pool, hosting the connection currently in use by some client of the Connection Service instance. As soon as a new session is opened, the corresponding connection will populate the ACTIVE pool.

  • the IDLE pool, hosting the connection released by all of the clients of the Connection Service instance. As soon as a session is dropped by its user, the corresponding connection will populate the IDLE pool.

The connectiond stored in the IDLE pool can be of course re-used to open new session, by any database user. For Read-Only session, also active connections (associated to sessions already open) can be shared among more proxy sessions, if the request comes from the same database user. At each request for a new Session, first the idle pool is searched. In case no idle connection is found matching the requested connection string, then the active pool is searched. When also in this case no suitable connection is found, a new connection is created from scratch. The session sharing (enabled by default) can be disabled esplicitly in the IConnectionServiceConfiguration.

After a specific timeout the connections stored in the IDLE Pool will be closed. The timeout can be configured by method 'setConnectionTimeOut' in class IConnectionServiceConfiguration. The cleanup of timed out session is internally triggered at each connection and delete pool operation. However, the purging can be forced explicitly at any moment, by calling the method IConnectionService::purgeTimedOutConnection.

2.5. Authentication

The authentication is always implicit. The user cannot specify explicitly the database service username and password in the connection method call. The two parameters are retrieved "internally" by the authentication service, where they are stored in entries mapped to the corresponding connection string. Such feature implies that only a single pair user/password can be associated to a given connection string.

2.6. Connection Retry

The creation of a new connection, when requested, may fail for a various type of reasons. For some categories of failure, a recovey can be attempted by simply iterating the connection request. Such policy applies to some specific failure, like the ones due to a network glitch, the overloading of the service, or to a short service unavailability. The connection service can distinguish such condition, and apply the connection re-try according to the user configuration. However, for other failure types, like for wrong authentication parameters, the retry will be not applied. The connection is attempted with a specific period of time between each trials (retry period), during a well defined total time (retry timeout) on the given database service. In case of insuccess, the given connection string is registered on an internal list of excluded replicas, for a specific duration of time (exclusion time out). After this timeout, the connection is re-admitted in the replica list. The three parameters retry period, retry timeout and exclusion time can be modified at run time by the user, via the IConnectionServiceConfiguration interface.

2.7. Replica management and failover

The Connection Service delegates the resolution of the connection string to an other service, the database lookup service, implementing the ILookupService interface. The lookup service provides a list of possible physical replicas for logical database/service name, with the associated authentication mechanisms and access mode.

For read-only access, the user can define a set of equivalent database service. In this case, more than one physical connection string can be used for the connection and a failover mechanism can be applied. The connection string associated to the replicas are used in the order they are stored, attempting the connection to the first entry, and moving to the next in case of failure. A similar mechanism applies to the re-connect policy, in case an established connection fails during its lifetime.

3. Examples

3.1. Connection service instantiation

seal::PluginManager* pm = seal::PluginManager::get(); pm->initialise(); seal::Handle<seal::ComponentLoader> loader = new seal::ComponentLoader( context ); loader->load( "CORAL/Services/ConnectionService" ); std::vector< seal::IHandle<coral::IConnectionService> > v_svc; context->query( v_svc ); if ( v_svc.empty() ) { throw std::runtime_error( "Could not locate the connection service" ); } seal::IHandle<coral::IConnectionService> theConnectionService = v_svc.front();

3.2. Connection service initialization

IConnectionServiceConfiguration& conf = theConnectionService.configuration(); // disable the failover to the next replica conf.disableReplicaFailOver(); // disable the connection sharing for read only replica conf.disableConnectionSharing(); // disbale the use of update-capable idle connection for read only session conf.disableReadOnlySessionOnUpdateConnections(); // set the connection retrial period conf.setConnectionRetrialPeriod(10); // set the connection retrial time out conf.setConnectionRetrialTimeOut(60); // set the timeout for idle connection conf.setConnectionTimeOut(120); // set the timeout in the exclusion list conf.setMissingConnectionExclusionTime(3600); // set the monitoring level conf.setMonitoringLevel(monitor::Debug); // enforce the usage of myAuthentication service conf.setDefaultAuthenticationService("myplugins/MyAuthenticationService");

3.3. Access to a database service

// connect to a database described by a logical connection string try { std::string connectionString = "myDatabase"; // connect in update mode ISessionProxy* session = theConnectionService->connect( connectionString, Update ); // start an update transaction session->transaction().start(); // create a table in the nominal schema coral::TableDescription descr; descr.setName("MYTABLE"); descr.insertColumn("N_X",coral::AttributeSpecification::typeNameForType<int>()); descr.insertColumn("N_S",coral::AttributeSpecification::typeNameForType<std::string>()); session->nominalSchema().createTable( descr ); // commit changes session->transaction().commit(); // delete the session proxy (the connection will be not dropped) delete session; // reconnect in read-only mode - the same connection will be re-used session = theConnectionService->connect( connectionString, ReadOnly ); // start a read-only transaction session->transaction().start( true ); std::set<std::string> tables = session->nominalSchema().listTables(); session->transaction().commit(); delete session; for(std::set<std::string>::const_iterator iT=tables.begin(); iT!=tables.end();iT++){ std::cout << "Found table:" << *iT << std::endl; } // force clean up of timed-out connections theConnectionService->purgeConnectionPool(); } catch ( const ConnectionServiceException& exc) { std::cout << "ERROR: " << exc.what() << std::endl; }

3.4. Increasing the failover coverage

// connect to a database described by a logical connection string std::string connectionString = "myDatabase"; int maxtries = 5; ISessionProxy* session = 0; bool success = false; bool give_up = false; int itry = 0; while( !success && !give_up ){ try { itry++; session = theConnectionService->connect( connectionString, ReadOnly ); // start a read-only transaction session->transaction().start( true ); std::set<std::string> tables = session->nominalSchema().listTables(); session->transaction().commit(); delete session; session = 0; success = true; // do something... } catch (const ConnectionServiceException& exc){ give_up = true; delete session; session = 0; std::cout << "ERROR:" << exc.what() << std::endl; } catch (const SessionException& exc){ if(itry==maxtries) give_up = true; } }

4. Implementation specifics

This package consists of two main components connection service and web cache control service, providing a concrete implementation respectively for the public interfaces IConnectionService, IConnectionServiceConfiguration, ISessionProxy, and IWebCacheControl, IWebCacheInfo.

The main subcomponents of connection service are the connection replica service and the connection pool service. The connection replica service is in charged to translate a user connection request ? based on logical or physical connection string - into a list of pre-defined database connection corresponding to it, retrieved by the underlying ILookupService implementation. When a connection attempt to one of the physical replica fails for the (configurable) maximum number of times, the connection string to this replica is registered in a special list of 'unavailable' database services, where it remains for a configurable interval of time. Connection string in this list will be excluded as possible replicas.

The connection pool manages the cache of coral::ISession objects. In the pool idle connections (with no user session started on them) and active connections (with one session open on them, possibly shared among more clients of the proxy) are stored in two distinct registers. When active connection become idle ( when the user session on them is closed ) , it is automatically moved to the idle connection register. When a client requests a new ISessionProxy object, the first lookup is done against the idle connection register. If a connection matches the request (in terms of physical connection string for a given replica and access mode), a new user session is started on it and the connection is moved to the active list. If no idle connection is matching the request, the active list is looked up. According to the current policy, only READ-ONLY session can be shared among more proxy clients. Therefore, for UPDATE session the active list is never used. Both idle and active list are implemented with std::map, using uuid as unique connection identifier. Connection handling and reference management is implemented with boost::shared_ptr.

5. Related components

  • RelationalAccess, is the package where the CORAL abstract interfaces are defined.

  • CoralCommon, is the package where some developer-level interfaces and some common implementation classes are defined.

6. ConnectionService Reference

6.1. class IConnectionService

6.1.1. Members
  • ISessionProxy* connect( const std::string& connectionName, AccessMode accessMode = Update );

    Parameters:

    •  connectionName 
      : the logical or physical connection string

    •  accessMode 
      : the access mode capabilities of the connection. Possible values: ReadOnly, Update. Default: Update

    Effects: Delivers a valid session proxy object, constructed around an active connection to the requested service. The ownership of the session object is fully controlled by the user code.

    Returns: The pointer to the session proxy object, constructed by new. The ownership of the session object is fully controlled by the user code.

    Throws: When no valid connection is available, a ConnectionServiceException object is thrown by value.

  • IConnectionServiceConfiguration& configuration();

    Returns: a reference of the internal configuration parameter store. The object can be accesses in read/write mode, for changing and reading the configuration parameters.

    Throws: never throws.

  • void purgeConnectionPool() ;

    Effects: Cleans up the IDLE pool, closing and deleting the connections for which the lifetime reached the timeout. No disconnect is enforced to the other connections in IDLE pool, no action is taken for connection in the ACTIVE pool.

    Throws: never throws.

  • const IMonitoringReporter& monitoringReporter() const ;

    Returns: a reference of the internal monitoring reporter, which can be used for read-only access.

    Throws: never throws.

  • IWebCacheControl& webCacheControl();

    Returns: a reference of the internal object for the control of the web cache. Its usage make sense only for the Frontier back-end plug-in.

    Throws: never throws.

6.2. class IConnectionServiceConfiguration

6.2.1. Members
  • void enableReplicaFailOver();

    Effects: Enables the failing over to the next available replica in case the first provided by the ILookupService is not available. Otherwise the ConnectionService gives up.

    Postcondition: isReplicaFailoverEnabled() == true.

    Throws: never throws.

  • void disableReplicaFailOver();

    Effects: Disables the failing over to the next available replica in case the first provided by the ILookupService is not available.

    Postcondition: isReplicaFailoverEnabled() == false.

    Throws: never throws.

  • bool isReplicaFailOverEnabled();

    Returns: TRUE if the failing over to the next available replica is enabled. Default value is TRUE.

    Throws: never throws.

  • void enableConnectionSharing() ;

    Effects: Enables the sharing of the same physical connection among more read-only session proxies.

    Postcondition: isConnectionSharingEnabled() == true.

    Throws: never throws.

  • void disableConnectionSharing() ;

    Effects: Disables the sharing of the same physical connection among more read-only session proxies.

    Postcondition: isConnectionSharingEnabled() == false.

    Throws: never throws.

  • bool isConnectionSharingEnabled();

    Returns: TRUE if the connection sharing is enabled. Default value is TRUE.

    Throws: never throws.

  • void enableReadOnlySessionOnUpdateConnections() ;

    Effects: Enables the re-use of idle connections opened in update mode for read-Only sessions.

    Postcondition: isReadOnlySessionOnUpdateConnectionsEnabled == true.

    Throws: never throws.

  • void disableReadOnlySessionOnUpdateConnections() ;

    Effects: Disables the re-use of idle connections opened in update mode for read-Only sessions.

    Postcondition: isReadOnlySessionOnUpdateConnectionsEnabled == false.

    Throws: never throws.

  • bool isReadOnlySessionOnUpdateConnectionsEnabled();

    Returns: TRUE if the re-use of Update connections for Read-Only sessions is enabled . Default value is TRUE.

    Throws: never throws.

  • void setConnectionRetrialPeriod( int timeOutInSeconds ) ;

    Parameters:
    •  timeOutInSeconds 
      : the time out in seconds

    Effects: Sets the period of connection retrials on the requested service (time interval between two retrials).

    Postcondition: connectionRetrialPeriod() == timeOutInSeconds.

    Throws: never throws.

  • int connectionRetrialPeriod();

    Returns: the rate of connection retrials on the requested service (time interval between two retrials). Default value is 10 sec.

    Throws: never throws.

  • void setConnectionRetrialTimeOut( int timeOutInSeconds ) ;

    Parameters:
    •  timeOutInSeconds 
      : the time out in seconds

    Effects: Sets the time out for the connection retrials before the connection service fails over to the next available replica or gives up.

    Postcondition: connectionRetrialTimeOut() == timeOutInSeconds.

    Throws: never throws.

  • int connectionRetrialTimeOut();

    Returns: the rate of connection retrials on the requested service (time interval between two retrials). Default value is 60 sec.

    Throws: never throws.

  • void setConnectionTimeOut( int timeOutInSeconds );

    Parameters:
    •  timeOutInSeconds 
      : the time out in seconds

    Effects: Sets the time out (in seconds) for the IDLE connections.

    Postcondition: connectionTimeOut() == timeOutInSeconds.

    Throws: never throws.

  • int connectionTimeOut();

    Returns: the time out (in seconds) for the IDLE connections. Default value is 300 sec.

    Throws: never throws.

  • void setMissingConnectionExclusionTime( int timeInSeconds );

    Parameters:
    •  timeInSeconds 
      : the time in seconds

    Effects: Sets the time duration of exclusion from failover list for a connection not available.

    Postcondition: missingConnectionExclusionTime() == timeInSeconds.

    Throws: never throws.

  • int missingConnectionExclusionTime();

    Returns: the time duration of exclusion from failover list for a connection not available. Default value is 3600 sec.

    Throws: never throws.

  • void setMonitoringLevel( monitor::Level level );

    Parameters:
    •  level 
      : the monitoring level. Possible values in coral::IMontoring

    Effects: Sets the monitoring level for the new sessions.

    Postcondition: monitoringLevel() == level.

    Throws: never throws.

  • monitor::Level monitoringLevel() ;

    Returns: the current monitoring level. Default is monitor::Off.

    Throws: never throws.

  • void setDefaultAuthenticationService( const std::string serviceName );

    Parameters:
    •  serviceName 
      : the name of the service to be used.

    Effects: Sets the default authentication service to be used for the new sessions. The corresponding plug-in is loaded when necessary, and only if no other implementation of the corresponding interface is found in the context.

    Throws: never throws.

  • void setDefaultLookupService( const std::string serviceName );

    Parameters:
    •  serviceName 
      : the name of the service to be used.

    Effects: Sets the default lookup service to be used for the new sessions. The corresponding plug-in is loaded when necessary, and only if no other implementation of the corresponding interface is found in the context.

    Throws: never throws.

  • void setDefaultRelationalService( const std::string serviceName );

    Parameters:
    •  serviceName 
      : the name of the service to be used.

    Effects: Sets the default relational service to be used for the new sessions. The corresponding plug-in is loaded when necessary, and only if no other implementation of the corresponding interface is found in the context.

    Throws: never throws.

  • void setDefaultMonitoringService( const std::string serviceName );

    Parameters:
    •  serviceName 
      : the name of the service to be used.

    Effects: Sets the default monitoring service to be used for the new sessions. The corresponding plug-in is loaded when necessary, and only if no other implementation of the corresponding interface is found in the context.

    Throws: never throws.

6.3. class ISessionProxy

6.3.1. Members
  • ISessionProperties& properties();

    Returns: a reference of the internal property store, containing read-only data related to the underlying connection. Since the underlying connection is probed before the object info construction, it always contains valid data.

    Throws: ConnectionServiceException if the underlying connection becomes invalid and cannot be recovered. InvalidSessionProxyException if the associated Connection service is unavailable.

  • ISchema& nominalSchema();

    Returns: a reference to the object describing the working schema of the connection. Since the underlying connection is probed before the object info construction, it is always a valid schema.

    Throws: ConnectionServiceException if the underlying connection becomes invalid and cannot be recovered. InvalidSessionProxyException if the associated Connection service is unavailable.

  • ISchema& schema();

    Returns: a reference to the object describing the specified schema. Since the underlying connection is probed before the object info construction, it is always a valid schema.

    Throws: ConnectionServiceException if the underlying connection becomes invalid and cannot be recovered. InvalidSessionProxyException if the associated Connection service is unavailable.

  • ITransaction& transaction();

    Returns: a reference to the object describing the transaction. Since the underlying connection is probed before the object info construction, it is always a valid transaction.

    Throws: ConnectionServiceException if the underlying connection becomes invalid and cannot be recovered. InvalidSessionProxyException if the associated Connection service is unavailable.

  • ITypeConverter& typeConverter();

    Returns: a reference to the type converter of the active session. Since the underlying connection is probed before the object info construction, it is always a valid type converter.

    Throws: ConnectionServiceException if the underlying connection becomes invalid and cannot be recovered. InvalidSessionProxyException if the associated Connection service is unavailable.

  • bool isConnectionShared();

    Returns: TRUE if the underlying connection is shared among more session proxies. To be used to control read-only transaction of shared sessions. Only the last remaining session (the one having isConnectionShared()== false ) must call the transaction commit.

    Throws: InvalidSessionProxyException if the associated Connection service is unavailable.

6.4. class ISessionProperties

6.4.1. Members
  • std::string flavorName() ;

    Returns: the name of the RDBMS flavour for the underlying connection.

    Throws: never throws.

  • std::string serverVersion();

    Returns: the version of the database server of the underying connection

    Throws: never throws.

6.5. class IWebCacheControl

6.5.1. Members
  • void refreshSchemaInfo( const std::string& connection );

    Parameters:
    •  connection 
      : the connection name

    Effects: Instructs the RDBMS backend that all the tables within the schema specified by the physical or logical connection should be refreshed, in case they are accessed.

    Throws: never throws.

  • void refreshTable( const std::string& connection, const std::string& tableName );

    Parameters:
    •  connection 
      : the connection name

    •  tableName 
      : the specific table name

    Effects: Instructs the RDBMS backend that the specified table within the schema specified by the physical or logical connection should be refreshed in case it is accessed.

    Throws: never throws.

  • const IWebCacheInfo& webCacheInfo( const std::string& connection ) const ;

    Parameters:
    •  connection 
      : the connection name

    Returns: the web cache information for a schema given the corresponding physical or logical connection.

    Throws: never throws.

  • int compressionLevel();

    Returns: the current compression level in use.

    Throws: never throws.

  • void setCompressionLevel( int level );

    Parameters:
    •  level 
      : the compression level: 0 - off, 1 - fast, 5 - default, 9 - maximum

    Effects: Sets the compression level for data transfer

    Throws: never throws.

  • void setProxyList( const std::vector<std::string>& proxyList );

    Parameters:
    •  proxyList 
      : the list of the web cache proxies

    Effects: Sets the list of the web cache proxies for the plug-in internal fail-over mechanism

    Throws: never throws.

6.6. class IWebCacheInfo

6.6.1. Members
  • bool isSchemaInfoCached() const ;

    Returns: TRUE if the schema info (data dictionary) is cached, i.e.it does not need to be refreshed

    Throws: never throws.

  • bool isTableCached( const std::string& tableName ) const;

    Parameters:
    •  tableName 
      : the specific table of the schema

    Returns: TRUE if a table in the schema is cached, i.e.it does not need to be refreshed

    Throws: never throws.

6.7. class IWebCacheInfo

6.7.1. Members
  • std::set< std::string > monitoredDataSources() const ;

    Returns: the set of currently monitored data sources.

    Throws: never throws.

  • void report( unsigned int level=coral::monitor::Default ) const;

    Parameters:
    •  level 
      : the monitoring level used as a filter

    Effects: Reports the events for all data sources being monitored.

    Throws: never throws.

  • void report( const std::string& contextKey, unsigned int level=coral::monitor::Default ) const ;

    Parameters:
    •  contextKey 
      : the data source name

    •  level 
      : the monitoring level used as a filter

    Effects: Reports the events for a given data source name of a given monitoring level.

    Throws: never throws.

  • void reportToOutputStream( const std::string& contextKey, std::ostream& os, unsigned int level=coral::monitor::Default ) const ;

    Parameters:
    •  contextKey 
      : the data source name

    •  os 
      : the reference the output stream to be used.

    •  level 
      : the monitoring level used as a filter

    Effects: Reports the events for a given data source name to the specified output stream.

    Throws: never throws.