<commit_before>// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file was forked off the Mac port.

#include "webkit/tools/test_shell/test_webview_delegate.h"

#include <gtk/gtk.h>

#include "base/gfx/point.h"
#include "base/string_util.h"
#include "net/base/net_errors.h"
#include "chrome/common/page_transition_types.h"
#include "webkit/glue/webcursor.h"
#include "webkit/glue/webdatasource.h"
#include "webkit/glue/webdropdata.h"
#include "webkit/glue/weberror.h"
#include "webkit/glue/webframe.h"
#include "webkit/glue/webpreferences.h"
#include "webkit/glue/weburlrequest.h"
#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/webview.h"
#include "webkit/glue/window_open_disposition.h"
#include "webkit/tools/test_shell/test_navigation_controller.h"
#include "webkit/tools/test_shell/test_shell.h"

// WebViewDelegate -----------------------------------------------------------

TestWebViewDelegate::~TestWebViewDelegate() {
}

WebPluginDelegate* TestWebViewDelegate::CreatePluginDelegate(
    WebView* webview,
    const GURL& url,
    const std::string& mime_type,
    const std::string& clsid,
    std::string* actual_mime_type) {
  NOTIMPLEMENTED();
  return NULL;
}

void TestWebViewDelegate::ShowJavaScriptAlert(const std::wstring& message) {
  // TODO(port): remove GTK_WINDOW bit after gfx::WindowHandle is fixed.
  GtkWidget* dialog = gtk_message_dialog_new(
      GTK_WINDOW(shell_->mainWnd()), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO,
      GTK_BUTTONS_OK, "%s", WideToUTF8(message).c_str());
  gtk_window_set_title(GTK_WINDOW(dialog), "JavaScript Alert");
  gtk_dialog_run(GTK_DIALOG(dialog));  // Runs a nested message loop.
  gtk_widget_destroy(dialog);
}

void TestWebViewDelegate::Show(WebWidget* webwidget,
                               WindowOpenDisposition disposition) {
  WebWidgetHost* host = GetHostForWidget(webwidget);
  GtkWidget* drawing_area = host->window_handle();
  GtkWidget* window =
      gtk_widget_get_parent(gtk_widget_get_parent(drawing_area));
  gtk_widget_show_all(window);
}

void TestWebViewDelegate::CloseWidgetSoon(WebWidget* webwidget) {
  if (webwidget == shell_->popup()) {
    shell_->ClosePopup();
  } else {
    // In the Windows code, this closes the main window. However, it's not
    // clear when this would ever be needed by WebKit.
    NOTIMPLEMENTED();
  }
}

void TestWebViewDelegate::SetCursor(WebWidget* webwidget,
                                    const WebCursor& cursor) {
  GdkCursorType cursor_type = cursor.GetCursorType();
  GdkCursor* gdk_cursor;
  if (cursor_type == GDK_CURSOR_IS_PIXMAP) {
    // TODO(port): WebKit bug https://bugs.webkit.org/show_bug.cgi?id=16388 is
    // that calling gdk_window_set_cursor repeatedly is expensive.  We should
    // avoid it here where possible.
    gdk_cursor = cursor.GetCustomCursor();
  } else {
    // Optimize the common case, where the cursor hasn't changed.
    // However, we can switch between different pixmaps, so only on the
    // non-pixmap branch.
    if (cursor_type_ == cursor_type)
      return;
    gdk_cursor = gdk_cursor_new(cursor_type);
  }
  cursor_type_ = cursor_type;
  gdk_window_set_cursor(shell_->webViewWnd()->window, gdk_cursor);
  // The window now owns the cursor.
  gdk_cursor_unref(gdk_cursor);
}

void TestWebViewDelegate::GetWindowRect(WebWidget* webwidget,
                                        gfx::Rect* out_rect) {
  DCHECK(out_rect);
  WebWidgetHost* host = GetHostForWidget(webwidget);
  GtkWidget* drawing_area = host->window_handle();
  GtkWidget* vbox = gtk_widget_get_parent(drawing_area);
  GtkWidget* window = gtk_widget_get_parent(vbox);

  gint x, y;
  gtk_window_get_position(GTK_WINDOW(window), &x, &y);
  x += vbox->allocation.x + drawing_area->allocation.x;
  y += vbox->allocation.y + drawing_area->allocation.y;

  out_rect->SetRect(x, y, drawing_area->allocation.width,
                    drawing_area->allocation.height);
}

void TestWebViewDelegate::SetWindowRect(WebWidget* webwidget,
                                        const gfx::Rect& rect) {
  if (webwidget == shell_->webView()) {
    // ignored
  } else if (webwidget == shell_->popup()) {
    WebWidgetHost* host = GetHostForWidget(webwidget);
    GtkWidget* drawing_area = host->window_handle();
    GtkWidget* window =
        gtk_widget_get_parent(gtk_widget_get_parent(drawing_area));
    gtk_window_resize(GTK_WINDOW(window), rect.width(), rect.height());
    gtk_window_move(GTK_WINDOW(window), rect.x(), rect.y());
  }
}

void TestWebViewDelegate::GetRootWindowRect(WebWidget* webwidget,
                                            gfx::Rect* out_rect) {
  if (WebWidgetHost* host = GetHostForWidget(webwidget)) {
    // We are being asked for the x/y and width/height of the entire browser
    // window.  This means the x/y is the distance from the corner of the
    // screen, and the width/height is the size of the entire browser window.
    // For example, this is used to implement window.screenX and window.screenY.
    GtkWidget* drawing_area = host->window_handle();
    GtkWidget* window =
        gtk_widget_get_parent(gtk_widget_get_parent(drawing_area));
    gint x, y, width, height;
    gtk_window_get_position(GTK_WINDOW(window), &x, &y);
    gtk_window_get_size(GTK_WINDOW(window), &width, &height);
    out_rect->SetRect(x, y, width, height);
  }
}

void TestWebViewDelegate::RunModal(WebWidget* webwidget) {
  NOTIMPLEMENTED();
}

// Private methods -----------------------------------------------------------

void TestWebViewDelegate::SetPageTitle(const std::wstring& title) {
  gtk_window_set_title(GTK_WINDOW(shell_->mainWnd()),
                       ("Test Shell - " + WideToUTF8(title)).c_str());
}

void TestWebViewDelegate::SetAddressBarURL(const GURL& url) {
  gtk_entry_set_text(GTK_ENTRY(shell_->editWnd()), url.spec().c_str());
}
<commit_msg>Implement window closing.<commit_after>// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file was forked off the Mac port.

#include "webkit/tools/test_shell/test_webview_delegate.h"

#include <gtk/gtk.h>

#include "base/gfx/point.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "net/base/net_errors.h"
#include "chrome/common/page_transition_types.h"
#include "webkit/glue/webcursor.h"
#include "webkit/glue/webdatasource.h"
#include "webkit/glue/webdropdata.h"
#include "webkit/glue/weberror.h"
#include "webkit/glue/webframe.h"
#include "webkit/glue/webpreferences.h"
#include "webkit/glue/weburlrequest.h"
#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/webview.h"
#include "webkit/glue/window_open_disposition.h"
#include "webkit/tools/test_shell/test_navigation_controller.h"
#include "webkit/tools/test_shell/test_shell.h"

// WebViewDelegate -----------------------------------------------------------

TestWebViewDelegate::~TestWebViewDelegate() {
}

WebPluginDelegate* TestWebViewDelegate::CreatePluginDelegate(
    WebView* webview,
    const GURL& url,
    const std::string& mime_type,
    const std::string& clsid,
    std::string* actual_mime_type) {
  NOTIMPLEMENTED();
  return NULL;
}

void TestWebViewDelegate::ShowJavaScriptAlert(const std::wstring& message) {
  // TODO(port): remove GTK_WINDOW bit after gfx::WindowHandle is fixed.
  GtkWidget* dialog = gtk_message_dialog_new(
      GTK_WINDOW(shell_->mainWnd()), GTK_DIALOG_MODAL, GTK_MESSAGE_INFO,
      GTK_BUTTONS_OK, "%s", WideToUTF8(message).c_str());
  gtk_window_set_title(GTK_WINDOW(dialog), "JavaScript Alert");
  gtk_dialog_run(GTK_DIALOG(dialog));  // Runs a nested message loop.
  gtk_widget_destroy(dialog);
}

void TestWebViewDelegate::Show(WebWidget* webwidget,
                               WindowOpenDisposition disposition) {
  WebWidgetHost* host = GetHostForWidget(webwidget);
  GtkWidget* drawing_area = host->window_handle();
  GtkWidget* window =
      gtk_widget_get_parent(gtk_widget_get_parent(drawing_area));
  gtk_widget_show_all(window);
}

void TestWebViewDelegate::CloseWidgetSoon(WebWidget* webwidget) {
  if (webwidget == shell_->webView()) {
    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction(
        &gtk_widget_destroy, GTK_WIDGET(shell_->mainWnd())));
  } else if (webwidget == shell_->popup()) {
    shell_->ClosePopup();
  }
}

void TestWebViewDelegate::SetCursor(WebWidget* webwidget,
                                    const WebCursor& cursor) {
  GdkCursorType cursor_type = cursor.GetCursorType();
  GdkCursor* gdk_cursor;
  if (cursor_type == GDK_CURSOR_IS_PIXMAP) {
    // TODO(port): WebKit bug https://bugs.webkit.org/show_bug.cgi?id=16388 is
    // that calling gdk_window_set_cursor repeatedly is expensive.  We should
    // avoid it here where possible.
    gdk_cursor = cursor.GetCustomCursor();
  } else {
    // Optimize the common case, where the cursor hasn't changed.
    // However, we can switch between different pixmaps, so only on the
    // non-pixmap branch.
    if (cursor_type_ == cursor_type)
      return;
    gdk_cursor = gdk_cursor_new(cursor_type);
  }
  cursor_type_ = cursor_type;
  gdk_window_set_cursor(shell_->webViewWnd()->window, gdk_cursor);
  // The window now owns the cursor.
  gdk_cursor_unref(gdk_cursor);
}

