<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: SlsSlideFunction.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 19:07:40 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"

#include "controller/SlsSlideFunction.hxx"

#include "SlideSorterViewShell.hxx"
#include "controller/SlideSorterController.hxx"
#include "view/SlideSorterView.hxx"
#include "model/SlideSorterModel.hxx"

namespace sd { namespace slidesorter { namespace controller {

TYPEINIT1(SlideFunction, FuPoor);

SlideFunction::SlideFunction (
    SlideSorterController& rController,
    SfxRequest& rRequest)
    : FuPoor (
        &rController.GetViewShell(),
        rController.GetView().GetWindow(),
        & rController.GetView(),
        rController.GetModel().GetDocument(),
        rRequest)
{
}

FunctionReference SlideFunction::Create( SlideSorterController& rController, SfxRequest& rRequest )
{
    FunctionReference xFunc( new SlideFunction( rController, rRequest ) );
    return xFunc;
}

void SlideFunction::ScrollStart (void)
{
}

void SlideFunction::ScrollEnd (void)
{
}

BOOL SlideFunction::MouseMove(const MouseEvent& rMEvt)
{
    return FALSE;
}

BOOL SlideFunction::MouseButtonUp(const MouseEvent& rMEvt)
{
    return FALSE;

}

BOOL SlideFunction::MouseButtonDown(const MouseEvent& rMEvt)
{
    return FALSE;
}

} } } // end of namespace ::sd::slidesorter::controller
<commit_msg>INTEGRATION: CWS sdwarningsbegone (1.5.38); FILE MERGED 2006/11/22 12:42:12 cl 1.5.38.1: #i69285# warning free code changes for unxlngi6.pro<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: SlsSlideFunction.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: kz $ $Date: 2006-12-12 18:32:19 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"

#include "controller/SlsSlideFunction.hxx"

#include "SlideSorterViewShell.hxx"
#include "controller/SlideSorterController.hxx"
#include "view/SlideSorterView.hxx"
#include "model/SlideSorterModel.hxx"

namespace sd { namespace slidesorter { namespace controller {

TYPEINIT1(SlideFunction, FuPoor);

SlideFunction::SlideFunction (
    SlideSorterController& rController,
    SfxRequest& rRequest)
    : FuPoor (
        &rController.GetViewShell(),
        rController.GetView().GetWindow(),
        & rController.GetView(),
        rController.GetModel().GetDocument(),
        rRequest)
{
}

FunctionReference SlideFunction::Create( SlideSorterController& rController, SfxRequest& rRequest )
{
    FunctionReference xFunc( new SlideFunction( rController, rRequest ) );
    return xFunc;
}

void SlideFunction::ScrollStart (void)
{
}

void SlideFunction::ScrollEnd (void)
{
}

BOOL SlideFunction::MouseMove(const MouseEvent& )
{
    return FALSE;
}

BOOL SlideFunction::MouseButtonUp(const MouseEvent& )
{
    return FALSE;

}

BOOL SlideFunction::MouseButtonDown(const MouseEvent& )
{
    return FALSE;
}

} } } // end of namespace ::sd::slidesorter::controller
<|endoftext|>


<commit_before>#include "Version.h"
#include "SourceControl.h"
#include "System/Config.h"
#include "System/Events/EventLoop.h"
#include "System/IO/IOProcessor.h"
#include "System/Service.h"
#include "System/FileSystem.h"
#include "System/CrashReporter.h"
#include "Framework/Storage/BloomFilter.h"
#include "Application/Common/ContextTransport.h"
#include "Application/ConfigServer/ConfigServerApp.h"
#include "Application/ShardServer/ShardServerApp.h"

#define    IDENT            "ScalienDB"

const char PRODUCT_STRING[] = IDENT " v" VERSION_STRING " " PLATFORM_STRING;
const char BUILD_DATE[]     = "Build date: " __DATE__ " " __TIME__;

static void InitLog();
static void ParseArgs(int argc, char** argv);
static void SetupServiceIdentity(ServiceIdentity& ident);
static void RunMain(int argc, char** argv);
static void RunApplication();
static void ConfigureSystemSettings();
static bool IsController();
static void InitContextTransport();
static void LogPrintVersion(bool isController);
static void CrashReporterCallback();

// the application object is global for debugging purposes
static Application*     app;
static bool             restoreMode = false;
static bool             setNodeID = false;
static uint64_t         nodeID = 0;

int main(int argc, char** argv)
{
    SetMemoryLeakReports();

    try
    {
        // crash reporter messes up the debugging on Windows
#ifndef DEBUG
        CrashReporter::SetCallback(CFunc(CrashReporterCallback));
#endif
        RunMain(argc, argv);
    }
    catch (std::bad_alloc& e)
    {
        UNUSED(e);
        STOP_FAIL(1, "Out of memory error");
    }
    catch (std::exception& e)
    {
        STOP_FAIL(1, "Unexpected exception happened (%s)", e.what());
    }
    catch (...)
    {
        STOP_FAIL(1, "Unexpected exception happened");
    }

    ReportMemoryLeaks();

    return 0;
}

static void RunMain(int argc, char** argv)
{
    ServiceIdentity     identity;

    ParseArgs(argc, argv);

    if (argc < 2)
        STOP_FAIL(1, "Config file argument not given");

    if (!configFile.Init(argv[1]))
        STOP_FAIL(1, "Invalid config file (%s)", argv[1]);

    InitLog();

    // HACK: this is called twice, because command line arguments may override log settings
    ParseArgs(argc, argv);
    SetupServiceIdentity(identity);
    Service::Main(argc, argv, RunApplication, identity);
}

static void RunApplication()
{
    bool            isController;

    StartClock();
    ConfigureSystemSettings();

    IOProcessor::Init(configFile.GetIntValue("io.maxfd", 32768));
    InitContextTransport();
    BloomFilter::StaticInit();

    isController = IsController();
    LogPrintVersion(isController);
    if (isController)
        app = new ConfigServerApp(restoreMode);
    else
        app = new ShardServerApp(restoreMode, setNodeID, nodeID);

    Service::SetStatus(SERVICE_STATUS_RUNNING);
    app->Init();

    IOProcessor::BlockSignals(IOPROCESSOR_BLOCK_ALL);
    EventLoop::Init();

    EventLoop::Run();

    Service::SetStatus(SERVICE_STATUS_STOP_PENDING);
    Log_Message("Shutting down...");

    EventLoop::Shutdown();
    app->Shutdown();
    delete app;

    IOProcessor::Shutdown();
    StopClock();
    configFile.Shutdown();
    Registry::Shutdown();

    // This is here and not the end of main(), because logging may be turned off by then
    Log_Message(IDENT " exited normally");
    Log_Shutdown();
}

static void SetupServiceIdentity(ServiceIdentity& identity)
{
    // set up service identity based on role
    if (IsController())
    {
        identity.name = "ScalienController";
        identity.displayName = "Scalien Database Controller";
        identity.description = "Provides and stores metadata for Scalien Database cluster";
    }
    else
    {
        identity.name = "ScalienShardServer";
        identity.displayName = "Scalien Database Shard Server";
        identity.description = "Provides reliable and replicated data storage for Scalien Database cluster";
    }
}

static void InitLog()
{
    int logTargets;
    bool debug;

#ifdef DEBUG
    debug = true;
#else
    debug = false;
#endif

    logTargets = 0;
    if (configFile.GetListNum("log.targets") == 0)
        logTargets = LOG_TARGET_STDOUT;

    for (int i = 0; i < configFile.GetListNum("log.targets"); i++)
    {
        if (strcmp(configFile.GetListValue("log.targets", i, ""), "file") == 0)
        {
            logTargets |= LOG_TARGET_FILE;
            Log_SetOutputFile(configFile.GetValue("log.file", NULL),
            configFile.GetBoolValue("log.truncate", false));
        }
        if (strcmp(configFile.GetListValue("log.targets", i, NULL), "stdout") == 0)
            logTargets |= LOG_TARGET_STDOUT;
        if (strcmp(configFile.GetListValue("log.targets", i, NULL), "stderr") == 0)
            logTargets |= LOG_TARGET_STDERR;
    }
    Log_SetTarget(logTargets);

    Log_SetTrace(configFile.GetBoolValue("log.trace", false));
    Log_SetDebug(configFile.GetBoolValue("log.debug", debug));
    Log_SetTimestamping(configFile.GetBoolValue("log.timestamping", false));
    Log_SetAutoFlush(configFile.GetBoolValue("log.autoFlush", true));
    Log_SetMaxSize(configFile.GetIntValue("log.maxSize", 100*1000*1000) / (1000 * 1000));
    Log_SetTraceBufferSize(configFile.GetIntValue("log.traceBufferSize", 0));
    Log_SetFlushInterval(configFile.GetIntValue("log.flushInterval", 0) * 1000);
}

static void ParseDebugArgs(char* arg)
{
    bool    pause = false;

    switch (arg[0])
    {
    case 'X':
        // Do not exit on error or assert
        SetExitOnError(false);
        SetAssertCritical(false);
        break;
    case 'P':
        // Pause execution while debugger is attaching
        // Once the debugger is attached, change the value of pause to false
        pause = true;
        while (pause)
            MSleep(1000);   // <- Put debugger breakpoint this line
        break;
    }
}

static void ParseArgs(int argc, char** argv)
{
    ReadBuffer arg;

    for (int i = 1; i < argc; i++)
    {
        if (argv[i][0] == '-')
        {
            switch (argv[i][1])
            {
            case 't':
                Log_SetTrace(true);
                break;
            case 'D':
                // Debugging options
                ParseDebugArgs(&argv[i][2]);
                break;
            case 'v':
                STOP("%s", PRODUCT_STRING);
                break;
            case 'r':
                restoreMode = true;
                break;
            case 'n':
                setNodeID = true;
                i++;
                arg.Wrap(argv[i]);
                arg.Readf("%U", &nodeID);
                break;
            case 'h':
                STOP("Usage:\n"
                     "\n"
                     "       %s config-file [options] [service-options]\n"
                     "\n"
                     "Options:\n"
                     "\n"
                     "       -v: print version number and exit\n"
                     "       -r: start server in restore mode\n"
                     "       -t: turn trace mode on\n"
                     "       -h: print this help\n"
                     "\n"
                     "Service options (mutually exclusive):\n"
                     "\n"
                     "       --install:   install service\n"
                     "       --reinstall: reinstall service\n"
                     "       --uninstall: uninstall server\n"
                     , argv[0]);
                break;
            }
        }
    }
}

