Ejemplo n.º 1
0
CDB_Connection*
CDBConnectionFactory::MakeDBConnection(
    I_DriverContext& ctx,
    const CDBConnParams& params)
{
    CFastMutexGuard mg(m_Mtx);

    CDB_UserHandler::ClearExceptions(m_Errors);

    CDB_Connection* t_con = NULL;
    CRuntimeData& rt_data = GetRuntimeData(params.GetConnValidator());
    TSvrRef dsp_srv = rt_data.GetDispatchedServer(params.GetServerName());

    // Prepare to collect messages, whose proper severity depends on whether
    // ANY attempt succeeds.
    impl::CDBHandlerStack ultimate_handlers;
    {{
        const impl::CDriverContext* ctx_impl
            = dynamic_cast<impl::CDriverContext*>(&ctx);
        if (params.GetOpeningMsgHandlers().GetSize() > 0) {
            ultimate_handlers = params.GetOpeningMsgHandlers();
        } else if (ctx_impl != NULL) {
            ultimate_handlers = ctx_impl->GetCtxHandlerStack();
        } else {
            ultimate_handlers.Push(&CDB_UserHandler::GetDefault());
        }
    }}
    SOpeningContext opening_ctx(ctx);
    CRef<CDB_UserHandler_Deferred> handler
        (new CDB_UserHandler_Deferred(ultimate_handlers));
    opening_ctx.handlers.Push(&*handler, eTakeOwnership);
    
    // Store original query timeout ...
    unsigned int query_timeout = ctx.GetTimeout();

    // Set "validation timeouts" ...
    ctx.SetTimeout(CalculateConnectionTimeout(ctx));
    ctx.SetLoginTimeout(CalculateLoginTimeout(ctx));

    if ( dsp_srv.Empty() ) {
        // We are here either because server name was never dispatched or
        // because a named connection pool has been used before.
        // Dispatch server name ...

        t_con = DispatchServerName(opening_ctx, params);
    } else {
        // Server name is already dispatched ...
        string single_server(params.GetParam("single_server"));

        // We probably need to re-dispatch it ...
        if (single_server != "true"  &&  GetMaxNumOfDispatches() &&
            rt_data.GetNumOfDispatches(params.GetServerName()) >= GetMaxNumOfDispatches()) {
            // We definitely need to re-dispatch it ...

            // Clean previous info ...
            rt_data.SetDispatchedServer(params.GetServerName(), TSvrRef());
            t_con = DispatchServerName(opening_ctx, params);
        } else {
            // We do not need to re-dispatch it ...

            // Try to connect.
            try {
                // I_DriverContext::SConnAttr cur_conn_attr(conn_attr);
                // cur_conn_attr.srv_name = dsp_srv->GetName();
                CDB_DBLB_Delegate cur_params(
                        dsp_srv->GetName(),
                        dsp_srv->GetHost(),
                        dsp_srv->GetPort(),
                        params);
                cur_params.SetOpeningMsgHandlers() = opening_ctx.handlers;

                // MakeValidConnection may return NULL here because a newly
                // created connection may not pass validation.
                t_con = MakeValidConnection(opening_ctx,
                                            // cur_conn_attr,
                                            cur_params);

            } catch (CDB_Exception& ex) {
                // m_Errors.push_back(ex.Clone());
                opening_ctx.handlers.PostMsg(&ex);
                if (params.GetConnValidator()) {
                    opening_ctx.conn_status
                        = params.GetConnValidator()->ValidateException(ex);
                }
            }

            if (!t_con) {
                // We couldn't connect ...
                if (single_server != "true") {
                    // Server might be temporarily unavailable ...
                    // Check conn_status ...
                    if (opening_ctx.conn_status
                        == IConnValidator::eTempInvalidConn) {
                        rt_data.IncNumOfValidationFailures(params.GetServerName(),
                                                           dsp_srv);
                    }

                    // Re-dispatch ...
                    t_con = DispatchServerName(opening_ctx, params);
                }
            } else {
                // Dispatched server is already set, but calling of this method
                // will increase number of successful dispatches.
                rt_data.SetDispatchedServer(params.GetServerName(), dsp_srv);
            }
        }
    }

    // Restore original connection timeout ...
    ctx.SetTimeout(query_timeout);

    // Restore original query timeout ...
    if (t_con) {
        t_con->SetTimeout(query_timeout);
    }

    x_LogConnection(opening_ctx, t_con, params);
    handler->Flush((t_con == NULL) ? eDiagSevMax : eDiag_Warning);

    return t_con;
}