void TestWebViewDelegate::GetWindowRect(WebWidget* webwidget,
                                        gfx::Rect* out_rect) {
  DCHECK(out_rect);
  WebWidgetHost* host = GetHostForWidget(webwidget);
  GtkWidget* drawing_area = host->window_handle();
  GtkWidget* vbox = gtk_widget_get_parent(drawing_area);
  GtkWidget* window = gtk_widget_get_parent(vbox);

  gint x, y;
  gtk_window_get_position(GTK_WINDOW(window), &x, &y);
  x += vbox->allocation.x + drawing_area->allocation.x;
  y += vbox->allocation.y + drawing_area->allocation.y;

  out_rect->SetRect(x, y, drawing_area->allocation.width,
                    drawing_area->allocation.height);
}

void TestWebViewDelegate::SetWindowRect(WebWidget* webwidget,
                                        const gfx::Rect& rect) {
  if (webwidget == shell_->webView()) {
    // ignored
  } else if (webwidget == shell_->popup()) {
    WebWidgetHost* host = GetHostForWidget(webwidget);
    GtkWidget* drawing_area = host->window_handle();
    GtkWidget* window =
        gtk_widget_get_parent(gtk_widget_get_parent(drawing_area));
    gtk_window_resize(GTK_WINDOW(window), rect.width(), rect.height());
    gtk_window_move(GTK_WINDOW(window), rect.x(), rect.y());
  }
}

void TestWebViewDelegate::GetRootWindowRect(WebWidget* webwidget,
                                            gfx::Rect* out_rect) {
  if (WebWidgetHost* host = GetHostForWidget(webwidget)) {
    // We are being asked for the x/y and width/height of the entire browser
    // window.  This means the x/y is the distance from the corner of the
    // screen, and the width/height is the size of the entire browser window.
    // For example, this is used to implement window.screenX and window.screenY.
    GtkWidget* drawing_area = host->window_handle();
    GtkWidget* window =
        gtk_widget_get_parent(gtk_widget_get_parent(drawing_area));
    gint x, y, width, height;
    gtk_window_get_position(GTK_WINDOW(window), &x, &y);
    gtk_window_get_size(GTK_WINDOW(window), &width, &height);
    out_rect->SetRect(x, y, width, height);
  }
}

void TestWebViewDelegate::RunModal(WebWidget* webwidget) {
  NOTIMPLEMENTED();
}

// Private methods -----------------------------------------------------------

void TestWebViewDelegate::SetPageTitle(const std::wstring& title) {
  gtk_window_set_title(GTK_WINDOW(shell_->mainWnd()),
                       ("Test Shell - " + WideToUTF8(title)).c_str());
}

void TestWebViewDelegate::SetAddressBarURL(const GURL& url) {
  gtk_entry_set_text(GTK_ENTRY(shell_->editWnd()), url.spec().c_str());
}
<|endoftext|>


<commit_before>/* Copyright (c) 2009-2014 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/**
 * \file
 * This file provides the main program for RAMCloud storage servers.
 */

#include "Context.h"
#include "CoordinatorSession.h"
#if INFINIBAND
#include "InfRcTransport.h"
#endif
#include "OptionParser.h"
#include "PortAlarm.h"
#include "Server.h"
#include "ShortMacros.h"
#include "TransportManager.h"

int
main(int argc, char *argv[])
{
    using namespace RAMCloud;
    signal(SIGTERM, Perf::terminationHandler);
    Logger::installCrashBacktraceHandlers();
    Context context(true);
    try {
        ServerConfig config = ServerConfig::forExecution();
        string masterTotalMemory, hashTableMemory;

        bool masterOnly;
        bool backupOnly;

        OptionsDescription serverOptions("Server");
        serverOptions.add_options()
            ("backupInMemory,m",
             ProgramOptions::bool_switch(&config.backup.inMemory),
             "Backup will store segment replicas in memory")
            ("backupOnly,B",
             ProgramOptions::bool_switch(&backupOnly),
             "The server should run the backup service only (no master)")
            ("backupStrategy",
             ProgramOptions::value<int>(&config.backup.strategy)->
               default_value(RANDOM_REFINE_AVG),
             "0 random refine min, 1 random refine avg, 2 even distribution, "
             "3 uniform random")
            ("cleanerBalancer",
             ProgramOptions::value<string>(&config.master.cleanerBalancer)->
                default_value("tombstoneRatio:0.40"),
             "Which balancing algorithm to use to schedule cleaning on disk "
             "and in-memory compaction, as well as how to orchestrate multiple "
             "cleaner threads. You will almost certainly want to use the "
             "default value. Currently the only other option is \"fixed:X\", "
             "where 0 <= X <= 100 represents the percentage of CPU time the "
             "disk cleaner will be limited to (the rest is for compaction).")
            ("disableLogCleaner,d",
             ProgramOptions::bool_switch(&config.master.disableLogCleaner),
             "Disable the log cleaner entirely. You will eventually run out "
             "of memory, but at least you can do so faster this way.")
            ("disableInMemoryCleaning,D",
             ProgramOptions::bool_switch(
                &config.master.disableInMemoryCleaning),
             "Disable the in-memory cleaning portion of the log cleaner. When "
             "turned off, the cleaner will always clean both in memory and on "
             "backup disks at the same time.")
            ("diskExpansionFactor,E",
             ProgramOptions::value<double>(&config.master.diskExpansionFactor)->
                default_value(2.0),
             "Factor (>= 1.0) controlling how much backup disk space this "
             "master will use beyond its in-memory log size. For example, if "
             "the master has memory for 100 full segments and the expansion "
             "factor is 2.0, it will place up to 200 segments (each replicated "
             "R times) on backups.")
            ("file,f",
             ProgramOptions::value<string>(&config.backup.file)->
                default_value("/var/tmp/backup.log"),
             "The file path to the backup storage.")
            ("hashTableMemory,h",
             ProgramOptions::value<string>(&hashTableMemory)->
                default_value("10%"),
             "Percentage or megabytes of master memory allocated to "
             "the hash table")
            ("masterOnly,M",
             ProgramOptions::bool_switch(&masterOnly),
             "The server should run the master service only (no backup)")
            ("totalMasterMemory,t",

             // Note: we have tried changing the default value below to
             // something that would make sense in production (80%?), but
             // as of 6/2014 that causes too many problems in test and
             // development environments (e.g. hooks/pre-commit will take
             // forever, and if two people do this, rcmaster will run out
             // of memory).
             ProgramOptions::value<string>(&masterTotalMemory)->
                default_value("500"),
             "Percentage or megabytes of system memory for master log & "
             "hash table")
            ("replicas,r",
             ProgramOptions::value<uint32_t>(&config.master.numReplicas),
             "Number of backup copies to make for each segment")
            ("useMinCopysets",
             ProgramOptions::value<bool>(&config.master.useMinCopysets)->
                default_value(false),
             "Whether to use MinCopysets or random replication")
            ("allowLocalBackup",
             ProgramOptions::bool_switch(&config.master.allowLocalBackup),
             "Allow replication to local backup")
            ("segmentFrames",
             ProgramOptions::value<uint32_t>(&config.backup.numSegmentFrames)->
                default_value(512),
             "Number of segment frames in backup storage")
            ("maxNonVolatileBuffers",
             ProgramOptions::value<uint32_t>(
               &config.backup.maxNonVolatileBuffers)->default_value(0),
             "Maximum number of segments the backup will buffer in memory. The "
             "0 value (default) is special: it tells the server to set the "
             "limit equal to the \"segmentFrames\" value, effectively making "
             "buffering unlimited.")
            ("detectFailures",
             ProgramOptions::value<bool>(&config.detectFailures)->
                default_value(true),
             "Whether to use the randomized failure detector")
            ("writeCostThreshold,w",
             ProgramOptions::value<uint32_t>(
                &config.master.cleanerWriteCostThreshold)->default_value(8),
             "If in-memory cleaning is enabled, do disk cleaning when the "
             "write cost of memory freed by the in-memory cleaner exceeds "
             "this value. Lower values cause the disk cleaner to run more "
             "frequently. Higher values do more in-memory cleaning and "
             "reduce the amount of backup disk bandwidth used during disk "
             "cleaning.")
            ("sync",
             ProgramOptions::bool_switch(&config.backup.sync),
             "Make all updates completely synchronous all the way down to "
             "stable storage.")
            ("masterServiceThreads",
             ProgramOptions::value<uint32_t>(
                &config.master.masterServiceThreadCount)->default_value(3),
             "The number of threads in MasterService determines the maximum "
             "number of client RPCs that may be processed in parallel. "
             "Increasing this value will use more cores and may improve client "
             "throuphput, especially for reads.")
            ("logCleanerThreads",
             ProgramOptions::value<uint32_t>(
                &config.master.cleanerThreadCount)->default_value(1),
             "The number of cleaner threads controls the amount of parallelism "
             "in the cleaner. More threads will use more cores, but may be "
             "able to better keep up with high write rates.")
            ("backupWriteRateLimit",
             ProgramOptions::value<size_t>(
                &config.backup.writeRateLimit)->default_value(0),
             "If non-0, specifies the maximum number of megabytes per second "
             "of bandwidth this backup should use. Useful for artificially "
             "restricting bandwidth when measuring various parts of the "
             "system.");

        OptionParser optionParser(serverOptions, argc, argv);

        // Log all the command-line arguments.
        string args;
        for (int i = 0; i < argc; i++) {
            if (i != 0)
                args.append(" ");
            args.append(argv[i]);
        }
        LOG(NOTICE, "Command line: %s", args.c_str());

        if (masterOnly && backupOnly)
            DIE("Can't specify both -B and -M options");

        if (masterOnly) {
            config.services = {WireFormat::MASTER_SERVICE,
                               WireFormat::MEMBERSHIP_SERVICE,
                               WireFormat::PING_SERVICE};
        } else if (backupOnly) {
            config.services = {WireFormat::BACKUP_SERVICE,
                               WireFormat::MEMBERSHIP_SERVICE,
                               WireFormat::PING_SERVICE};
        } else {
            config.services = {WireFormat::MASTER_SERVICE,
                               WireFormat::BACKUP_SERVICE,
                               WireFormat::MEMBERSHIP_SERVICE,
                               WireFormat::PING_SERVICE};
        }

        const string localLocator = optionParser.options.getLocalLocator();

#if INFINIBAND
        InfRcTransport::setName(localLocator.c_str());
#endif
        context.transportManager->setSessionTimeout(
                optionParser.options.getSessionTimeout());
        context.transportManager->initialize(localLocator.c_str());
        // Transports may augment the local locator somewhat.
        // Make sure the server is aware of that augmented locator.
        config.localLocator =
            context.transportManager->getListeningLocatorsString();
        LOG(NOTICE, "%s: Listening on %s",
            config.services.toString().c_str(), config.localLocator.c_str());

        config.coordinatorLocator =
            optionParser.options.getExternalStorageLocator();
        if (config.coordinatorLocator.size() == 0) {
            config.coordinatorLocator =
                optionParser.options.getCoordinatorLocator();
        }
        config.clusterName = optionParser.options.getClusterName();
        context.coordinatorSession->setLocation(
                config.coordinatorLocator.c_str(),
                config.clusterName.c_str());

        // Get Default Backup Configuration from Coordinator.
        if (config.services.has(WireFormat::BACKUP_SERVICE)) {
            ProtoBuf::ServerConfig_Backup backupConfig;
            CoordinatorClient::getBackupConfig(&context, backupConfig);
            config.backup.deserialize(backupConfig);
        }

        // Get Default Master Configuration from Coordinator.
        if (config.services.has(WireFormat::MASTER_SERVICE)) {
            ProtoBuf::ServerConfig_Master masterConfig;
            CoordinatorClient::getMasterConfig(&context, masterConfig);
            config.master.deserialize(masterConfig);
        }

        // Re-parse the options to override coordinator provided defaults.
        OptionParser optionReparser(serverOptions, argc, argv);

        if (!backupOnly) {
            LOG(NOTICE, "Using %u backups", config.master.numReplicas);
            config.setLogAndHashTableSize(masterTotalMemory, hashTableMemory);
        }

        // Set PortTimeout and start portTimer
        LOG(NOTICE, "PortTimeOut=%d", optionParser.options.getPortTimeout());
        context.portAlarmTimer->setPortTimeout(
            optionParser.options.getPortTimeout());

        Server server(&context, &config);
        server.run(); // Never returns except for exceptions.

        return 0;
    } catch (const Exception& e) {
        LOG(ERROR, "Fatal error in server at %s: %s",
            context.transportManager->getListeningLocatorsString().c_str(),
            e.what());
        return 1;
    } catch (const std::exception& e) {
        LOG(ERROR, "Fatal error in server at %s: %s",
            context.transportManager->getListeningLocatorsString().c_str(),
            e.what());
        return 1;
    } catch (...) {
        LOG(ERROR, "Unknown fatal error in server at %s",
            context.transportManager->getListeningLocatorsString().c_str());
        return 1;
    }
}
<commit_msg>Rearranged list of command-line options in alphabetical order.<commit_after>/* Copyright (c) 2009-2014 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/**
 * \file
 * This file provides the main program for RAMCloud storage servers.
 */