static void ConfigureSystemSettings()
{
    int         memLimitPerc;
    uint64_t    memLimit;
    uint64_t    maxFileCacheSize;
    const char* dir;

    // percentage of physical memory can be used by the program
    memLimitPerc = configFile.GetIntValue("system.memoryLimitPercentage", 90);
    if (memLimitPerc < 0)
        memLimitPerc = 90;

    // memoryLimit overrides memoryLimitPercentage
    memLimit = configFile.GetInt64Value("system.memoryLimit", 0);
    if (memLimit == 0)
        memLimit = (uint64_t) (GetTotalPhysicalMemory() * memLimit / 100.0 + 0.5);

    if (memLimit != 0)
        SetMemoryLimit(memLimit);

    // Set the maximum size of file system cache used by the OS.
    // This is needed on Windows, because it has _really_ dumb cache allocation strategy,
    // that totally kills IO intensive applications like databases.
    // For more, see:
    // http://blogs.msdn.com/b/ntdebugging/archive/2009/02/06/microsoft-windows-dynamic-cache-service.aspx
    maxFileCacheSize = configFile.GetInt64Value("system.maxFileCacheSize", 0);
    if (maxFileCacheSize != 0)
        SetMaxFileCacheSize(maxFileCacheSize);

    *(Registry::GetUintPtr("system.maxFileCacheSize")) = maxFileCacheSize;

    // set the base directory
    dir = configFile.GetValue("dir", NULL);
    if (dir)
    {
        if (!FS_ChangeDir(dir))
            STOP_FAIL(1, "Cannot change to dir: %s", dir);

        // setting the base dir may affect the location of the log file
        InitLog();
    }

    // set exit on error: this is how ASSERTs are handled in release build
    SetExitOnError(true);

    // this must be called here, because the first value it returns might be unreliable
    GetTotalCpuUsage();

    SeedRandom();
}

static bool IsController()
{
    const char* role;

    role = configFile.GetValue("role", "");
    if (role == NULL)
        STOP_FAIL(1, "Missing \"role\" in config file!");

    if (strcmp(role, "controller") == 0)
        return true;
    else
        return false;
}

static void InitContextTransport()
{
    const char* str;
    Endpoint    endpoint;

    // set my endpoint
    str = configFile.GetValue("endpoint", "");
    if (str == NULL)
        STOP_FAIL(1, "Missing \"endpoint\" in config file!");

    if (!endpoint.Set(str, true))
        STOP_FAIL(1, "Bad endpoint format in config file!");

    CONTEXT_TRANSPORT->Init(endpoint);
}

static void LogPrintVersion(bool isController)
{
    Log_Message("%s started as %s", PRODUCT_STRING,
     isController ? "CONTROLLER" : "SHARD SERVER");

    Log_Message("Pid: %U", GetProcessID());
    Log_Message("%s", BUILD_DATE);
    Log_Message("Branch: %s", SOURCE_CONTROL_BRANCH);
    Log_Message("Source control version: %s", SOURCE_CONTROL_VERSION);
    Log_Message("================================================================");
}

static void CrashReporterCallback()
{
    const char*     msg;

    // We need to be careful here, because by the time the control gets here the stack and the heap
    // may already be corrupted. Therefore there must not be any heap allocations here, but unfortunately
    // stack allocations cannot be avoided.

    // When rotating the log there is heap allocation. To prevent it, we turn off log rotation ASAP.
    Log_SetMaxSize(0);

    CrashReporter::ReportSystemEvent(IDENT);

    // Generate report and send it to log and standard error
    msg = CrashReporter::GetReport();

    Log_SetTarget(Log_GetTarget() | LOG_TARGET_STDERR | LOG_TARGET_FILE);
    Log_Message("%s", msg);
    IFDEBUG(ASSERT_FAIL());
    _exit(1);
}
<commit_msg>Changed SetMemoryLeakReports location in Main.<commit_after>#include "Version.h"
#include "SourceControl.h"
#include "System/Config.h"
#include "System/Events/EventLoop.h"
#include "System/IO/IOProcessor.h"
#include "System/Service.h"
#include "System/FileSystem.h"
#include "System/CrashReporter.h"
#include "Framework/Storage/BloomFilter.h"
#include "Application/Common/ContextTransport.h"
#include "Application/ConfigServer/ConfigServerApp.h"
#include "Application/ShardServer/ShardServerApp.h"

#define    IDENT            "ScalienDB"

const char PRODUCT_STRING[] = IDENT " v" VERSION_STRING " " PLATFORM_STRING;
const char BUILD_DATE[]     = "Build date: " __DATE__ " " __TIME__;

static void InitLog();
static void ParseArgs(int argc, char** argv);
static void SetupServiceIdentity(ServiceIdentity& ident);
static void RunMain(int argc, char** argv);
static void RunApplication();
static void ConfigureSystemSettings();
static bool IsController();
static void InitContextTransport();
static void LogPrintVersion(bool isController);
static void CrashReporterCallback();

// the application object is global for debugging purposes
static Application*     app;
static bool             restoreMode = false;
static bool             setNodeID = false;
static uint64_t         nodeID = 0;

int main(int argc, char** argv)
{
    try
    {
        // crash reporter messes up the debugging on Windows
#ifndef DEBUG
        CrashReporter::SetCallback(CFunc(CrashReporterCallback));
#endif
        RunMain(argc, argv);
    }
    catch (std::bad_alloc& e)
    {
        UNUSED(e);
        STOP_FAIL(1, "Out of memory error");
    }
    catch (std::exception& e)
    {
        STOP_FAIL(1, "Unexpected exception happened (%s)", e.what());
    }
    catch (...)
    {
        STOP_FAIL(1, "Unexpected exception happened");
    }

    ReportMemoryLeaks();

    return 0;
}

static void RunMain(int argc, char** argv)
{
    ServiceIdentity     identity;

    ParseArgs(argc, argv);

    if (argc < 2)
        STOP_FAIL(1, "Config file argument not given");

    if (!configFile.Init(argv[1]))
        STOP_FAIL(1, "Invalid config file (%s)", argv[1]);

    InitLog();

    // HACK: this is called twice, because command line arguments may override log settings
    ParseArgs(argc, argv);
    SetupServiceIdentity(identity);
    Service::Main(argc, argv, RunApplication, identity);
}

static void RunApplication()
{
    bool            isController;

    StartClock();
    ConfigureSystemSettings();

    IOProcessor::Init(configFile.GetIntValue("io.maxfd", 32768));
    InitContextTransport();
    BloomFilter::StaticInit();

    isController = IsController();
    LogPrintVersion(isController);
    if (isController)
        app = new ConfigServerApp(restoreMode);
    else
        app = new ShardServerApp(restoreMode, setNodeID, nodeID);

    Service::SetStatus(SERVICE_STATUS_RUNNING);
    app->Init();

    IOProcessor::BlockSignals(IOPROCESSOR_BLOCK_ALL);
    EventLoop::Init();

    EventLoop::Run();

    Service::SetStatus(SERVICE_STATUS_STOP_PENDING);
    Log_Message("Shutting down...");

    EventLoop::Shutdown();
    app->Shutdown();
    delete app;

    IOProcessor::Shutdown();
    StopClock();
    configFile.Shutdown();
    Registry::Shutdown();

    // This is here and not the end of main(), because logging may be turned off by then
    Log_Message(IDENT " exited normally");
    Log_Shutdown();
}

static void SetupServiceIdentity(ServiceIdentity& identity)
{
    // set up service identity based on role
    if (IsController())
    {
        identity.name = "ScalienController";
        identity.displayName = "Scalien Database Controller";
        identity.description = "Provides and stores metadata for Scalien Database cluster";
    }
    else
    {
        identity.name = "ScalienShardServer";
        identity.displayName = "Scalien Database Shard Server";
        identity.description = "Provides reliable and replicated data storage for Scalien Database cluster";
    }
}

static void InitLog()
{
    int logTargets;
    bool debug;

#ifdef DEBUG
    debug = true;
#else
    debug = false;
#endif

    logTargets = 0;
    if (configFile.GetListNum("log.targets") == 0)
        logTargets = LOG_TARGET_STDOUT;

    for (int i = 0; i < configFile.GetListNum("log.targets"); i++)
    {
        if (strcmp(configFile.GetListValue("log.targets", i, ""), "file") == 0)
        {
            logTargets |= LOG_TARGET_FILE;
            Log_SetOutputFile(configFile.GetValue("log.file", NULL),
            configFile.GetBoolValue("log.truncate", false));
        }
        if (strcmp(configFile.GetListValue("log.targets", i, NULL), "stdout") == 0)
            logTargets |= LOG_TARGET_STDOUT;
        if (strcmp(configFile.GetListValue("log.targets", i, NULL), "stderr") == 0)
            logTargets |= LOG_TARGET_STDERR;
    }
    Log_SetTarget(logTargets);

    Log_SetTrace(configFile.GetBoolValue("log.trace", false));
    Log_SetDebug(configFile.GetBoolValue("log.debug", debug));
    Log_SetTimestamping(configFile.GetBoolValue("log.timestamping", false));
    Log_SetAutoFlush(configFile.GetBoolValue("log.autoFlush", true));
    Log_SetMaxSize(configFile.GetIntValue("log.maxSize", 100*1000*1000) / (1000 * 1000));
    Log_SetTraceBufferSize(configFile.GetIntValue("log.traceBufferSize", 0));
    Log_SetFlushInterval(configFile.GetIntValue("log.flushInterval", 0) * 1000);
}