#include "Context.h"
#include "CoordinatorSession.h"
#if INFINIBAND
#include "InfRcTransport.h"
#endif
#include "OptionParser.h"
#include "PortAlarm.h"
#include "Server.h"
#include "ShortMacros.h"
#include "TransportManager.h"

int
main(int argc, char *argv[])
{
    using namespace RAMCloud;
    signal(SIGTERM, Perf::terminationHandler);
    Logger::installCrashBacktraceHandlers();
    Context context(true);
    try {
        ServerConfig config = ServerConfig::forExecution();
        string masterTotalMemory, hashTableMemory;

        bool masterOnly;
        bool backupOnly;

        OptionsDescription serverOptions("Server");
        serverOptions.add_options()
            ("allowLocalBackup",
             ProgramOptions::bool_switch(&config.master.allowLocalBackup),
             "Allow replication to local backup")
            ("backupInMemory,m",
             ProgramOptions::bool_switch(&config.backup.inMemory),
             "Backup will store segment replicas in memory")
            ("backupOnly,B",
             ProgramOptions::bool_switch(&backupOnly),
             "The server should run the backup service only (no master)")
            ("backupStrategy",
             ProgramOptions::value<int>(&config.backup.strategy)->
               default_value(RANDOM_REFINE_AVG),
             "0 random refine min, 1 random refine avg, 2 even distribution, "
             "3 uniform random")
            ("backupWriteRateLimit",
             ProgramOptions::value<size_t>(
                &config.backup.writeRateLimit)->default_value(0),
             "If non-0, specifies the maximum number of megabytes per second "
             "of bandwidth this backup should use. Useful for artificially "
             "restricting bandwidth when measuring various parts of the "
             "system.")
            ("cleanerBalancer",
             ProgramOptions::value<string>(&config.master.cleanerBalancer)->
                default_value("tombstoneRatio:0.40"),
             "Which balancing algorithm to use to schedule cleaning on disk "
             "and in-memory compaction, as well as how to orchestrate multiple "
             "cleaner threads. You will almost certainly want to use the "
             "default value. Currently the only other option is \"fixed:X\", "
             "where 0 <= X <= 100 represents the percentage of CPU time the "
             "disk cleaner will be limited to (the rest is for compaction).")
            ("detectFailures",
             ProgramOptions::value<bool>(&config.detectFailures)->
                default_value(true),
             "Whether to use the randomized failure detector")
            ("disableLogCleaner,d",
             ProgramOptions::bool_switch(&config.master.disableLogCleaner),
             "Disable the log cleaner entirely. You will eventually run out "
             "of memory, but at least you can do so faster this way.")
            ("disableInMemoryCleaning,D",
             ProgramOptions::bool_switch(
                &config.master.disableInMemoryCleaning),
             "Disable the in-memory cleaning portion of the log cleaner. When "
             "turned off, the cleaner will always clean both in memory and on "
             "backup disks at the same time.")
            ("diskExpansionFactor,E",
             ProgramOptions::value<double>(&config.master.diskExpansionFactor)->
                default_value(2.0),
             "Factor (>= 1.0) controlling how much backup disk space this "
             "master will use beyond its in-memory log size. For example, if "
             "the master has memory for 100 full segments and the expansion "
             "factor is 2.0, it will place up to 200 segments (each replicated "
             "R times) on backups.")
            ("file,f",
             ProgramOptions::value<string>(&config.backup.file)->
                default_value("/var/tmp/backup.log"),
             "The file path to the backup storage.")
            ("hashTableMemory,h",
             ProgramOptions::value<string>(&hashTableMemory)->
                default_value("10%"),
             "Percentage or megabytes of master memory allocated to "
             "the hash table")
            ("logCleanerThreads",
             ProgramOptions::value<uint32_t>(
                &config.master.cleanerThreadCount)->default_value(1),
             "The number of cleaner threads controls the amount of parallelism "
             "in the cleaner. More threads will use more cores, but may be "
             "able to better keep up with high write rates.")
            ("masterOnly,M",
             ProgramOptions::bool_switch(&masterOnly),
             "The server should run the master service only (no backup)")
            ("masterServiceThreads",
             ProgramOptions::value<uint32_t>(
                &config.master.masterServiceThreadCount)->default_value(3),
             "The number of threads in MasterService determines the maximum "
             "number of client RPCs that may be processed in parallel. "
             "Increasing this value will use more cores and may improve client "
             "throuphput, especially for reads.")
            ("maxNonVolatileBuffers",
             ProgramOptions::value<uint32_t>(
               &config.backup.maxNonVolatileBuffers)->default_value(0),
             "Maximum number of segments the backup will buffer in memory. The "
             "0 value (default) is special: it tells the server to set the "
             "limit equal to the \"segmentFrames\" value, effectively making "
             "buffering unlimited.")
            ("replicas,r",
             ProgramOptions::value<uint32_t>(&config.master.numReplicas),
             "Number of backup copies to make for each segment")
            ("segmentFrames",
             ProgramOptions::value<uint32_t>(&config.backup.numSegmentFrames)->
                default_value(512),
             "Number of segment frames in backup storage")
            ("sync",
             ProgramOptions::bool_switch(&config.backup.sync),
             "Make all updates completely synchronous all the way down to "
             "stable storage.")
            ("totalMasterMemory,t",

             // Note: we have tried changing the default value below to
             // something that would make sense in production (80%?), but
             // as of 6/2014 that causes too many problems in test and
             // development environments (e.g. hooks/pre-commit will take
             // forever, and if two people do this, rcmaster will run out
             // of memory).
             ProgramOptions::value<string>(&masterTotalMemory)->
                default_value("500"),
             "Percentage or megabytes of system memory for master log & "
             "hash table")
            ("useMinCopysets",
             ProgramOptions::value<bool>(&config.master.useMinCopysets)->
                default_value(false),
             "Whether to use MinCopysets or random replication")
            ("writeCostThreshold,w",
             ProgramOptions::value<uint32_t>(
                &config.master.cleanerWriteCostThreshold)->default_value(8),
             "If in-memory cleaning is enabled, do disk cleaning when the "
             "write cost of memory freed by the in-memory cleaner exceeds "
             "this value. Lower values cause the disk cleaner to run more "
             "frequently. Higher values do more in-memory cleaning and "
             "reduce the amount of backup disk bandwidth used during disk "
             "cleaning.");

        OptionParser optionParser(serverOptions, argc, argv);

        // Log all the command-line arguments.
        string args;
        for (int i = 0; i < argc; i++) {
            if (i != 0)
                args.append(" ");
            args.append(argv[i]);
        }
        LOG(NOTICE, "Command line: %s", args.c_str());

        if (masterOnly && backupOnly)
            DIE("Can't specify both -B and -M options");

        if (masterOnly) {
            config.services = {WireFormat::MASTER_SERVICE,
                               WireFormat::MEMBERSHIP_SERVICE,
                               WireFormat::PING_SERVICE};
        } else if (backupOnly) {
            config.services = {WireFormat::BACKUP_SERVICE,
                               WireFormat::MEMBERSHIP_SERVICE,
                               WireFormat::PING_SERVICE};
        } else {
            config.services = {WireFormat::MASTER_SERVICE,
                               WireFormat::BACKUP_SERVICE,
                               WireFormat::MEMBERSHIP_SERVICE,
                               WireFormat::PING_SERVICE};
        }

        const string localLocator = optionParser.options.getLocalLocator();

#if INFINIBAND
        InfRcTransport::setName(localLocator.c_str());
#endif
        context.transportManager->setSessionTimeout(
                optionParser.options.getSessionTimeout());
        context.transportManager->initialize(localLocator.c_str());
        // Transports may augment the local locator somewhat.
        // Make sure the server is aware of that augmented locator.
        config.localLocator =
            context.transportManager->getListeningLocatorsString();
        LOG(NOTICE, "%s: Listening on %s",
            config.services.toString().c_str(), config.localLocator.c_str());

        config.coordinatorLocator =
            optionParser.options.getExternalStorageLocator();
        if (config.coordinatorLocator.size() == 0) {
            config.coordinatorLocator =
                optionParser.options.getCoordinatorLocator();
        }
        config.clusterName = optionParser.options.getClusterName();
        context.coordinatorSession->setLocation(
                config.coordinatorLocator.c_str(),
                config.clusterName.c_str());

        // Get Default Backup Configuration from Coordinator.
        if (config.services.has(WireFormat::BACKUP_SERVICE)) {
            ProtoBuf::ServerConfig_Backup backupConfig;
            CoordinatorClient::getBackupConfig(&context, backupConfig);
            config.backup.deserialize(backupConfig);
        }

        // Get Default Master Configuration from Coordinator.
        if (config.services.has(WireFormat::MASTER_SERVICE)) {
            ProtoBuf::ServerConfig_Master masterConfig;
            CoordinatorClient::getMasterConfig(&context, masterConfig);
            config.master.deserialize(masterConfig);
        }

        // Re-parse the options to override coordinator provided defaults.
        OptionParser optionReparser(serverOptions, argc, argv);

        if (!backupOnly) {
            LOG(NOTICE, "Using %u backups", config.master.numReplicas);
            config.setLogAndHashTableSize(masterTotalMemory, hashTableMemory);
        }

        // Set PortTimeout and start portTimer
        LOG(NOTICE, "PortTimeOut=%d", optionParser.options.getPortTimeout());
        context.portAlarmTimer->setPortTimeout(
            optionParser.options.getPortTimeout());

        Server server(&context, &config);
        server.run(); // Never returns except for exceptions.

        return 0;
    } catch (const Exception& e) {
        LOG(ERROR, "Fatal error in server at %s: %s",
            context.transportManager->getListeningLocatorsString().c_str(),
            e.what());
        return 1;
    } catch (const std::exception& e) {
        LOG(ERROR, "Fatal error in server at %s: %s",
            context.transportManager->getListeningLocatorsString().c_str(),
            e.what());
        return 1;
    } catch (...) {
        LOG(ERROR, "Unknown fatal error in server at %s",
            context.transportManager->getListeningLocatorsString().c_str());
        return 1;
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "partition_version.hh"
#include "flat_mutation_reader.hh"

struct partition_snapshot_reader_dummy_accounter {
   void operator()(const clustering_row& cr) {}
   void operator()(const static_row& sr) {}
   void operator()(const range_tombstone& rt) {}
   void operator()(const partition_start& ph) {}
   void operator()(const partition_end& eop) {}
};
extern partition_snapshot_reader_dummy_accounter no_accounter;

template <typename MemoryAccounter = partition_snapshot_reader_dummy_accounter>
class partition_snapshot_flat_reader : public flat_mutation_reader::impl, public MemoryAccounter {
    struct rows_position {
        mutation_partition::rows_type::const_iterator _position;
        mutation_partition::rows_type::const_iterator _end;
    };

    class heap_compare {
        rows_entry::compare _cmp;
    public:
        explicit heap_compare(const schema& s) : _cmp(s) { }
        bool operator()(const rows_position& a, const rows_position& b) {
            return _cmp(*b._position, *a._position);
        }
    };

    // The part of the reader that accesses LSA memory directly and works
    // with reclamation disabled. The state is either immutable (comparators,
    // snapshot, references to region and alloc section) or dropped on any
    // allocation section retry (_clustering_rows).
    class lsa_partition_reader {
        const schema& _schema;
        reader_permit _permit;
        rows_entry::tri_compare _cmp;
        position_in_partition::equal_compare _eq;
        heap_compare _heap_cmp;

        partition_snapshot_ptr _snapshot;

        logalloc::region& _region;
        logalloc::allocating_section& _read_section;

        partition_snapshot::change_mark _change_mark;
        std::vector<rows_position> _clustering_rows;

        bool _digest_requested;
    private:
        template<typename Function>
        decltype(auto) in_alloc_section(Function&& fn) {
            return _read_section.with_reclaiming_disabled(_region, [&] {
                return fn();
            });
        }
        void refresh_state(const query::clustering_range& ck_range,
                           const std::optional<position_in_partition>& last_row,
                           range_tombstone_stream& range_tombstones) {
            _clustering_rows.clear();

            if (!last_row) {
                // New range. Collect all relevant range tombstone.
                for (auto&& v : _snapshot->versions()) {
                    range_tombstones.apply(v.partition().row_tombstones(), ck_range);
                }
            }

            for (auto&& v : _snapshot->versions()) {
                mutation_partition::rows_type::const_iterator cr_end = v.partition().upper_bound(_schema, ck_range);
                auto cr = [&] () -> mutation_partition::rows_type::const_iterator {
                    if (last_row) {
                        return v.partition().clustered_rows().upper_bound(*last_row, _cmp);
                    } else {
                        return v.partition().lower_bound(_schema, ck_range);
                    }
                }();

                if (cr != cr_end) {
                    _clustering_rows.emplace_back(rows_position { cr, cr_end });
                }
            }

            boost::range::make_heap(_clustering_rows, _heap_cmp);
        }
        // Valid if has_more_rows()
        const rows_entry& pop_clustering_row() {
            boost::range::pop_heap(_clustering_rows, _heap_cmp);
            auto& current = _clustering_rows.back();
            const rows_entry& e = *current._position;
            current._position = std::next(current._position);
            if (current._position == current._end) {
                _clustering_rows.pop_back();
            } else {
                boost::range::push_heap(_clustering_rows, _heap_cmp);
            }
            return e;
        }
        // Valid if has_more_rows()
        const rows_entry& peek_row() const {
            return *_clustering_rows.front()._position;
        }
        bool has_more_rows() const {
            return !_clustering_rows.empty();
        }
    public:
        explicit lsa_partition_reader(const schema& s, reader_permit permit, partition_snapshot_ptr snp,
                                      logalloc::region& region, logalloc::allocating_section& read_section,
                                      bool digest_requested)
            : _schema(s)
            , _permit(std::move(permit))
            , _cmp(s)
            , _eq(s)
            , _heap_cmp(s)
            , _snapshot(std::move(snp))
            , _region(region)
            , _read_section(read_section)
            , _digest_requested(digest_requested)
        { }

        template<typename Function>
        decltype(auto) with_reserve(Function&& fn) {
            return _read_section.with_reserve(std::forward<Function>(fn));
        }

        tombstone partition_tombstone() {
            logalloc::reclaim_lock guard(_region);
            return _snapshot->partition_tombstone();
        }

        static_row get_static_row() {
            return in_alloc_section([&] {
                return _snapshot->static_row(_digest_requested);
            });
        }

        // Returns next clustered row in the range.
        // If the ck_range is the same as the one used previously last_row needs
        // to be engaged and equal the position of the row returned last time.
        // If the ck_range is different or this is the first call to this
        // function last_row has to be disengaged. Additionally, when entering
        // new range range_tombstones will be populated with all relevant
        // tombstones.
        mutation_fragment_opt next_row(const query::clustering_range& ck_range,
                                       const std::optional<position_in_partition>& last_row,
                                       range_tombstone_stream& range_tombstones) {
            return in_alloc_section([&] () -> mutation_fragment_opt {
                auto mark = _snapshot->get_change_mark();
                if (!last_row || mark != _change_mark) {
                    refresh_state(ck_range, last_row, range_tombstones);
                    _change_mark = mark;
                }
                while (has_more_rows()) {
                    const rows_entry& e = pop_clustering_row();
                    if (e.dummy()) {
                        continue;
                    }
                    if (_digest_requested) {
                        e.row().cells().prepare_hash(_schema, column_kind::regular_column);
                    }
                    auto result = mutation_fragment(mutation_fragment::clustering_row_tag_t(), _schema, _permit, _schema, e);
                    while (has_more_rows() && _eq(peek_row().position(), result.as_clustering_row().position())) {
                        const rows_entry& e = pop_clustering_row();
                        if (_digest_requested) {
                            e.row().cells().prepare_hash(_schema, column_kind::regular_column);
                        }
                        result.mutate_as_clustering_row(_schema, [&] (clustering_row& cr) mutable {
                            cr.apply(_schema, e);
                        });
                    }
                    return result;
                }
                return { };
            });
        }
    };
private:
    // Keeps shared pointer to the container we read mutation from to make sure
    // that its lifetime is appropriately extended.
    boost::any _container_guard;

    query::clustering_key_filter_ranges _ck_ranges;
    query::clustering_row_ranges::const_iterator _current_ck_range;
    query::clustering_row_ranges::const_iterator _ck_range_end;

    std::optional<position_in_partition> _last_entry;
    mutation_fragment_opt _next_row;
    range_tombstone_stream _range_tombstones;

    lsa_partition_reader _reader;
    bool _static_row_done = false;
    bool _no_more_rows_in_current_range = false;

    MemoryAccounter& mem_accounter() {
        return *this;
    }
private:
    void push_static_row() {
        auto sr = _reader.get_static_row();
        if (!sr.empty()) {
            emplace_mutation_fragment(mutation_fragment(*_schema, _permit, std::move(sr)));
        }
    }

    mutation_fragment_opt read_next() {
        if (!_next_row && !_no_more_rows_in_current_range) {
            _next_row = _reader.next_row(*_current_ck_range, _last_entry, _range_tombstones);
        }
        if (_next_row) {
            auto pos_view = _next_row->as_clustering_row().position();
            auto mf = _range_tombstones.get_next(pos_view);
            if (mf) {
                return mf;
            }
            _last_entry = position_in_partition(pos_view);
            return std::exchange(_next_row, {});
        } else {
            _no_more_rows_in_current_range = true;
            return _range_tombstones.get_next(position_in_partition_view::for_range_end(*_current_ck_range));
        }
    }

    void emplace_mutation_fragment(mutation_fragment&& mfopt) {
        mfopt.visit(mem_accounter());
        push_mutation_fragment(std::move(mfopt));
    }

    void on_new_range() {
        if (_current_ck_range == _ck_range_end) {
            _end_of_stream = true;
            push_mutation_fragment(mutation_fragment(*_schema, _permit, partition_end()));
        }
        _no_more_rows_in_current_range = false;
    }

    void do_fill_buffer(db::timeout_clock::time_point timeout) {
        while (!is_end_of_stream() && !is_buffer_full()) {
            auto mfopt = read_next();
            if (mfopt) {
                emplace_mutation_fragment(std::move(*mfopt));
            } else {
                _last_entry = std::nullopt;
                _current_ck_range = std::next(_current_ck_range);
                on_new_range();
            }
            if (need_preempt()) {
                break;
            }
        }
    }
public:
    template <typename... Args>
    partition_snapshot_flat_reader(schema_ptr s, reader_permit permit, dht::decorated_key dk, partition_snapshot_ptr snp,
                              query::clustering_key_filter_ranges crr, bool digest_requested,
                              logalloc::region& region, logalloc::allocating_section& read_section,
                              boost::any pointer_to_container, Args&&... args)
        : impl(std::move(s), std::move(permit))
        , MemoryAccounter(std::forward<Args>(args)...)
        , _container_guard(std::move(pointer_to_container))
        , _ck_ranges(std::move(crr))
        , _current_ck_range(_ck_ranges.begin())
        , _ck_range_end(_ck_ranges.end())
        , _range_tombstones(*_schema, _permit)
        , _reader(*_schema, _permit, std::move(snp), region, read_section, digest_requested)
    {
        _reader.with_reserve([&] {
            push_mutation_fragment(*_schema, _permit, partition_start(std::move(dk), _reader.partition_tombstone()));
        });
    }

    virtual future<> fill_buffer(db::timeout_clock::time_point timeout) override {
      // FIXME: indentation
      return do_until([this] { return is_end_of_stream() || is_buffer_full(); }, [this, timeout] {
        _reader.with_reserve([&] {
            if (!_static_row_done) {
                push_static_row();
                on_new_range();
                _static_row_done = true;
            }
            do_fill_buffer(timeout);
        });
        return make_ready_future<>();
      });
    }
    virtual future<> next_partition() override {
        clear_buffer_to_next_partition();
        if (is_buffer_empty()) {
            _end_of_stream = true;
        }
        return make_ready_future<>();
    }
    virtual future<> fast_forward_to(const dht::partition_range& pr, db::timeout_clock::time_point timeout) override {
        throw std::runtime_error("This reader can't be fast forwarded to another partition.");
    };
    virtual future<> fast_forward_to(position_range cr, db::timeout_clock::time_point timeout) override {
        throw std::runtime_error("This reader can't be fast forwarded to another position.");
    };
};

template <typename MemoryAccounter, typename... Args>
inline flat_mutation_reader
make_partition_snapshot_flat_reader(schema_ptr s,
                                    reader_permit permit,
                                    dht::decorated_key dk,
                                    query::clustering_key_filter_ranges crr,
                                    partition_snapshot_ptr snp,
                                    bool digest_requested,
                                    logalloc::region& region,
                                    logalloc::allocating_section& read_section,
                                    boost::any pointer_to_container,
                                    streamed_mutation::forwarding fwd,
                                    Args&&... args)
{
    auto res = make_flat_mutation_reader<partition_snapshot_flat_reader<MemoryAccounter>>(std::move(s), std::move(permit), std::move(dk),
            snp, std::move(crr), digest_requested, region, read_section, std::move(pointer_to_container), std::forward<Args>(args)...);
    if (fwd) {
        return make_forwardable(std::move(res)); // FIXME: optimize
    } else {
        return res;
    }
}

inline flat_mutation_reader
make_partition_snapshot_flat_reader(schema_ptr s,
                                    reader_permit permit,
                                    dht::decorated_key dk,
                                    query::clustering_key_filter_ranges crr,
                                    partition_snapshot_ptr snp,
                                    bool digest_requested,
                                    logalloc::region& region,
                                    logalloc::allocating_section& read_section,
                                    boost::any pointer_to_container,
                                    streamed_mutation::forwarding fwd)
{
    return make_partition_snapshot_flat_reader<partition_snapshot_reader_dummy_accounter>(std::move(s), std::move(permit),
            std::move(dk), std::move(crr), std::move(snp), digest_requested, region, read_section, std::move(pointer_to_container), fwd);
}
<commit_msg>partition_snapshot_reader: Use on-demand comparators<commit_after>/*
 * Copyright (C) 2017 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "partition_version.hh"
#include "flat_mutation_reader.hh"

struct partition_snapshot_reader_dummy_accounter {
   void operator()(const clustering_row& cr) {}
   void operator()(const static_row& sr) {}
   void operator()(const range_tombstone& rt) {}
   void operator()(const partition_start& ph) {}
   void operator()(const partition_end& eop) {}
};
extern partition_snapshot_reader_dummy_accounter no_accounter;

template <typename MemoryAccounter = partition_snapshot_reader_dummy_accounter>
class partition_snapshot_flat_reader : public flat_mutation_reader::impl, public MemoryAccounter {
    struct rows_position {
        mutation_partition::rows_type::const_iterator _position;
        mutation_partition::rows_type::const_iterator _end;
    };

    class heap_compare {
        rows_entry::compare _cmp;
    public:
        explicit heap_compare(const schema& s) : _cmp(s) { }
        bool operator()(const rows_position& a, const rows_position& b) {
            return _cmp(*b._position, *a._position);
        }
    };

    // The part of the reader that accesses LSA memory directly and works
    // with reclamation disabled. The state is either immutable (comparators,
    // snapshot, references to region and alloc section) or dropped on any
    // allocation section retry (_clustering_rows).
    class lsa_partition_reader {
        const schema& _schema;
        reader_permit _permit;
        heap_compare _heap_cmp;

        partition_snapshot_ptr _snapshot;

        logalloc::region& _region;
        logalloc::allocating_section& _read_section;

        partition_snapshot::change_mark _change_mark;
        std::vector<rows_position> _clustering_rows;

        bool _digest_requested;
    private:
        template<typename Function>
        decltype(auto) in_alloc_section(Function&& fn) {
            return _read_section.with_reclaiming_disabled(_region, [&] {
                return fn();
            });
        }
        void refresh_state(const query::clustering_range& ck_range,
                           const std::optional<position_in_partition>& last_row,
                           range_tombstone_stream& range_tombstones) {
            _clustering_rows.clear();

            if (!last_row) {
                // New range. Collect all relevant range tombstone.
                for (auto&& v : _snapshot->versions()) {
                    range_tombstones.apply(v.partition().row_tombstones(), ck_range);
                }
            }

            rows_entry::tri_compare rows_cmp(_schema);
            for (auto&& v : _snapshot->versions()) {
                mutation_partition::rows_type::const_iterator cr_end = v.partition().upper_bound(_schema, ck_range);
                auto cr = [&] () -> mutation_partition::rows_type::const_iterator {
                    if (last_row) {
                        return v.partition().clustered_rows().upper_bound(*last_row, rows_cmp);
                    } else {
                        return v.partition().lower_bound(_schema, ck_range);
                    }
                }();

                if (cr != cr_end) {
                    _clustering_rows.emplace_back(rows_position { cr, cr_end });
                }
            }

            boost::range::make_heap(_clustering_rows, _heap_cmp);
        }
        // Valid if has_more_rows()
        const rows_entry& pop_clustering_row() {
            boost::range::pop_heap(_clustering_rows, _heap_cmp);
            auto& current = _clustering_rows.back();
            const rows_entry& e = *current._position;
            current._position = std::next(current._position);
            if (current._position == current._end) {
                _clustering_rows.pop_back();
            } else {
                boost::range::push_heap(_clustering_rows, _heap_cmp);
            }
            return e;
        }
        // Valid if has_more_rows()
        const rows_entry& peek_row() const {
            return *_clustering_rows.front()._position;
        }
        bool has_more_rows() const {
            return !_clustering_rows.empty();
        }
    public:
        explicit lsa_partition_reader(const schema& s, reader_permit permit, partition_snapshot_ptr snp,
                                      logalloc::region& region, logalloc::allocating_section& read_section,
                                      bool digest_requested)
            : _schema(s)
            , _permit(std::move(permit))
            , _heap_cmp(s)
            , _snapshot(std::move(snp))
            , _region(region)
            , _read_section(read_section)
            , _digest_requested(digest_requested)
        { }

        template<typename Function>
        decltype(auto) with_reserve(Function&& fn) {
            return _read_section.with_reserve(std::forward<Function>(fn));
        }

        tombstone partition_tombstone() {
            logalloc::reclaim_lock guard(_region);
            return _snapshot->partition_tombstone();
        }

        static_row get_static_row() {
            return in_alloc_section([&] {
                return _snapshot->static_row(_digest_requested);
            });
        }

        // Returns next clustered row in the range.
        // If the ck_range is the same as the one used previously last_row needs
        // to be engaged and equal the position of the row returned last time.
        // If the ck_range is different or this is the first call to this
        // function last_row has to be disengaged. Additionally, when entering
        // new range range_tombstones will be populated with all relevant
        // tombstones.
        mutation_fragment_opt next_row(const query::clustering_range& ck_range,
                                       const std::optional<position_in_partition>& last_row,
                                       range_tombstone_stream& range_tombstones) {
            return in_alloc_section([&] () -> mutation_fragment_opt {
                auto mark = _snapshot->get_change_mark();
                if (!last_row || mark != _change_mark) {
                    refresh_state(ck_range, last_row, range_tombstones);
                    _change_mark = mark;
                }
                position_in_partition::equal_compare rows_eq(_schema);
                while (has_more_rows()) {
                    const rows_entry& e = pop_clustering_row();
                    if (e.dummy()) {
                        continue;
                    }
                    if (_digest_requested) {
                        e.row().cells().prepare_hash(_schema, column_kind::regular_column);
                    }
                    auto result = mutation_fragment(mutation_fragment::clustering_row_tag_t(), _schema, _permit, _schema, e);
                    while (has_more_rows() && rows_eq(peek_row().position(), result.as_clustering_row().position())) {
                        const rows_entry& e = pop_clustering_row();
                        if (_digest_requested) {
                            e.row().cells().prepare_hash(_schema, column_kind::regular_column);
                        }
                        result.mutate_as_clustering_row(_schema, [&] (clustering_row& cr) mutable {
                            cr.apply(_schema, e);
                        });
                    }
                    return result;
                }
                return { };
            });
        }
    };
private:
    // Keeps shared pointer to the container we read mutation from to make sure
    // that its lifetime is appropriately extended.
    boost::any _container_guard;

    query::clustering_key_filter_ranges _ck_ranges;
    query::clustering_row_ranges::const_iterator _current_ck_range;
    query::clustering_row_ranges::const_iterator _ck_range_end;

    std::optional<position_in_partition> _last_entry;
    mutation_fragment_opt _next_row;
    range_tombstone_stream _range_tombstones;

    lsa_partition_reader _reader;
    bool _static_row_done = false;
    bool _no_more_rows_in_current_range = false;

    MemoryAccounter& mem_accounter() {
        return *this;
    }
private:
    void push_static_row() {
        auto sr = _reader.get_static_row();
        if (!sr.empty()) {
            emplace_mutation_fragment(mutation_fragment(*_schema, _permit, std::move(sr)));
        }
    }

    mutation_fragment_opt read_next() {
        if (!_next_row && !_no_more_rows_in_current_range) {
            _next_row = _reader.next_row(*_current_ck_range, _last_entry, _range_tombstones);
        }
        if (_next_row) {
            auto pos_view = _next_row->as_clustering_row().position();
            auto mf = _range_tombstones.get_next(pos_view);
            if (mf) {
                return mf;
            }
            _last_entry = position_in_partition(pos_view);
            return std::exchange(_next_row, {});
        } else {
            _no_more_rows_in_current_range = true;
            return _range_tombstones.get_next(position_in_partition_view::for_range_end(*_current_ck_range));
        }
    }

    void emplace_mutation_fragment(mutation_fragment&& mfopt) {
        mfopt.visit(mem_accounter());
        push_mutation_fragment(std::move(mfopt));
    }

    void on_new_range() {
        if (_current_ck_range == _ck_range_end) {
            _end_of_stream = true;
            push_mutation_fragment(mutation_fragment(*_schema, _permit, partition_end()));
        }
        _no_more_rows_in_current_range = false;
    }

    void do_fill_buffer(db::timeout_clock::time_point timeout) {
        while (!is_end_of_stream() && !is_buffer_full()) {
            auto mfopt = read_next();
            if (mfopt) {
                emplace_mutation_fragment(std::move(*mfopt));
            } else {
                _last_entry = std::nullopt;
                _current_ck_range = std::next(_current_ck_range);
                on_new_range();
            }
            if (need_preempt()) {
                break;
            }
        }
    }
public:
    template <typename... Args>
    partition_snapshot_flat_reader(schema_ptr s, reader_permit permit, dht::decorated_key dk, partition_snapshot_ptr snp,
                              query::clustering_key_filter_ranges crr, bool digest_requested,
                              logalloc::region& region, logalloc::allocating_section& read_section,
                              boost::any pointer_to_container, Args&&... args)
        : impl(std::move(s), std::move(permit))
        , MemoryAccounter(std::forward<Args>(args)...)
        , _container_guard(std::move(pointer_to_container))
        , _ck_ranges(std::move(crr))
        , _current_ck_range(_ck_ranges.begin())
        , _ck_range_end(_ck_ranges.end())
        , _range_tombstones(*_schema, _permit)
        , _reader(*_schema, _permit, std::move(snp), region, read_section, digest_requested)
    {
        _reader.with_reserve([&] {
            push_mutation_fragment(*_schema, _permit, partition_start(std::move(dk), _reader.partition_tombstone()));
        });
    }

    virtual future<> fill_buffer(db::timeout_clock::time_point timeout) override {
      // FIXME: indentation
      return do_until([this] { return is_end_of_stream() || is_buffer_full(); }, [this, timeout] {
        _reader.with_reserve([&] {
            if (!_static_row_done) {
                push_static_row();
                on_new_range();
                _static_row_done = true;
            }
            do_fill_buffer(timeout);
        });
        return make_ready_future<>();
      });
    }
    virtual future<> next_partition() override {
        clear_buffer_to_next_partition();
        if (is_buffer_empty()) {
            _end_of_stream = true;
        }
        return make_ready_future<>();
    }
    virtual future<> fast_forward_to(const dht::partition_range& pr, db::timeout_clock::time_point timeout) override {
        throw std::runtime_error("This reader can't be fast forwarded to another partition.");
    };
    virtual future<> fast_forward_to(position_range cr, db::timeout_clock::time_point timeout) override {
        throw std::runtime_error("This reader can't be fast forwarded to another position.");
    };
};

template <typename MemoryAccounter, typename... Args>
inline flat_mutation_reader
make_partition_snapshot_flat_reader(schema_ptr s,
                                    reader_permit permit,
                                    dht::decorated_key dk,
                                    query::clustering_key_filter_ranges crr,
                                    partition_snapshot_ptr snp,
                                    bool digest_requested,
                                    logalloc::region& region,
                                    logalloc::allocating_section& read_section,
                                    boost::any pointer_to_container,
                                    streamed_mutation::forwarding fwd,
                                    Args&&... args)
{
    auto res = make_flat_mutation_reader<partition_snapshot_flat_reader<MemoryAccounter>>(std::move(s), std::move(permit), std::move(dk),
            snp, std::move(crr), digest_requested, region, read_section, std::move(pointer_to_container), std::forward<Args>(args)...);
    if (fwd) {
        return make_forwardable(std::move(res)); // FIXME: optimize
    } else {
        return res;
    }
}

inline flat_mutation_reader
make_partition_snapshot_flat_reader(schema_ptr s,
                                    reader_permit permit,
                                    dht::decorated_key dk,
                                    query::clustering_key_filter_ranges crr,
                                    partition_snapshot_ptr snp,
                                    bool digest_requested,
                                    logalloc::region& region,
                                    logalloc::allocating_section& read_section,
                                    boost::any pointer_to_container,
                                    streamed_mutation::forwarding fwd)
{
    return make_partition_snapshot_flat_reader<partition_snapshot_reader_dummy_accounter>(std::move(s), std::move(permit),
            std::move(dk), std::move(crr), std::move(snp), digest_requested, region, read_section, std::move(pointer_to_container), fwd);
}
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include <info.hpp>

#include <cmdline.hpp>
#include <kdb.hpp>
#include <modules.hpp>
#include <plugin.hpp>

#include <iostream>

using namespace std;
using namespace kdb;
using namespace kdb::tools;

InfoCommand::InfoCommand ()
{
}

int InfoCommand::execute (Cmdline const & cl)
{
	std::string subkey;
	if (cl.arguments.size () == 1)
	{
	}
	else if (cl.arguments.size () == 2)
	{
		subkey = cl.arguments[1];
	}
	else
	{
		throw invalid_argument ("Need at 1 or 2 argument(s)");
	}
	std::string name = cl.arguments[0];

	KeySet conf;
	Key parentKey (std::string ("system/elektra/modules/") + name, KEY_END);

	if (!cl.load)
	{
		KDB kdb;
		kdb.get (conf, parentKey);
	}

	if (!conf.lookup (parentKey))
	{
		if (!cl.load)
		{
			cerr << "Module does not seem to be loaded." << endl;
			cerr << "Now in fallback code. Will directly load config from plugin." << endl;
		}

		Modules modules;
		KeySet ks = cl.getPluginsConfig ();
		PluginPtr plugin;
		if (ks.size () == 0)
		{
			plugin = modules.load (name);
		}
		else
		{
			plugin = modules.load (name, ks);
		}

		// fix name for virtual plugins
		if (name != plugin->name ())
		{
			std::cerr << "Will use name " << plugin->name () << " for virtual plugin named " << name << std::endl;
			name = plugin->name ();
		}
		conf.append (plugin->getInfo ());
	}

	Key root (std::string ("system/elektra/modules/") + name + "/exports", KEY_END);

	if (!subkey.empty ())
	{
		root.setName (std::string ("system/elektra/modules/") + name + "/infos/" + subkey);
		Key k = conf.lookup (root);
		if (k)
		{
			cout << k.getString () << std::endl;
			return 0;
		}
		else
		{
			cerr << "clause not found" << std::endl;
			return 1;
		}
	}

	root.setName (std::string ("system/elektra/modules/") + name + "/exports");
	Key k = conf.lookup (root);

	if (k)
	{
		cout << "Exported symbols: ";
		while ((k = conf.next ()) && k.isBelow (root))
		{
			cout << k.getBaseName () << " ";
		}
		cout << endl;
	}
	else
		cout << "no exported symbols found" << endl;

	root.setName (std::string ("system/elektra/modules/") + name + "/infos");
	k = conf.lookup (root);

	if (k)
	{
		while ((k = conf.next ()) && k.isBelow (root))
		{
			cout << getStdColor (ANSI_COLOR::BOLD) << k.getBaseName () << ": " << getStdColor (ANSI_COLOR::RESET)
			     << k.getString () << endl;
		}
	}
	else
		cout << "no information found" << endl;

	return 0;
}

InfoCommand::~InfoCommand ()
{
}
<commit_msg>KDB Info: Remove empty if-statement<commit_after>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include <info.hpp>

#include <cmdline.hpp>
#include <kdb.hpp>
#include <modules.hpp>
#include <plugin.hpp>

#include <iostream>

using namespace std;
using namespace kdb;
using namespace kdb::tools;

InfoCommand::InfoCommand ()
{
}

int InfoCommand::execute (Cmdline const & cl)
{
	std::string subkey;
	if (cl.arguments.size () < 1 || cl.arguments.size () > 2)
	{
		throw invalid_argument ("Need 1 or 2 argument(s)");
	}

	if (cl.arguments.size () == 2)
	{
		subkey = cl.arguments[1];
	}
	std::string name = cl.arguments[0];

	KeySet conf;
	Key parentKey (std::string ("system/elektra/modules/") + name, KEY_END);

	if (!cl.load)
	{
		KDB kdb;
		kdb.get (conf, parentKey);
	}

	if (!conf.lookup (parentKey))
	{
		if (!cl.load)
		{
			cerr << "Module does not seem to be loaded." << endl;
			cerr << "Now in fallback code. Will directly load config from plugin." << endl;
		}

		Modules modules;
		KeySet ks = cl.getPluginsConfig ();
		PluginPtr plugin;
		if (ks.size () == 0)
		{
			plugin = modules.load (name);
		}
		else
		{
			plugin = modules.load (name, ks);
		}

		// fix name for virtual plugins
		if (name != plugin->name ())
		{
			std::cerr << "Will use name " << plugin->name () << " for virtual plugin named " << name << std::endl;
			name = plugin->name ();
		}
		conf.append (plugin->getInfo ());
	}

	Key root (std::string ("system/elektra/modules/") + name + "/exports", KEY_END);

	if (!subkey.empty ())
	{
		root.setName (std::string ("system/elektra/modules/") + name + "/infos/" + subkey);
		Key k = conf.lookup (root);
		if (k)
		{
			cout << k.getString () << std::endl;
			return 0;
		}
		else
		{
			cerr << "clause not found" << std::endl;
			return 1;
		}
	}

	root.setName (std::string ("system/elektra/modules/") + name + "/exports");
	Key k = conf.lookup (root);

	if (k)
	{
		cout << "Exported symbols: ";
		while ((k = conf.next ()) && k.isBelow (root))
		{
			cout << k.getBaseName () << " ";
		}
		cout << endl;
	}
	else
		cout << "no exported symbols found" << endl;

	root.setName (std::string ("system/elektra/modules/") + name + "/infos");
	k = conf.lookup (root);

	if (k)
	{
		while ((k = conf.next ()) && k.isBelow (root))
		{
			cout << getStdColor (ANSI_COLOR::BOLD) << k.getBaseName () << ": " << getStdColor (ANSI_COLOR::RESET)
			     << k.getString () << endl;
		}
	}
	else
		cout << "no information found" << endl;

	return 0;
}

InfoCommand::~InfoCommand ()
{
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//
// A WebAssembly optimizer, loads code, optionally runs passes on it,
// then writes it.
//

#include <memory>

#include "pass.h"
#include "support/command-line.h"
#include "support/file.h"
#include "wasm-printing.h"
#include "wasm-s-parser.h"
#include "wasm-validator.h"
#include "wasm-io.h"

using namespace wasm;

//
// main
//

int main(int argc, const char* argv[]) {
  Name entry;
  std::vector<std::string> passes;
  bool runOptimizationPasses = false;
  PassOptions passOptions;
  bool emitBinary = true;
  bool debugInfo = false;

  Options options("wasm-opt", "Optimize .wast files");
  options
      .add("--output", "-o", "Output file (stdout if not specified)",
           Options::Arguments::One,
           [](Options* o, const std::string& argument) {
             o->extra["output"] = argument;
             Colors::disable();
           })
      #include "optimization-options.h"
      .add("--emit-text", "-S", "Emit text instead of binary for the output file",
           Options::Arguments::Zero,
           [&](Options *o, const std::string &argument) { emitBinary = false; })
      .add("--debuginfo", "-g", "Emit names section and debug info",
           Options::Arguments::Zero,
           [&](Options *o, const std::string &arguments) { debugInfo = true; })
      .add_positional("INFILE", Options::Arguments::One,
                      [](Options* o, const std::string& argument) {
                        o->extra["infile"] = argument;
                      });
  for (const auto& p : PassRegistry::get()->getRegisteredNames()) {
    options.add(
        std::string("--") + p, "", PassRegistry::get()->getPassDescription(p),
        Options::Arguments::Zero,
        [&passes, p](Options*, const std::string&) { passes.push_back(p); });
  }
  options.parse(argc, argv);

  if (runOptimizationPasses) {
    passes.resize(passes.size() + 1);
    std::move_backward(passes.begin(), passes.begin() + passes.size() - 1, passes.end());
    passes[0] = "O";
  }

  auto input(read_file<std::string>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release));

  Module wasm;

  {
    if (options.debug) std::cerr << "reading...\n";
    ModuleReader reader;
    reader.setDebug(options.debug);

    try {
      reader.read(options.extra["infile"], wasm);
    } catch (ParseException& p) {
      p.dump(std::cerr);
      Fatal() << "error in parsing input";
    } catch (std::bad_alloc& b) {
      Fatal() << "error in building module, std::bad_alloc (possibly invalid request for silly amounts of memory)";
    }
  }

  if (!WasmValidator().validate(wasm)) {
    Fatal() << "error in validating input";
  }

  if (passes.size() > 0) {
    if (options.debug) std::cerr << "running passes...\n";
    PassRunner passRunner(&wasm, passOptions);
    if (options.debug) passRunner.setDebug(true);
    for (auto& passName : passes) {
      if (passName == "O") {
        passRunner.addDefaultOptimizationPasses();
      } else {
        passRunner.add(passName);
      }
    }
    passRunner.run();
    assert(WasmValidator().validate(wasm));
  }

  if (options.extra.count("output") > 0) {
    if (options.debug) std::cerr << "writing..." << std::endl;
    ModuleWriter writer;
    writer.setDebug(options.debug);
    writer.setBinary(emitBinary);
    writer.setDebugInfo(debugInfo);
    writer.write(wasm, options.extra["output"]);
  }
}
<commit_msg>add --fuzz-exec option to wasm-opt, which (when possible) executes results before and after optimizations are run, checking for changes. this can be used when fuzzing<commit_after>/*
 * Copyright 2016 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//
// A WebAssembly optimizer, loads code, optionally runs passes on it,
// then writes it.
//

#include <memory>

#include "pass.h"
#include "support/command-line.h"
#include "support/file.h"
#include "wasm-printing.h"
#include "wasm-s-parser.h"
#include "wasm-validator.h"
#include "wasm-io.h"
#include "wasm-interpreter.h"
#include "shell-interface.h"

using namespace wasm;

// gets execution results from a wasm module. this is useful for fuzzing
//
// we can only get results when there are no imports. we then call each method
// that has a result, with some values
struct ExecutionResults {
  std::map<Name, Literal> results;

  void get(Module& wasm) {
    if (wasm.imports.size() > 0) {
      std::cout << "[fuzz-exec] imports, so quitting\n";
      return;
    }
    for (auto& func : wasm.functions) {
      if (func->result != none) {
        // this is good
        results[func->name] = run(func.get(), wasm);
      }
    }
    std::cout << "[fuzz-exec] " << results.size() << " results noted\n";
  }

  bool operator==(ExecutionResults& other) {
    for (auto& iter : results) {
      auto name = iter.first;
      if (other.results.find(name) != other.results.end()) {
        if (results[name] != other.results[name]) {
          return false;
        }
      }
    }
    return true;
  }

  bool operator!=(ExecutionResults& other) {
    return !((*this) == other);
  }

  Literal run(Function* func, Module& wasm) {
    ShellExternalInterface interface;
    ModuleInstance instance(wasm, &interface);
    LiteralList arguments;
    for (WasmType param : func->params) {
      // zeros in arguments TODO: more?
      arguments.push_back(Literal(param));
    }
    try {
      return instance.callFunctionInternal(func->name, arguments);
    } catch (const TrapException&) {
      return Literal();
    }
  }
};

//
// main
//

int main(int argc, const char* argv[]) {
  Name entry;
  std::vector<std::string> passes;
  bool runOptimizationPasses = false;
  PassOptions passOptions;
  bool emitBinary = true;
  bool debugInfo = false;
  bool fuzzExec = false;

  Options options("wasm-opt", "Optimize .wast files");
  options
      .add("--output", "-o", "Output file (stdout if not specified)",
           Options::Arguments::One,
           [](Options* o, const std::string& argument) {
             o->extra["output"] = argument;
             Colors::disable();
           })
      #include "optimization-options.h"
      .add("--emit-text", "-S", "Emit text instead of binary for the output file",
           Options::Arguments::Zero,
           [&](Options *o, const std::string &argument) { emitBinary = false; })
      .add("--debuginfo", "-g", "Emit names section and debug info",
           Options::Arguments::Zero,
           [&](Options *o, const std::string &arguments) { debugInfo = true; })
      .add("--fuzz-exec", "-fe", "Execute functions before and after optimization, helping fuzzing find bugs",
           Options::Arguments::Zero,
           [&](Options *o, const std::string &arguments) { fuzzExec = true; })
      .add_positional("INFILE", Options::Arguments::One,
                      [](Options* o, const std::string& argument) {
                        o->extra["infile"] = argument;
                      });
  for (const auto& p : PassRegistry::get()->getRegisteredNames()) {
    options.add(
        std::string("--") + p, "", PassRegistry::get()->getPassDescription(p),
        Options::Arguments::Zero,
        [&passes, p](Options*, const std::string&) { passes.push_back(p); });
  }
  options.parse(argc, argv);

  if (runOptimizationPasses) {
    passes.resize(passes.size() + 1);
    std::move_backward(passes.begin(), passes.begin() + passes.size() - 1, passes.end());
    passes[0] = "O";
  }

  auto input(read_file<std::string>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release));

  Module wasm;

  {
    if (options.debug) std::cerr << "reading...\n";
    ModuleReader reader;
    reader.setDebug(options.debug);

    try {
      reader.read(options.extra["infile"], wasm);
    } catch (ParseException& p) {
      p.dump(std::cerr);
      Fatal() << "error in parsing input";
    } catch (std::bad_alloc& b) {
      Fatal() << "error in building module, std::bad_alloc (possibly invalid request for silly amounts of memory)";
    }
  }

  if (!WasmValidator().validate(wasm)) {
    Fatal() << "error in validating input";
  }

  ExecutionResults results;
  if (fuzzExec) {
    results.get(wasm);
  }

  if (passes.size() > 0) {
    if (options.debug) std::cerr << "running passes...\n";
    PassRunner passRunner(&wasm, passOptions);
    if (options.debug) passRunner.setDebug(true);
    for (auto& passName : passes) {
      if (passName == "O") {
        passRunner.addDefaultOptimizationPasses();
      } else {
        passRunner.add(passName);
      }
    }
    passRunner.run();
    assert(WasmValidator().validate(wasm));
  }

  if (fuzzExec) {
    ExecutionResults optimizedResults;
    optimizedResults.get(wasm);
    if (optimizedResults != results) {
      Fatal() << "[fuzz-exec] optimization passes changed execution results";
    }
    std::cout << "[fuzz-exec] results match\n";
  }

  if (options.extra.count("output") > 0) {
    if (options.debug) std::cerr << "writing..." << std::endl;
    ModuleWriter writer;
    writer.setDebug(options.debug);
    writer.setBinary(emitBinary);
    writer.setDebugInfo(debugInfo);
    writer.write(wasm, options.extra["output"]);
  }
}
<|endoftext|>


<commit_before>/* Copyright (c) 2009 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <getopt.h>
#include <stdlib.h>
#include <string.h>

#include <cppunit/CompilerOutputter.h>
#include <cppunit/Message.h>
#include <cppunit/Protector.h>
#include <cppunit/TestResult.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/extensions/TypeInfoHelper.h>
#include <cppunit/ui/text/TestRunner.h>
#include <gtest/gtest.h>

#include <typeinfo>

#include "Common.h"
#include "ClientException.h"

char testName[256];
bool progress = false;

void __attribute__ ((noreturn))
usage(char *arg0)
{
    printf("Usage: %s "
            "[-p] [-t testName]\n"
           "\t-t\t--test\tRun a specific test..\n"
           "\t-p\t--progress\tShow test progress.\n",
           arg0);
    exit(EXIT_FAILURE);
}

void
cmdline(int argc, char *argv[])
{
    struct option long_options[] = {
        {"test", required_argument, NULL, 't'},
        {"progress", no_argument, NULL, 'p'},
        {0, 0, 0, 0},
    };

    int c;
    int i = 0;
    while ((c = getopt_long(argc, argv, "t:p",
                            long_options, &i)) >= 0)
    {
        switch (c) {
        case 't':
            strncpy(testName, optarg, sizeof(testName));
            testName[sizeof(testName) - 1] = '\0';
            break;
        case 'p':
            progress = true;
            break;
        default:
            usage(argv[0]);
        }
    }
}

// CppUnit doesn't put this in a public header
struct CppUnit::ProtectorContext {
    void* _[2];
    std::string description;
};

int
main(int argc, char *argv[])
{
    int googleArgc = 0;
    char* googleArgv[] = {NULL};
    ::testing::InitGoogleTest(&googleArgc, googleArgv);

    const char *defaultTest = "";
    strncpy(testName, defaultTest, sizeof(testName));
    cmdline(argc, argv);

    CppUnit::TextUi::TestRunner runner;
    CppUnit::TestFactoryRegistry& registry =
            CppUnit::TestFactoryRegistry::getRegistry();

    // This thing will print RAMCloud::Exception::message when RAMCloud
    // exceptions are thrown in our unit tests.
    class RAMCloudProtector : public CppUnit::Protector {
        bool protect(const CppUnit::Functor& functor,
                     const CppUnit::ProtectorContext& context) {
            if (context.description == "setUp() failed")
                RAMCloud::logger.setLogLevels(RAMCloud::WARNING);
            try {
                return functor();
            } catch (const RAMCloud::Exception& e) {
                std::string className(
                    CppUnit::TypeInfoHelper::getClassName(typeid(e)));
                CppUnit::Message message(className + ":\n    " + e.str());
                reportError(context, message);
            } catch (const RAMCloud::ClientException& e) {
                std::string className(
                    CppUnit::TypeInfoHelper::getClassName(typeid(e)));
                CppUnit::Message message(className + ":\n    " + e.str());
                reportError(context, message);
            }
            return false;
        }
    };
    // CppUnit's ProtectorChain::pop() will call delete on our protector, so I
    // guess they want us to use new to allocate it.
    runner.eventManager().pushProtector(new RAMCloudProtector());

    runner.addTest(registry.makeTest());

    // set log levels for gtest unit tests
    struct LoggerEnvironment : public ::testing::Environment {
        void SetUp() { RAMCloud::logger.setLogLevels(RAMCloud::WARNING); }
    };
    ::testing::AddGlobalTestEnvironment(new LoggerEnvironment());

    return !runner.run(testName, false, true, progress) + RUN_ALL_TESTS();
}
<commit_msg>Do not run google tests on -t or ftest<commit_after>/* Copyright (c) 2009 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <getopt.h>
#include <stdlib.h>
#include <string.h>

#include <cppunit/CompilerOutputter.h>
#include <cppunit/Message.h>
#include <cppunit/Protector.h>
#include <cppunit/TestResult.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/extensions/TypeInfoHelper.h>
#include <cppunit/ui/text/TestRunner.h>
#include <gtest/gtest.h>

#include <typeinfo>

#include "Common.h"
#include "ClientException.h"

char testName[256];
bool progress = false;
bool googleOnly = false;

void __attribute__ ((noreturn))
usage(char *arg0)
{
    printf("Usage: %s "
            "[-p] [-t testName]\n"
           "\t-t\t--test\tRun a specific test..\n"
           "\t-p\t--progress\tShow test progress.\n",
           "\t-g\t--google\tRun google tests only.\n",
           arg0);
    exit(EXIT_FAILURE);
}

void
cmdline(int argc, char *argv[])
{
    struct option long_options[] = {
        {"test", required_argument, NULL, 't'},
        {"progress", no_argument, NULL, 'p'},
        {"google", no_argument, NULL, 'g'},
        {0, 0, 0, 0},
    };

    int c;
    int i = 0;
    while ((c = getopt_long(argc, argv, "t:pg",
                            long_options, &i)) >= 0)
    {
        switch (c) {
        case 't':
            strncpy(testName, optarg, sizeof(testName));
            testName[sizeof(testName) - 1] = '\0';
            break;
        case 'p':
            progress = true;
            break;
        case 'g':
            googleOnly = true;
            break;
        default:
            usage(argv[0]);
        }
    }
}

// CppUnit doesn't put this in a public header
struct CppUnit::ProtectorContext {
    void* _[2];
    std::string description;
};

int
main(int argc, char *argv[])
{
    int googleArgc = 0;
    char* googleArgv[] = {NULL};
    ::testing::InitGoogleTest(&googleArgc, googleArgv);

    const char *defaultTest = "";
    strncpy(testName, defaultTest, sizeof(testName));
    cmdline(argc, argv);

    CppUnit::TextUi::TestRunner runner;
    CppUnit::TestFactoryRegistry& registry =
            CppUnit::TestFactoryRegistry::getRegistry();

    // This thing will print RAMCloud::Exception::message when RAMCloud
    // exceptions are thrown in our unit tests.
    class RAMCloudProtector : public CppUnit::Protector {
        bool protect(const CppUnit::Functor& functor,
                     const CppUnit::ProtectorContext& context) {
            if (context.description == "setUp() failed")
                RAMCloud::logger.setLogLevels(RAMCloud::WARNING);
            try {
                return functor();
            } catch (const RAMCloud::Exception& e) {
                std::string className(
                    CppUnit::TypeInfoHelper::getClassName(typeid(e)));
                CppUnit::Message message(className + ":\n    " + e.str());
                reportError(context, message);
            } catch (const RAMCloud::ClientException& e) {
                std::string className(
                    CppUnit::TypeInfoHelper::getClassName(typeid(e)));
                CppUnit::Message message(className + ":\n    " + e.str());
                reportError(context, message);
            }
            return false;
        }
    };
    // CppUnit's ProtectorChain::pop() will call delete on our protector, so I
    // guess they want us to use new to allocate it.
    runner.eventManager().pushProtector(new RAMCloudProtector());

    runner.addTest(registry.makeTest());

    // set log levels for gtest unit tests
    struct LoggerEnvironment : public ::testing::Environment {
        void SetUp() { RAMCloud::logger.setLogLevels(RAMCloud::WARNING); }
    };
    ::testing::AddGlobalTestEnvironment(new LoggerEnvironment());

    int r = 0;
    if (!googleOnly)
        r += !runner.run(testName, false, true, progress);
    if (googleOnly || !strcmp(testName, defaultTest))
        r += RUN_ALL_TESTS();
    return r;
}
<|endoftext|>