static void ParseDebugArgs(char* arg)
{
    bool    pause = false;

    switch (arg[0])
    {
    case 'X':
        // Do not exit on error or assert
        SetExitOnError(false);
        SetAssertCritical(false);
        break;
    case 'P':
        // Pause execution while debugger is attaching
        // Once the debugger is attached, change the value of pause to false
        pause = true;
        while (pause)
            MSleep(1000);   // <- Put debugger breakpoint this line
        break;
    }
}

static void ParseArgs(int argc, char** argv)
{
    ReadBuffer arg;

    for (int i = 1; i < argc; i++)
    {
        if (argv[i][0] == '-')
        {
            switch (argv[i][1])
            {
            case 't':
                Log_SetTrace(true);
                break;
            case 'D':
                // Debugging options
                ParseDebugArgs(&argv[i][2]);
                break;
            case 'v':
                STOP("%s", PRODUCT_STRING);
                break;
            case 'r':
                restoreMode = true;
                break;
            case 'n':
                setNodeID = true;
                i++;
                arg.Wrap(argv[i]);
                arg.Readf("%U", &nodeID);
                break;
            case 'h':
                STOP("Usage:\n"
                     "\n"
                     "       %s config-file [options] [service-options]\n"
                     "\n"
                     "Options:\n"
                     "\n"
                     "       -v: print version number and exit\n"
                     "       -r: start server in restore mode\n"
                     "       -t: turn trace mode on\n"
                     "       -h: print this help\n"
                     "\n"
                     "Service options (mutually exclusive):\n"
                     "\n"
                     "       --install:   install service\n"
                     "       --reinstall: reinstall service\n"
                     "       --uninstall: uninstall server\n"
                     , argv[0]);
                break;
            }
        }
    }
}

static void ConfigureSystemSettings()
{
    int         memLimitPerc;
    uint64_t    memLimit;
    uint64_t    maxFileCacheSize;
    const char* dir;

    // percentage of physical memory can be used by the program
    memLimitPerc = configFile.GetIntValue("system.memoryLimitPercentage", 90);
    if (memLimitPerc < 0)
        memLimitPerc = 90;

    // memoryLimit overrides memoryLimitPercentage
    memLimit = configFile.GetInt64Value("system.memoryLimit", 0);
    if (memLimit == 0)
        memLimit = (uint64_t) (GetTotalPhysicalMemory() * memLimit / 100.0 + 0.5);

    if (memLimit != 0)
        SetMemoryLimit(memLimit);

    // Set the maximum size of file system cache used by the OS.
    // This is needed on Windows, because it has _really_ dumb cache allocation strategy,
    // that totally kills IO intensive applications like databases.
    // For more, see:
    // http://blogs.msdn.com/b/ntdebugging/archive/2009/02/06/microsoft-windows-dynamic-cache-service.aspx
    maxFileCacheSize = configFile.GetInt64Value("system.maxFileCacheSize", 0);
    if (maxFileCacheSize != 0)
        SetMaxFileCacheSize(maxFileCacheSize);

    *(Registry::GetUintPtr("system.maxFileCacheSize")) = maxFileCacheSize;

    // set the base directory
    dir = configFile.GetValue("dir", NULL);
    if (dir)
    {
        if (!FS_ChangeDir(dir))
            STOP_FAIL(1, "Cannot change to dir: %s", dir);

        // setting the base dir may affect the location of the log file
        InitLog();
    }

    // set exit on error: this is how ASSERTs are handled in release build
    SetExitOnError(true);

    // this must be called here, because the first value it returns might be unreliable
    GetTotalCpuUsage();

    SeedRandom();

    SetMemoryLeakReports();
}

static bool IsController()
{
    const char* role;

    role = configFile.GetValue("role", "");
    if (role == NULL)
        STOP_FAIL(1, "Missing \"role\" in config file!");

    if (strcmp(role, "controller") == 0)
        return true;
    else
        return false;
}

static void InitContextTransport()
{
    const char* str;
    Endpoint    endpoint;

    // set my endpoint
    str = configFile.GetValue("endpoint", "");
    if (str == NULL)
        STOP_FAIL(1, "Missing \"endpoint\" in config file!");

    if (!endpoint.Set(str, true))
        STOP_FAIL(1, "Bad endpoint format in config file!");

    CONTEXT_TRANSPORT->Init(endpoint);
}

static void LogPrintVersion(bool isController)
{
    Log_Message("%s started as %s", PRODUCT_STRING,
     isController ? "CONTROLLER" : "SHARD SERVER");

    Log_Message("Pid: %U", GetProcessID());
    Log_Message("%s", BUILD_DATE);
    Log_Message("Branch: %s", SOURCE_CONTROL_BRANCH);
    Log_Message("Source control version: %s", SOURCE_CONTROL_VERSION);
    Log_Message("================================================================");
}

static void CrashReporterCallback()
{
    const char*     msg;

    // We need to be careful here, because by the time the control gets here the stack and the heap
    // may already be corrupted. Therefore there must not be any heap allocations here, but unfortunately
    // stack allocations cannot be avoided.

    // When rotating the log there is heap allocation. To prevent it, we turn off log rotation ASAP.
    Log_SetMaxSize(0);

    CrashReporter::ReportSystemEvent(IDENT);

    // Generate report and send it to log and standard error
    msg = CrashReporter::GetReport();

    Log_SetTarget(Log_GetTarget() | LOG_TARGET_STDERR | LOG_TARGET_FILE);
    Log_Message("%s", msg);
    IFDEBUG(ASSERT_FAIL());
    _exit(1);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdint>
#include <random>
#include <chrono>
#include <vector>
#include <boost/dynamic_bitset.hpp>

/**
 * Lessons learned so far:
 * - SIMD registers are used as soon as we compile with -03
 * - If we want to get the real speed up (and use all SIMD registers by unfolding both loops,
 *   we have to know both, input-size and number of comparisons, at compile time.
 * - Otherwise, only some of the SIMD registers are used, and speedup is 0, compared to
 *   code optimized with 02.
 * - Example compile command: g++ -std=c++11 -march=native -O3 simd.cpp -o simd
 * - Command for getting assembly code: g++ -std=c++11 -march=native -O3 -S simd.cpp
 */

typedef std::mt19937 Engine;
typedef std::uniform_int_distribution<unsigned> Intdistr;

template <typename T, typename U>
void smaller (const T *input, U outputs, const T *comparison_values, const unsigned array_size, const unsigned comparisons) {

    for (unsigned i = 0; i < array_size; ++i)
    {
        for (unsigned m = 0; m < comparisons; ++m) {
            outputs[m*array_size+i] = input[i] < comparison_values[m];
        }
    }
}

//template <typename T>
//void pretty_print (T *arr, unsigned size, std::string s = "Pretty Print") {
//    std::cout << s << ":" << std::endl;
//    for (auto r = arr; r < arr+size; ++r ) {
//        std::cout << *r << std::endl;
//    }
//}

template <typename T>
void fill (T *arr, unsigned size) {
    Engine engine (0);
    Intdistr distr (0, 100000);
    for (auto r = arr; r < arr+size; ++r ) {
        *r = distr(engine);
    }
}

int main (int argc, char *argv[]) {
    typedef unsigned TestType;
    static constexpr unsigned repetitions = 100;

    constexpr unsigned input_size = 1000000;
    constexpr unsigned comparisons = 3;

//    if (argc != 3)
//    {
//        std::cout << "Usage: ./simd <input-size> <comparisons>" << std::endl;
//        return -1;
//    }
//    unsigned long input_size = std::stoi(argv[1]);
//    unsigned comparisons = std::stoi(argv[2]);

    std::cout << "input size: " << input_size << std::endl;
    std::cout << "comparisons :" << comparisons<< std::endl;

    TestType test_input [input_size];
    fill(test_input, input_size);
//    pretty_print(test_input, input_size, "Input");

    TestType comparison_values [comparisons];
    for (unsigned c = 0; c < comparisons; ++c) {
        comparison_values[c] = test_input[c];
    }
//    pretty_print(comparison_values, comparisons, "Comparison values");

    bool results [comparisons * input_size];
//    std::vector<bool> results (comparisons * input_size);
//    boost::dynamic_bitset<> results(comparisons * input_size);

    auto start = std::chrono::high_resolution_clock::now();
    for (unsigned i = 0; i < repetitions; ++i)
        smaller(test_input, results, comparison_values, input_size, comparisons);
    auto end = std::chrono::high_resolution_clock::now();
    std::cout << "Avg Time [microsecs]: "
              << (std::chrono::duration_cast<std::chrono::microseconds>(end-start).count())
                 /((double)repetitions)
              << std::endl;

//    for (unsigned c = 0; c < comparisons; ++c) {
//        pretty_print(&results[c*input_size], input_size, "Result");
//    }

    return 0;
}
<commit_msg>finished simd experiments for all-same-operator (smaller)<commit_after>#include <iostream>
#include <cstdint>
#include <random>
#include <chrono>
#include <vector>
#include <boost/dynamic_bitset.hpp>
#include <numeric>

/**
 * Lessons learned so far:
 * - SIMD registers are used as soon as we compile with -03
 * - If we want to get the real speed up (and use all SIMD registers by unfolding both loops,
 *   we have to know both, input-size and number of comparisons, at compile time.
 * - Otherwise, only some of the SIMD registers are used, and speedup is 0, compared to
 *   code optimized with 02.
 * - Example compile command: g++ -std=c++11 -march=native -O3 simd.cpp -o simd
 * - Command for getting assembly code: g++ -std=c++11 -march=native -O3 -S simd.cpp
 */

typedef std::mt19937 Engine;
typedef std::uniform_int_distribution<unsigned> Intdistr;

template <typename T, typename U>
void smaller (const T *input, U outputs, const T *comparison_values, const unsigned array_size, const unsigned comparisons) {

    for (unsigned i = 0; i < array_size; ++i)
    {
        for (unsigned m = 0; m < comparisons; ++m) {
            outputs[m*array_size+i] = (float) (input[i] < comparison_values[m]);
        }
    }
}

template <typename T>
void pretty_print (T *arr, unsigned size, std::string s = "Pretty Print") {
    std::cout << s << ":" << std::endl;
    for (auto r = arr; r < arr+size; ++r ) {
        std::cout << *r << std::endl;
    }
}

template <typename T>
void compute_stats(const std::vector<T> stats, double &mean, double &stdev) {
    double sum = std::accumulate(stats.begin(), stats.end(), 0.0);
    mean = sum / stats.size();

    std::vector<double> diff(stats.size());
    std::transform(stats.begin(), stats.end(), diff.begin(),
                   std::bind2nd(std::minus<double>(), mean));
    double sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0);
    stdev = std::sqrt(sq_sum / stats.size());
}

template <typename T>
void fill (T *arr, unsigned size) {
    Engine engine (0);
    Intdistr distr (0, 100000);
    for (auto r = arr; r < arr+size; ++r ) {
        *r = distr(engine);
    }
}

int main (int argc, char *argv[]) {
    //**** PARAMS ****/
    typedef unsigned TestType;
    static constexpr unsigned repetitions = 10000;

//    constexpr unsigned input_size = 500000;
    constexpr unsigned comparisons = 1;

//    if (argc != 3)
//    {
//        std::cout << "Usage: ./simd <input-size> <comparisons>" << std::endl;
//        return -1;
//    }
    unsigned long input_size = std::stoi(argv[1]);
//    unsigned comparisons = std::stoi(argv[2]);

    std::cout << "input size: " << input_size << std::endl;
    std::cout << "comparisons: " << comparisons<< std::endl;

    //**** INPUT ****/
    TestType test_input [input_size];
    fill(test_input, input_size);
//    pretty_print(test_input, input_size, "Input");

    TestType comparison_values [comparisons];
    for (unsigned c = 0; c < comparisons; ++c) {
        comparison_values[c] = test_input[c];
    }
//    pretty_print(comparison_values, comparisons, "Comparison values");

    //**** COMPUTE ****/
    std::vector<unsigned long> stats (repetitions);
    bool results [comparisons * input_size];
//    std::vector<bool> results (comparisons * input_size);
//    boost::dynamic_bitset<> results(comparisons * input_size);

    for (unsigned i = 0; i < repetitions; ++i) {
        auto start = std::chrono::high_resolution_clock::now();
        smaller(test_input, results, comparison_values, input_size, comparisons);
        auto end = std::chrono::high_resolution_clock::now();
        stats [i] =
            std::chrono::duration_cast<std::chrono::microseconds>(end-start).count();
    }

    //**** REPORT ****/
    double mean, stdev;
    compute_stats(stats, mean, stdev);
    std::cout
//              << "Avg Time [microsecs]: "
              << mean
              << "\t"
//              << "(+/- "
              << stdev
//              << ")"
              << std::endl;
//    pretty_print(stats.data(), repetitions, "Stats");

//    for (unsigned c = 0; c < comparisons; ++c) {
//        pretty_print(&results[c*input_size], input_size, "Result");
//    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "modules/audio_processing/aec3/echo_path_delay_estimator.h"

#include <algorithm>
#include <string>

#include "api/audio/echo_canceller3_config.h"
#include "modules/audio_processing/aec3/aec3_common.h"
#include "modules/audio_processing/aec3/render_delay_buffer.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
#include "modules/audio_processing/test/echo_canceller_test_tools.h"
#include "rtc_base/random.h"
#include "rtc_base/strings/string_builder.h"
#include "test/gtest.h"

namespace webrtc {
namespace {

std::string ProduceDebugText(size_t delay, size_t down_sampling_factor) {
  rtc::StringBuilder ss;
  ss << "Delay: " << delay;
  ss << ", Down sampling factor: " << down_sampling_factor;
  return ss.Release();
}

}  // namespace

class EchoPathDelayEstimatorMultiChannel
    : public ::testing::Test,
      public ::testing::WithParamInterface<std::tuple<size_t, size_t>> {};

INSTANTIATE_TEST_SUITE_P(MultiChannel,
                         EchoPathDelayEstimatorMultiChannel,
                         ::testing::Combine(::testing::Values(1, 2, 3, 6, 8),
                                            ::testing::Values(1, 2, 4)));

// Verifies that the basic API calls work.
TEST_P(EchoPathDelayEstimatorMultiChannel, BasicApiCalls) {
  const size_t num_render_channels = std::get<0>(GetParam());
  const size_t num_capture_channels = std::get<1>(GetParam());
  constexpr int kSampleRateHz = 48000;
  constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
  ApmDataDumper data_dumper(0);
  EchoCanceller3Config config;
  std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
      RenderDelayBuffer::Create(config, kSampleRateHz, num_render_channels));
  EchoPathDelayEstimator estimator(&data_dumper, config, num_capture_channels);
  std::vector<std::vector<std::vector<float>>> render(
      kNumBands, std::vector<std::vector<float>>(
                     num_render_channels, std::vector<float>(kBlockSize)));
  std::vector<std::vector<float>> capture(num_capture_channels,
                                          std::vector<float>(kBlockSize));
  for (size_t k = 0; k < 100; ++k) {
    render_delay_buffer->Insert(render);
    estimator.EstimateDelay(render_delay_buffer->GetDownsampledRenderBuffer(),
                            capture);
  }
}

// Verifies that the delay estimator produces correct delay for artificially
// delayed signals.
TEST(EchoPathDelayEstimator, DelayEstimation) {
  constexpr size_t kNumRenderChannels = 1;
  constexpr size_t kNumCaptureChannels = 1;
  constexpr int kSampleRateHz = 48000;
  constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);

  Random random_generator(42U);
  std::vector<std::vector<std::vector<float>>> render(
      kNumBands, std::vector<std::vector<float>>(
                     kNumRenderChannels, std::vector<float>(kBlockSize)));
  std::vector<std::vector<float>> capture(kNumCaptureChannels,
                                          std::vector<float>(kBlockSize));
  ApmDataDumper data_dumper(0);
  constexpr size_t kDownSamplingFactors[] = {2, 4, 8};
  for (auto down_sampling_factor : kDownSamplingFactors) {
    EchoCanceller3Config config;
    config.delay.down_sampling_factor = down_sampling_factor;
    config.delay.num_filters = 10;
    for (size_t delay_samples : {30, 64, 150, 200, 800, 4000}) {
      SCOPED_TRACE(ProduceDebugText(delay_samples, down_sampling_factor));
      std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
          RenderDelayBuffer::Create(config, kSampleRateHz, kNumRenderChannels));
      DelayBuffer<float> signal_delay_buffer(delay_samples);
      EchoPathDelayEstimator estimator(&data_dumper, config,
                                       kNumCaptureChannels);

      absl::optional<DelayEstimate> estimated_delay_samples;
      for (size_t k = 0; k < (500 + (delay_samples) / kBlockSize); ++k) {
        RandomizeSampleVector(&random_generator, render[0][0]);
        signal_delay_buffer.Delay(render[0][0], capture[0]);
        render_delay_buffer->Insert(render);

        if (k == 0) {
          render_delay_buffer->Reset();
        }

        render_delay_buffer->PrepareCaptureProcessing();

        auto estimate = estimator.EstimateDelay(
            render_delay_buffer->GetDownsampledRenderBuffer(), capture);

        if (estimate) {
          estimated_delay_samples = estimate;
        }
      }

      if (estimated_delay_samples) {
        // Allow estimated delay to be off by one sample in the down-sampled
        // domain.
        size_t delay_ds = delay_samples / down_sampling_factor;
        size_t estimated_delay_ds =
            estimated_delay_samples->delay / down_sampling_factor;
        EXPECT_NEAR(delay_ds, estimated_delay_ds, 1);
      } else {
        ADD_FAILURE();
      }
    }
  }
}

// Verifies that the delay estimator does not produce delay estimates for render
// signals of low level.
TEST(EchoPathDelayEstimator, NoDelayEstimatesForLowLevelRenderSignals) {
  constexpr size_t kNumRenderChannels = 1;
  constexpr size_t kNumCaptureChannels = 1;
  constexpr int kSampleRateHz = 48000;
  constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
  Random random_generator(42U);
  EchoCanceller3Config config;
  std::vector<std::vector<std::vector<float>>> render(
      kNumBands, std::vector<std::vector<float>>(
                     kNumRenderChannels, std::vector<float>(kBlockSize)));
  std::vector<std::vector<float>> capture(kNumCaptureChannels,
                                          std::vector<float>(kBlockSize));
  ApmDataDumper data_dumper(0);
  EchoPathDelayEstimator estimator(&data_dumper, config, kNumCaptureChannels);
  std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
      RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
                                kNumRenderChannels));
  for (size_t k = 0; k < 100; ++k) {
    RandomizeSampleVector(&random_generator, render[0][0]);
    for (auto& render_k : render[0][0]) {
      render_k *= 100.f / 32767.f;
    }
    std::copy(render[0][0].begin(), render[0][0].end(), capture[0].begin());
    render_delay_buffer->Insert(render);
    render_delay_buffer->PrepareCaptureProcessing();
    EXPECT_FALSE(estimator.EstimateDelay(
        render_delay_buffer->GetDownsampledRenderBuffer(), capture));
  }
}

#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)

// Verifies the check for the render blocksize.
// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
// tests on test bots has been fixed.
TEST(EchoPathDelayEstimator, DISABLED_WrongRenderBlockSize) {
  ApmDataDumper data_dumper(0);
  EchoCanceller3Config config;
  EchoPathDelayEstimator estimator(&data_dumper, config, 1);
  std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
      RenderDelayBuffer::Create(config, 48000, 1));
  std::vector<std::vector<float>> capture(1, std::vector<float>(kBlockSize));
  EXPECT_DEATH(estimator.EstimateDelay(
                   render_delay_buffer->GetDownsampledRenderBuffer(), capture),
               "");
}

// Verifies the check for the capture blocksize.
// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
// tests on test bots has been fixed.
TEST(EchoPathDelayEstimator, WrongCaptureBlockSize) {
  ApmDataDumper data_dumper(0);
  EchoCanceller3Config config;
  EchoPathDelayEstimator estimator(&data_dumper, config, 1);
  std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
      RenderDelayBuffer::Create(config, 48000, 1));
  std::vector<std::vector<float>> capture(1,
                                          std::vector<float>(kBlockSize - 1));
  EXPECT_DEATH(estimator.EstimateDelay(
                   render_delay_buffer->GetDownsampledRenderBuffer(), capture),
               "");
}

// Verifies the check for non-null data dumper.
TEST(EchoPathDelayEstimator, NullDataDumper) {
  EXPECT_DEATH(EchoPathDelayEstimator(nullptr, EchoCanceller3Config(), 1), "");
}

#endif

}  // namespace webrtc
<commit_msg>Rename EchoPathDelayEstimator to EchoPathDelayEstimatorDeathTest.<commit_after>/*
 *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "modules/audio_processing/aec3/echo_path_delay_estimator.h"

#include <algorithm>
#include <string>

#include "api/audio/echo_canceller3_config.h"
#include "modules/audio_processing/aec3/aec3_common.h"
#include "modules/audio_processing/aec3/render_delay_buffer.h"
#include "modules/audio_processing/logging/apm_data_dumper.h"
#include "modules/audio_processing/test/echo_canceller_test_tools.h"
#include "rtc_base/random.h"
#include "rtc_base/strings/string_builder.h"
#include "test/gtest.h"

namespace webrtc {
namespace {

std::string ProduceDebugText(size_t delay, size_t down_sampling_factor) {
  rtc::StringBuilder ss;
  ss << "Delay: " << delay;
  ss << ", Down sampling factor: " << down_sampling_factor;
  return ss.Release();
}

}  // namespace

class EchoPathDelayEstimatorMultiChannel
    : public ::testing::Test,
      public ::testing::WithParamInterface<std::tuple<size_t, size_t>> {};

INSTANTIATE_TEST_SUITE_P(MultiChannel,
                         EchoPathDelayEstimatorMultiChannel,
                         ::testing::Combine(::testing::Values(1, 2, 3, 6, 8),
                                            ::testing::Values(1, 2, 4)));

// Verifies that the basic API calls work.
TEST_P(EchoPathDelayEstimatorMultiChannel, BasicApiCalls) {
  const size_t num_render_channels = std::get<0>(GetParam());
  const size_t num_capture_channels = std::get<1>(GetParam());
  constexpr int kSampleRateHz = 48000;
  constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
  ApmDataDumper data_dumper(0);
  EchoCanceller3Config config;
  std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
      RenderDelayBuffer::Create(config, kSampleRateHz, num_render_channels));
  EchoPathDelayEstimator estimator(&data_dumper, config, num_capture_channels);
  std::vector<std::vector<std::vector<float>>> render(
      kNumBands, std::vector<std::vector<float>>(
                     num_render_channels, std::vector<float>(kBlockSize)));
  std::vector<std::vector<float>> capture(num_capture_channels,
                                          std::vector<float>(kBlockSize));
  for (size_t k = 0; k < 100; ++k) {
    render_delay_buffer->Insert(render);
    estimator.EstimateDelay(render_delay_buffer->GetDownsampledRenderBuffer(),
                            capture);
  }
}

// Verifies that the delay estimator produces correct delay for artificially
// delayed signals.
TEST(EchoPathDelayEstimator, DelayEstimation) {
  constexpr size_t kNumRenderChannels = 1;
  constexpr size_t kNumCaptureChannels = 1;
  constexpr int kSampleRateHz = 48000;
  constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);

  Random random_generator(42U);
  std::vector<std::vector<std::vector<float>>> render(
      kNumBands, std::vector<std::vector<float>>(
                     kNumRenderChannels, std::vector<float>(kBlockSize)));
  std::vector<std::vector<float>> capture(kNumCaptureChannels,
                                          std::vector<float>(kBlockSize));
  ApmDataDumper data_dumper(0);
  constexpr size_t kDownSamplingFactors[] = {2, 4, 8};
  for (auto down_sampling_factor : kDownSamplingFactors) {
    EchoCanceller3Config config;
    config.delay.down_sampling_factor = down_sampling_factor;
    config.delay.num_filters = 10;
    for (size_t delay_samples : {30, 64, 150, 200, 800, 4000}) {
      SCOPED_TRACE(ProduceDebugText(delay_samples, down_sampling_factor));
      std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
          RenderDelayBuffer::Create(config, kSampleRateHz, kNumRenderChannels));
      DelayBuffer<float> signal_delay_buffer(delay_samples);
      EchoPathDelayEstimator estimator(&data_dumper, config,
                                       kNumCaptureChannels);

      absl::optional<DelayEstimate> estimated_delay_samples;
      for (size_t k = 0; k < (500 + (delay_samples) / kBlockSize); ++k) {
        RandomizeSampleVector(&random_generator, render[0][0]);
        signal_delay_buffer.Delay(render[0][0], capture[0]);
        render_delay_buffer->Insert(render);

        if (k == 0) {
          render_delay_buffer->Reset();
        }

        render_delay_buffer->PrepareCaptureProcessing();

        auto estimate = estimator.EstimateDelay(
            render_delay_buffer->GetDownsampledRenderBuffer(), capture);

        if (estimate) {
          estimated_delay_samples = estimate;
        }
      }

      if (estimated_delay_samples) {
        // Allow estimated delay to be off by one sample in the down-sampled
        // domain.
        size_t delay_ds = delay_samples / down_sampling_factor;
        size_t estimated_delay_ds =
            estimated_delay_samples->delay / down_sampling_factor;
        EXPECT_NEAR(delay_ds, estimated_delay_ds, 1);
      } else {
        ADD_FAILURE();
      }
    }
  }
}

// Verifies that the delay estimator does not produce delay estimates for render
// signals of low level.
TEST(EchoPathDelayEstimator, NoDelayEstimatesForLowLevelRenderSignals) {
  constexpr size_t kNumRenderChannels = 1;
  constexpr size_t kNumCaptureChannels = 1;
  constexpr int kSampleRateHz = 48000;
  constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
  Random random_generator(42U);
  EchoCanceller3Config config;
  std::vector<std::vector<std::vector<float>>> render(
      kNumBands, std::vector<std::vector<float>>(
                     kNumRenderChannels, std::vector<float>(kBlockSize)));
  std::vector<std::vector<float>> capture(kNumCaptureChannels,
                                          std::vector<float>(kBlockSize));
  ApmDataDumper data_dumper(0);
  EchoPathDelayEstimator estimator(&data_dumper, config, kNumCaptureChannels);
  std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
      RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
                                kNumRenderChannels));
  for (size_t k = 0; k < 100; ++k) {
    RandomizeSampleVector(&random_generator, render[0][0]);
    for (auto& render_k : render[0][0]) {
      render_k *= 100.f / 32767.f;
    }
    std::copy(render[0][0].begin(), render[0][0].end(), capture[0].begin());
    render_delay_buffer->Insert(render);
    render_delay_buffer->PrepareCaptureProcessing();
    EXPECT_FALSE(estimator.EstimateDelay(
        render_delay_buffer->GetDownsampledRenderBuffer(), capture));
  }
}

#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)

// Verifies the check for the render blocksize.
// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
// tests on test bots has been fixed.
TEST(EchoPathDelayEstimatorDeathTest, DISABLED_WrongRenderBlockSize) {
  ApmDataDumper data_dumper(0);
  EchoCanceller3Config config;
  EchoPathDelayEstimator estimator(&data_dumper, config, 1);
  std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
      RenderDelayBuffer::Create(config, 48000, 1));
  std::vector<std::vector<float>> capture(1, std::vector<float>(kBlockSize));
  EXPECT_DEATH(estimator.EstimateDelay(
                   render_delay_buffer->GetDownsampledRenderBuffer(), capture),
               "");
}

// Verifies the check for the capture blocksize.
// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
// tests on test bots has been fixed.
TEST(EchoPathDelayEstimatorDeathTest, WrongCaptureBlockSize) {
  ApmDataDumper data_dumper(0);
  EchoCanceller3Config config;
  EchoPathDelayEstimator estimator(&data_dumper, config, 1);
  std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
      RenderDelayBuffer::Create(config, 48000, 1));
  std::vector<std::vector<float>> capture(1,
                                          std::vector<float>(kBlockSize - 1));
  EXPECT_DEATH(estimator.EstimateDelay(
                   render_delay_buffer->GetDownsampledRenderBuffer(), capture),
               "");
}

// Verifies the check for non-null data dumper.
TEST(EchoPathDelayEstimatorDeathTest, NullDataDumper) {
  EXPECT_DEATH(EchoPathDelayEstimator(nullptr, EchoCanceller3Config(), 1), "");
}

#endif

}  // namespace webrtc
<|endoftext|>


<commit_before>#include <sys/time.h>
#include <ctime>
#include <cerrno>

#include "../utils/utils.hpp"

double walltime() {
	struct timeval tv;

	if (gettimeofday(&tv, NULL) == -1)
		fatalx(errno, "gettimeofday failed");

	return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
}

double cputime() {
	return clock() / CLOCKS_PER_SEC;
}
<commit_msg>utils: fix cputime computation.<commit_after>#include <sys/time.h>
#include <ctime>
#include <cerrno>

#include "../utils/utils.hpp"

double walltime() {
	struct timeval tv;

	if (gettimeofday(&tv, NULL) == -1)
		fatalx(errno, "gettimeofday failed");

	return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
}

double cputime() {
	return clock() / (double) CLOCKS_PER_SEC;
}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2015 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
**    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
**      disclaimer.
**    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
**      following disclaimer in the documentation and/or other materials provided with the distribution.
**    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
**      derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "precompiled.h"
#include "core.h"

QString SystemCommandResult::stdoutOneLine() const {
	Q_ASSERT(stdout_.size() == 1);
	return stdout_.first();
}

SystemCommandResult::operator QString() const
{
	Q_ASSERT(exitCode() == 0);
	Q_ASSERT(stderr_.size() == 0);
	return stdoutOneLine();
}

SystemCommandResult::operator QStringList() const
{
	Q_ASSERT(exitCode() == 0);
	Q_ASSERT(stderr_.size() == 0);
	return stdout_;
}

SystemCommandResult runSystemCommand(const QString& program, const QStringList& arguments,
												 const QString& workingDirectory)
{
	QProcess process;
	process.setProgram(program);
	if (!arguments.isEmpty()) process.setArguments(arguments);
	if (!workingDirectory.isNull()) process.setWorkingDirectory(workingDirectory);

	process.start();
	process.waitForFinished();

	SystemCommandResult result;
	result.exitCode_ = process.exitCode();

	auto EOLRegex = QRegularExpression("(\\r\\n|\\r|\\n)");
	result.stdout_ = QString(process.readAllStandardOutput()).split(EOLRegex);
	if (!result.stdout_.isEmpty() && result.stdout_.last().isEmpty())  result.stdout_.removeLast();
	result.stderr_ = QString(process.readAllStandardError()).split(EOLRegex);
	if (!result.stderr_.isEmpty() && result.stderr_.last().isEmpty())  result.stderr_.removeLast();

	return result;
}
<commit_msg>remove unused include<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2015 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
**    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
**      disclaimer.
**    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
**      following disclaimer in the documentation and/or other materials provided with the distribution.
**    * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
**      derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "precompiled.h"

QString SystemCommandResult::stdoutOneLine() const {
	Q_ASSERT(stdout_.size() == 1);
	return stdout_.first();
}

SystemCommandResult::operator QString() const
{
	Q_ASSERT(exitCode() == 0);
	Q_ASSERT(stderr_.size() == 0);
	return stdoutOneLine();
}

SystemCommandResult::operator QStringList() const
{
	Q_ASSERT(exitCode() == 0);
	Q_ASSERT(stderr_.size() == 0);
	return stdout_;
}

SystemCommandResult runSystemCommand(const QString& program, const QStringList& arguments,
												 const QString& workingDirectory)
{
	QProcess process;
	process.setProgram(program);
	if (!arguments.isEmpty()) process.setArguments(arguments);
	if (!workingDirectory.isNull()) process.setWorkingDirectory(workingDirectory);

	process.start();
	process.waitForFinished();

	SystemCommandResult result;
	result.exitCode_ = process.exitCode();

	auto EOLRegex = QRegularExpression("(\\r\\n|\\r|\\n)");
	result.stdout_ = QString(process.readAllStandardOutput()).split(EOLRegex);
	if (!result.stdout_.isEmpty() && result.stdout_.last().isEmpty())  result.stdout_.removeLast();
	result.stderr_ = QString(process.readAllStandardError()).split(EOLRegex);
	if (!result.stderr_.isEmpty() && result.stderr_.last().isEmpty())  result.stderr_.removeLast();

	return result;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 - Decho Corp.

#include "mordor/pch.h"

#include "broker.h"

#include "mordor/streams/pipe.h"
#include "mordor/streams/socket.h"
#include "mordor/streams/ssl.h"
#include "proxy.h"

namespace Mordor {
namespace HTTP {

RequestBroker::ptr defaultRequestBroker(IOManager *ioManager,
                                        Scheduler *scheduler,
                                        ConnectionBroker::ptr *connBroker)
{
    StreamBroker::ptr socketBroker(new SocketStreamBroker(ioManager, scheduler));
    StreamBrokerFilter::ptr sslBroker(new SSLStreamBroker(socketBroker));
    ConnectionCache::ptr connectionBroker(new ConnectionCache(sslBroker));
    if (connBroker != NULL)
        *connBroker = connectionBroker;
    RequestBroker::ptr requestBroker(new BaseRequestBroker(connectionBroker));

    socketBroker.reset(new ProxyStreamBroker(socketBroker, requestBroker));
    sslBroker->parent(StreamBroker::weak_ptr(socketBroker));
    connectionBroker.reset(new ProxyConnectionBroker(connectionBroker));
    requestBroker.reset(new BaseRequestBroker(connectionBroker));
    return requestBroker;
}

StreamBroker::ptr
StreamBrokerFilter::parent()
{
    if (m_parent)
        return m_parent;
    return StreamBroker::ptr(m_weakParent);
}

Stream::ptr
SocketStreamBroker::getStream(const URI &uri)
{
    if (m_cancelled)
        MORDOR_THROW_EXCEPTION(OperationAbortedException());

    MORDOR_ASSERT(uri.authority.hostDefined());
    MORDOR_ASSERT(uri.authority.portDefined() || uri.schemeDefined());
    std::ostringstream os;
    os << uri.authority.host();
    if (uri.authority.portDefined())
        os << ":" << uri.authority.port();
    else if (uri.schemeDefined())
        os << ":" << uri.scheme();
    std::vector<Address::ptr> addresses;
    {
        SchedulerSwitcher switcher(m_scheduler);
        addresses = Address::lookup(os.str(), AF_UNSPEC, SOCK_STREAM);
    }
    Socket::ptr socket;
    for (std::vector<Address::ptr>::const_iterator it(addresses.begin());
        it != addresses.end();
        ) {
        if (m_ioManager)
            socket = (*it)->createSocket(*m_ioManager);
        else
            socket = (*it)->createSocket();
        std::list<Socket::ptr>::iterator it2;
        {
            boost::mutex::scoped_lock lock(m_mutex);
            if (m_cancelled)
                MORDOR_THROW_EXCEPTION(OperationAbortedException());
            m_pending.push_back(socket);
            it2 = m_pending.end();
            --it2;
        }
        socket->sendTimeout(connectTimeout);
        try {
            socket->connect(*it);
            socket->sendTimeout(sendTimeout);
            socket->receiveTimeout(receiveTimeout);
            boost::mutex::scoped_lock lock(m_mutex);
            m_pending.erase(it2);
            break;
        } catch (...) {
            boost::mutex::scoped_lock lock(m_mutex);
            m_pending.erase(it2);
            if (++it == addresses.end())
                throw;
        }
    }
    Stream::ptr stream(new SocketStream(socket));
    return stream;
}

void
SocketStreamBroker::cancelPending()
{
    boost::mutex::scoped_lock lock(m_mutex);
    m_cancelled = true;
    for (std::list<Socket::ptr>::iterator it(m_pending.begin());
        it != m_pending.end();
        ++it) {
        (*it)->cancelConnect();
        (*it)->cancelSend();
        (*it)->cancelReceive();
    }
}

Stream::ptr
SSLStreamBroker::getStream(const URI &uri)
{
    Stream::ptr result = parent()->getStream(uri);
    if (uri.schemeDefined() && uri.scheme() == "https") {
        SSLStream::ptr sslStream(new SSLStream(result, true, true, m_sslCtx));
        result = sslStream;
        sslStream->connect();
        if (m_verifySslCert)
            sslStream->verifyPeerCertificate();
        if (m_verifySslCertHost)
            sslStream->verifyPeerCertificate(uri.authority.host());
    }
    return result;
}

static bool least(const ClientConnection::ptr &lhs,
                  const ClientConnection::ptr &rhs)
{
    if (lhs && rhs)
        return lhs->outstandingRequests() <
            rhs->outstandingRequests();
    if (!lhs)
        return false;
    if (!rhs)
        return true;
    MORDOR_NOTREACHED();
}

std::pair<ClientConnection::ptr, bool>
ConnectionCache::getConnection(const URI &uri, bool forceNewConnection)
{
    URI schemeAndAuthority;
    std::map<URI, std::pair<ConnectionList,
        boost::shared_ptr<FiberCondition> > >::iterator it, it3;
    ConnectionList::iterator it2;
    std::pair<ClientConnection::ptr, bool> result;
    {
        FiberMutex::ScopedLock lock(m_mutex);
        // Clean out any dead conns
        for (it = m_conns.begin(); it != m_conns.end();) {
            for (it2 = it->second.first.begin();
                it2 != it->second.first.end();) {
                if (*it2 && !(*it2)->newRequestsAllowed()) {
                    it2 = it->second.first.erase(it2);
                } else {
                    ++it2;
                }
            }
            if (it->second.first.empty()) {
                it3 = it;
                ++it3;
                m_conns.erase(it);
                it = it3;
            } else {
                ++it;
            }
        }

        schemeAndAuthority = uri;
        schemeAndAuthority.path = URI::Path();
        schemeAndAuthority.queryDefined(false);
        schemeAndAuthority.fragmentDefined(false);

        if (!forceNewConnection) {
            while (true) {
                // Look for an existing connection
                it = m_conns.find(schemeAndAuthority);
                if (it != m_conns.end() &&
                    !it->second.first.empty() &&
                    it->second.first.size() >= m_connectionsPerHost) {
                    ConnectionList &connsForThisUri = it->second.first;
                    // Assign it2 to point to the connection with the
                    // least number of outstanding requests
                    it2 = std::min_element(connsForThisUri.begin(),
                        connsForThisUri.end(), &least);
                    // No connection has completed yet (but it's in progress)
                    if (!*it2) {
                        // Wait for somebody to let us try again
                        it->second.second->wait();
                    } else {
                        // Return the existing, completed connection
                        return std::make_pair(*it2, false);
                    }
                } else {
                    // No existing connections
                    break;
                }
            }
        }
        // Create a new (blank) connection
        m_conns[schemeAndAuthority].first.push_back(ClientConnection::ptr());
        if (it == m_conns.end()) {
            // This is the first connection for this schemeAndAuthority
            it = m_conns.find(schemeAndAuthority);
            // (double-check)
            if (!it->second.second)
                // Create the condition variable for it
                it->second.second.reset(new FiberCondition(m_mutex));
        }
    }

    // Establish a new connection
    try {
        Stream::ptr stream = m_streamBroker->getStream(schemeAndAuthority);
        {
            FiberMutex::ScopedLock lock(m_mutex);
            result = std::make_pair(ClientConnection::ptr(
                new ClientConnection(stream)), false);
            // Assign this connection to the first blank connection for this
            // schemeAndAuthority
            // it should still be valid, even if the map changed
            for (it2 = it->second.first.begin();
                it2 != it->second.first.end();
                ++it2) {
                if (!*it2) {
                    *it2 = result.first;
                    break;
                }
            }
            // Unblock all waiters for them to choose an existing connection
            it->second.second->broadcast();
        }
    } catch (...) {
        FiberMutex::ScopedLock lock(m_mutex);
        // This connection attempt failed; remove the first blank connection
        // for this schemeAndAuthority to let someone else try to establish a
        // connection
        // it should still be valid, even if the map changed
        for (it2 = it->second.first.begin();
            it2 != it->second.first.end();
            ++it2) {
            if (!*it2) {
                it->second.first.erase(it2);
                break;
            }
        }
        it->second.second->broadcast();
        if (it->second.first.empty())
            m_conns.erase(it);
        throw;
    }
    return result;
}

void
ConnectionCache::closeConnections()
{
    m_streamBroker->cancelPending();
    FiberMutex::ScopedLock lock(m_mutex);
    std::map<URI, std::pair<ConnectionList,
        boost::shared_ptr<FiberCondition> > >::iterator it;
    for (it = m_conns.begin(); it != m_conns.end(); ++it) {
        it->second.second->broadcast();
        for (ConnectionList::iterator it2 = it->second.first.begin();
            it2 != it->second.first.end();
            ++it2) {
            if (*it2) {
                Stream::ptr connStream = (*it2)->stream();
                connStream->cancelRead();
                connStream->cancelWrite();
            }
        }
    }
    m_conns.clear();
}

std::pair<ClientConnection::ptr, bool>
MockConnectionBroker::getConnection(const URI &uri, bool forceNewConnection)
{
    ConnectionCache::iterator it = m_conns.find(uri);
    if (it != m_conns.end() && !it->second.first->newRequestsAllowed()) {
        m_conns.erase(it);
        it = m_conns.end();
    }
    if (it == m_conns.end()) {
        std::pair<Stream::ptr, Stream::ptr> pipes = pipeStream();
        ClientConnection::ptr client(
            new ClientConnection(pipes.first));
        ServerConnection::ptr server(
            new ServerConnection(pipes.second, boost::bind(m_dg,
                uri, _1)));
        Scheduler::getThis()->schedule(Fiber::ptr(new Fiber(boost::bind(
            &ServerConnection::processRequests, server))));
        m_conns[uri] = std::make_pair(client, server);
        return std::make_pair(client, false);
    }
    return std::make_pair(it->second.first, false);
}

RequestBroker::ptr
RequestBrokerFilter::parent()
{
    if (m_parent)
        return m_parent;
    return RequestBroker::ptr(m_weakParent);
}

ClientRequest::ptr
BaseRequestBroker::request(Request &requestHeaders, bool forceNewConnection,
                           boost::function<void (ClientRequest::ptr)> bodyDg)
{
    URI &currentUri = requestHeaders.requestLine.uri;
    URI originalUri = currentUri;
    bool connect = requestHeaders.requestLine.method == CONNECT;
    MORDOR_ASSERT(connect || originalUri.authority.hostDefined());
    MORDOR_ASSERT(!connect || !requestHeaders.request.host.empty());
    if (!connect)
        requestHeaders.request.host = originalUri.authority.host();
    else
        originalUri = "http://" + requestHeaders.request.host;
    while (true) {
        std::pair<ClientConnection::ptr, bool> conn =
            m_connectionBroker->getConnection(
                connect ? originalUri : currentUri, forceNewConnection);
        try {
            // Fix up our URI for use with/without proxies
            if (!connect) {
                if (conn.second && !currentUri.authority.hostDefined()) {
                    currentUri.authority = originalUri.authority;
                    if (originalUri.schemeDefined())
                        currentUri.scheme(originalUri.scheme());
                } else if (!conn.second && currentUri.authority.hostDefined()) {
                    currentUri.schemeDefined(false);
                    currentUri.authority.hostDefined(false);
                }
            }

            ClientRequest::ptr request = conn.first->request(requestHeaders);
            if (bodyDg)
                bodyDg(request);
            if (!connect)
                currentUri = originalUri;
            // Force reading the response here to check for connectivity problems
            request->response();
            return request;
        } catch (SocketException &) {
            if (!m_retry) {
                if (!connect)
                    currentUri = originalUri;
                throw;
            }
            continue;
        } catch (PriorRequestFailedException &) {
            if (!m_retry) {
                if (!connect)
                    currentUri = originalUri;
                throw;
            }
            continue;
        } catch (...) {
            if (!connect)
                currentUri = originalUri;
            throw;
        }
        MORDOR_NOTREACHED();
    }
}

ClientRequest::ptr
RedirectRequestBroker::request(Request &requestHeaders, bool forceNewConnection,
                               boost::function<void (ClientRequest::ptr)> bodyDg)
{
    URI &currentUri = requestHeaders.requestLine.uri;
    URI originalUri = currentUri;
    std::list<URI> uris;
    uris.push_back(originalUri);
    size_t redirects = 0;
    while (true) {
        try {
            ClientRequest::ptr request = parent()->request(requestHeaders,
                forceNewConnection, bodyDg);
            bool handleRedirect = false;
            switch (request->response().status.status)
            {
            case FOUND:
                handleRedirect = m_handle302;
                break;
            case TEMPORARY_REDIRECT:
                handleRedirect = m_handle307;
                break;
            case MOVED_PERMANENTLY:
                handleRedirect = m_handle301;
                break;
            default:
                currentUri = originalUri;
                return request;
            }
            if (handleRedirect) {
                if (++redirects == m_maxRedirects)
                    MORDOR_THROW_EXCEPTION(CircularRedirectException(originalUri));
                currentUri = URI::transform(currentUri,
                    request->response().response.location);
                if (std::find(uris.begin(), uris.end(), currentUri)
                    != uris.end())
                    MORDOR_THROW_EXCEPTION(CircularRedirectException(originalUri));
                uris.push_back(currentUri);
                if (request->response().status.status == MOVED_PERMANENTLY)
                    originalUri = currentUri;
                request->finish();
                continue;
            } else {
                currentUri = originalUri;
                return request;
            }
        } catch (...) {
            currentUri = originalUri;
            throw;
        }
        MORDOR_NOTREACHED();
    }
}

ClientRequest::ptr
UserAgentRequestBroker::request(Request &requestHeaders, bool forceNewConnection,
                               boost::function<void (ClientRequest::ptr)> bodyDg)
{
    requestHeaders.request.userAgent = m_userAgent;
    return parent()->request(requestHeaders, forceNewConnection, bodyDg);
}

}}
<commit_msg>Reset the URI before retrying in BaseRequestBroker<commit_after>// Copyright (c) 2009 - Decho Corp.

#include "mordor/pch.h"

#include "broker.h"

#include "mordor/streams/pipe.h"
#include "mordor/streams/socket.h"
#include "mordor/streams/ssl.h"
#include "proxy.h"

namespace Mordor {
namespace HTTP {

RequestBroker::ptr defaultRequestBroker(IOManager *ioManager,
                                        Scheduler *scheduler,
                                        ConnectionBroker::ptr *connBroker)
{
    StreamBroker::ptr socketBroker(new SocketStreamBroker(ioManager, scheduler));
    StreamBrokerFilter::ptr sslBroker(new SSLStreamBroker(socketBroker));
    ConnectionCache::ptr connectionBroker(new ConnectionCache(sslBroker));
    if (connBroker != NULL)
        *connBroker = connectionBroker;
    RequestBroker::ptr requestBroker(new BaseRequestBroker(connectionBroker));

    socketBroker.reset(new ProxyStreamBroker(socketBroker, requestBroker));
    sslBroker->parent(StreamBroker::weak_ptr(socketBroker));
    connectionBroker.reset(new ProxyConnectionBroker(connectionBroker));
    requestBroker.reset(new BaseRequestBroker(connectionBroker));
    return requestBroker;
}

StreamBroker::ptr
StreamBrokerFilter::parent()
{
    if (m_parent)
        return m_parent;
    return StreamBroker::ptr(m_weakParent);
}

Stream::ptr
SocketStreamBroker::getStream(const URI &uri)
{
    if (m_cancelled)
        MORDOR_THROW_EXCEPTION(OperationAbortedException());

    MORDOR_ASSERT(uri.authority.hostDefined());
    MORDOR_ASSERT(uri.authority.portDefined() || uri.schemeDefined());
    std::ostringstream os;
    os << uri.authority.host();
    if (uri.authority.portDefined())
        os << ":" << uri.authority.port();
    else if (uri.schemeDefined())
        os << ":" << uri.scheme();
    std::vector<Address::ptr> addresses;
    {
        SchedulerSwitcher switcher(m_scheduler);
        addresses = Address::lookup(os.str(), AF_UNSPEC, SOCK_STREAM);
    }
    Socket::ptr socket;
    for (std::vector<Address::ptr>::const_iterator it(addresses.begin());
        it != addresses.end();
        ) {
        if (m_ioManager)
            socket = (*it)->createSocket(*m_ioManager);
        else
            socket = (*it)->createSocket();
        std::list<Socket::ptr>::iterator it2;
        {
            boost::mutex::scoped_lock lock(m_mutex);
            if (m_cancelled)
                MORDOR_THROW_EXCEPTION(OperationAbortedException());
            m_pending.push_back(socket);
            it2 = m_pending.end();
            --it2;
        }
        socket->sendTimeout(connectTimeout);
        try {
            socket->connect(*it);
            socket->sendTimeout(sendTimeout);
            socket->receiveTimeout(receiveTimeout);
            boost::mutex::scoped_lock lock(m_mutex);
            m_pending.erase(it2);
            break;
        } catch (...) {
            boost::mutex::scoped_lock lock(m_mutex);
            m_pending.erase(it2);
            if (++it == addresses.end())
                throw;
        }
    }
    Stream::ptr stream(new SocketStream(socket));
    return stream;
}

void
SocketStreamBroker::cancelPending()
{
    boost::mutex::scoped_lock lock(m_mutex);
    m_cancelled = true;
    for (std::list<Socket::ptr>::iterator it(m_pending.begin());
        it != m_pending.end();
        ++it) {
        (*it)->cancelConnect();
        (*it)->cancelSend();
        (*it)->cancelReceive();
    }
}

Stream::ptr
SSLStreamBroker::getStream(const URI &uri)
{
    Stream::ptr result = parent()->getStream(uri);
    if (uri.schemeDefined() && uri.scheme() == "https") {
        SSLStream::ptr sslStream(new SSLStream(result, true, true, m_sslCtx));
        result = sslStream;
        sslStream->connect();
        if (m_verifySslCert)
            sslStream->verifyPeerCertificate();
        if (m_verifySslCertHost)
            sslStream->verifyPeerCertificate(uri.authority.host());
    }
    return result;
}

static bool least(const ClientConnection::ptr &lhs,
                  const ClientConnection::ptr &rhs)
{
    if (lhs && rhs)
        return lhs->outstandingRequests() <
            rhs->outstandingRequests();
    if (!lhs)
        return false;
    if (!rhs)
        return true;
    MORDOR_NOTREACHED();
}

std::pair<ClientConnection::ptr, bool>
ConnectionCache::getConnection(const URI &uri, bool forceNewConnection)
{
    URI schemeAndAuthority;
    std::map<URI, std::pair<ConnectionList,
        boost::shared_ptr<FiberCondition> > >::iterator it, it3;
    ConnectionList::iterator it2;
    std::pair<ClientConnection::ptr, bool> result;
    {
        FiberMutex::ScopedLock lock(m_mutex);
        // Clean out any dead conns
        for (it = m_conns.begin(); it != m_conns.end();) {
            for (it2 = it->second.first.begin();
                it2 != it->second.first.end();) {
                if (*it2 && !(*it2)->newRequestsAllowed()) {
                    it2 = it->second.first.erase(it2);
                } else {
                    ++it2;
                }
            }
            if (it->second.first.empty()) {
                it3 = it;
                ++it3;
                m_conns.erase(it);
                it = it3;
            } else {
                ++it;
            }
        }

        schemeAndAuthority = uri;
        schemeAndAuthority.path = URI::Path();
        schemeAndAuthority.queryDefined(false);
        schemeAndAuthority.fragmentDefined(false);

        if (!forceNewConnection) {
            while (true) {
                // Look for an existing connection
                it = m_conns.find(schemeAndAuthority);
                if (it != m_conns.end() &&
                    !it->second.first.empty() &&
                    it->second.first.size() >= m_connectionsPerHost) {
                    ConnectionList &connsForThisUri = it->second.first;
                    // Assign it2 to point to the connection with the
                    // least number of outstanding requests
                    it2 = std::min_element(connsForThisUri.begin(),
                        connsForThisUri.end(), &least);
                    // No connection has completed yet (but it's in progress)
                    if (!*it2) {
                        // Wait for somebody to let us try again
                        it->second.second->wait();
                    } else {
                        // Return the existing, completed connection
                        return std::make_pair(*it2, false);
                    }
                } else {
                    // No existing connections
                    break;
                }
            }
        }
        // Create a new (blank) connection
        m_conns[schemeAndAuthority].first.push_back(ClientConnection::ptr());
        if (it == m_conns.end()) {
            // This is the first connection for this schemeAndAuthority
            it = m_conns.find(schemeAndAuthority);
            // (double-check)
            if (!it->second.second)
                // Create the condition variable for it
                it->second.second.reset(new FiberCondition(m_mutex));
        }
    }

    // Establish a new connection
    try {
        Stream::ptr stream = m_streamBroker->getStream(schemeAndAuthority);
        {
            FiberMutex::ScopedLock lock(m_mutex);
            result = std::make_pair(ClientConnection::ptr(
                new ClientConnection(stream)), false);
            // Assign this connection to the first blank connection for this
            // schemeAndAuthority
            // it should still be valid, even if the map changed
            for (it2 = it->second.first.begin();
                it2 != it->second.first.end();
                ++it2) {
                if (!*it2) {
                    *it2 = result.first;
                    break;
                }
            }
            // Unblock all waiters for them to choose an existing connection
            it->second.second->broadcast();
        }
    } catch (...) {
        FiberMutex::ScopedLock lock(m_mutex);
        // This connection attempt failed; remove the first blank connection
        // for this schemeAndAuthority to let someone else try to establish a
        // connection
        // it should still be valid, even if the map changed
        for (it2 = it->second.first.begin();
            it2 != it->second.first.end();
            ++it2) {
            if (!*it2) {
                it->second.first.erase(it2);
                break;
            }
        }
        it->second.second->broadcast();
        if (it->second.first.empty())
            m_conns.erase(it);
        throw;
    }
    return result;
}

void
ConnectionCache::closeConnections()
{
    m_streamBroker->cancelPending();
    FiberMutex::ScopedLock lock(m_mutex);
    std::map<URI, std::pair<ConnectionList,
        boost::shared_ptr<FiberCondition> > >::iterator it;
    for (it = m_conns.begin(); it != m_conns.end(); ++it) {
        it->second.second->broadcast();
        for (ConnectionList::iterator it2 = it->second.first.begin();
            it2 != it->second.first.end();
            ++it2) {
            if (*it2) {
                Stream::ptr connStream = (*it2)->stream();
                connStream->cancelRead();
                connStream->cancelWrite();
            }
        }
    }
    m_conns.clear();
}

std::pair<ClientConnection::ptr, bool>
MockConnectionBroker::getConnection(const URI &uri, bool forceNewConnection)
{
    ConnectionCache::iterator it = m_conns.find(uri);
    if (it != m_conns.end() && !it->second.first->newRequestsAllowed()) {
        m_conns.erase(it);
        it = m_conns.end();
    }
    if (it == m_conns.end()) {
        std::pair<Stream::ptr, Stream::ptr> pipes = pipeStream();
        ClientConnection::ptr client(
            new ClientConnection(pipes.first));
        ServerConnection::ptr server(
            new ServerConnection(pipes.second, boost::bind(m_dg,
                uri, _1)));
        Scheduler::getThis()->schedule(Fiber::ptr(new Fiber(boost::bind(
            &ServerConnection::processRequests, server))));
        m_conns[uri] = std::make_pair(client, server);
        return std::make_pair(client, false);
    }
    return std::make_pair(it->second.first, false);
}

RequestBroker::ptr
RequestBrokerFilter::parent()
{
    if (m_parent)
        return m_parent;
    return RequestBroker::ptr(m_weakParent);
}

ClientRequest::ptr
BaseRequestBroker::request(Request &requestHeaders, bool forceNewConnection,
                           boost::function<void (ClientRequest::ptr)> bodyDg)
{
    URI &currentUri = requestHeaders.requestLine.uri;
    URI originalUri = currentUri;
    bool connect = requestHeaders.requestLine.method == CONNECT;
    MORDOR_ASSERT(connect || originalUri.authority.hostDefined());
    MORDOR_ASSERT(!connect || !requestHeaders.request.host.empty());
    if (!connect)
        requestHeaders.request.host = originalUri.authority.host();
    else
        originalUri = "http://" + requestHeaders.request.host;
    while (true) {
        std::pair<ClientConnection::ptr, bool> conn =
            m_connectionBroker->getConnection(
                connect ? originalUri : currentUri, forceNewConnection);
        try {
            // Fix up our URI for use with/without proxies
            if (!connect) {
                if (conn.second && !currentUri.authority.hostDefined()) {
                    currentUri.authority = originalUri.authority;
                    if (originalUri.schemeDefined())
                        currentUri.scheme(originalUri.scheme());
                } else if (!conn.second && currentUri.authority.hostDefined()) {
                    currentUri.schemeDefined(false);
                    currentUri.authority.hostDefined(false);
                }
            }

            ClientRequest::ptr request = conn.first->request(requestHeaders);
            if (bodyDg)
                bodyDg(request);
            if (!connect)
                currentUri = originalUri;
            // Force reading the response here to check for connectivity problems
            request->response();
            return request;
        } catch (SocketException &) {
            if (!connect)
                    currentUri = originalUri;
            if (!m_retry)
                throw;
            continue;
        } catch (PriorRequestFailedException &) {
            if (!connect)
                currentUri = originalUri;
            if (!m_retry)
                throw;
            continue;
        } catch (...) {
            if (!connect)
                currentUri = originalUri;
            throw;
        }
        MORDOR_NOTREACHED();
    }
}

ClientRequest::ptr
RedirectRequestBroker::request(Request &requestHeaders, bool forceNewConnection,
                               boost::function<void (ClientRequest::ptr)> bodyDg)
{
    URI &currentUri = requestHeaders.requestLine.uri;
    URI originalUri = currentUri;
    std::list<URI> uris;
    uris.push_back(originalUri);
    size_t redirects = 0;
    while (true) {
        try {
            ClientRequest::ptr request = parent()->request(requestHeaders,
                forceNewConnection, bodyDg);
            bool handleRedirect = false;
            switch (request->response().status.status)
            {
            case FOUND:
                handleRedirect = m_handle302;
                break;
            case TEMPORARY_REDIRECT:
                handleRedirect = m_handle307;
                break;
            case MOVED_PERMANENTLY:
                handleRedirect = m_handle301;
                break;
            default:
                currentUri = originalUri;
                return request;
            }
            if (handleRedirect) {
                if (++redirects == m_maxRedirects)
                    MORDOR_THROW_EXCEPTION(CircularRedirectException(originalUri));
                currentUri = URI::transform(currentUri,
                    request->response().response.location);
                if (std::find(uris.begin(), uris.end(), currentUri)
                    != uris.end())
                    MORDOR_THROW_EXCEPTION(CircularRedirectException(originalUri));
                uris.push_back(currentUri);
                if (request->response().status.status == MOVED_PERMANENTLY)
                    originalUri = currentUri;
                request->finish();
                continue;
            } else {
                currentUri = originalUri;
                return request;
            }
        } catch (...) {
            currentUri = originalUri;
            throw;
        }
        MORDOR_NOTREACHED();
    }
}

ClientRequest::ptr
UserAgentRequestBroker::request(Request &requestHeaders, bool forceNewConnection,
                               boost::function<void (ClientRequest::ptr)> bodyDg)
{
    requestHeaders.request.userAgent = m_userAgent;
    return parent()->request(requestHeaders, forceNewConnection, bodyDg);
}

}}
<|endoftext|>