<commit_before>#include <Server_Common/Logger.h>
#include <Server_Common/Database.h>
#include <Server_Common/ExdData.h>
#include <boost/lexical_cast.hpp>

#include "ZoneMgr.h"
#include "Zone.h"

#include "ZonePosition.h"

extern Core::Logger g_log;
extern Core::Db::Database g_database;
extern Core::Data::ExdData g_exdData;

namespace Core {

   ZoneMgr::ZoneMgr()
   {
   }

   ZoneMgr::~ZoneMgr()
   {
   }

   void ZoneMgr::loadZonePositionMap()
   {
      auto pQR = g_database.query( "SELECT id, target_zone_id, pos_x, pos_y, pos_z, pos_o, radius " \
                                   "FROM dbzonepositions;" );

      if( !pQR )
         return;

      do
      {
         Db::Field *field = pQR->fetch();
         uint32_t id = field[0].getUInt32();
         uint32_t targetZoneId = field[1].getUInt32();
         Common::FFXIVARR_POSITION3 pos;
         pos.x = field[2].getFloat();
         pos.y = field[3].getFloat();
         pos.z = field[4].getFloat();
         float posO = field[5].getFloat();
         uint32_t radius = field[6].getUInt32();

         m_zonePositionMap[id] = ZonePositionPtr( new ZonePosition( id, targetZoneId, pos, radius, posO ) );

      } while( pQR->nextRow() );
   }

   ZonePositionPtr ZoneMgr::getZonePosition( uint32_t zonePositionId )
   {
      auto it = m_zonePositionMap.find( zonePositionId );

      if( it != m_zonePositionMap.end() )
         return it->second;

      return nullptr;
   }

   bool ZoneMgr::createZones()
   {
      loadZonePositionMap();

      // find zone info from exd
      for( auto zone : g_exdData.m_zoneInfoMap )
      {
         uint32_t zoneId = zone.first;

         auto info = zone.second;
         g_log.Log( LoggingSeverity::info, std::to_string( info.id ) + "\t" + info.zone_str );

         ZonePtr pZone( new Zone( info.id, info.layout_id, info.zone_name, info.zone_str, false ) );
         pZone->init();
         m_zoneMap[info.id] = pZone;
      }

      //do
      //{
      //   Db::Field *field = pQR->fetch();
      //   uint16_t id = field[0].getUInt16();
      //   std::string inName = field[1].getString();
      //   std::string name = field[2].getString();
      //   uint32_t layoutId = field[3].getUInt32();
      //   bool isPrivate = field[4].getBool();

      //   if(!isPrivate)
      //   {
      //      g_log.Log(LoggingSeverity::info, std::to_string(id) + "\t" + inName + " - " + name);

      //      ZonePtr pZone( new Zone( id, layoutId, name, inName, isPrivate ) );

      //      m_zoneMap[id] = pZone;

      //      // start the region worker
      //      // ThreadPool->executeTask(pRegion);
      //   }
      //   else
      //   {
      //      //Console->outTime(" --> %s", inName.c_str());
      //      //Console->outTime("\tCached private instance...", name.c_str());

      //      //// write the instance data into the instance cache for later use
      //      //InstanceCacheEntry * pICE = new InstanceCacheEntry();
      //      //pICE->id		= id;
      //      //pICE->inName	= inName;
      //      //pICE->minX		= minX;
      //      //pICE->maxX		= maxX;
      //      //pICE->minY		= minY;
      //      //pICE->maxY		= maxY;
      //      //pICE->name		= name;
      //      //pICE->layoutId  = layoutId;
      //      //pICE->isPrivate	= isPrivate;

      //      //m_instanceCache[pICE->id] = pICE;
      //      //m_instanceCacheName[inName] = pICE;

      //      //createInstance(pICE);
      //   }

      //} while(pQR->nextRow());

      return true;
   }

   void ZoneMgr::updateZones()
   {
      for( auto zone : m_zoneMap )
      {
         zone.second->runZoneLogic();
      }
   }

   ZonePtr ZoneMgr::getZone( uint32_t zoneId )
   {
      ZoneMap::iterator it;
      it = m_zoneMap.find( zoneId );

      if( it != m_zoneMap.end() )
         return it->second;

      return nullptr;
   }

}
<commit_msg>Fix zoneline handler<commit_after>#include <Server_Common/Logger.h>
#include <Server_Common/Database.h>
#include <Server_Common/ExdData.h>
#include <boost/lexical_cast.hpp>

#include "ZoneMgr.h"
#include "Zone.h"

#include "ZonePosition.h"

extern Core::Logger g_log;
extern Core::Db::Database g_database;
extern Core::Data::ExdData g_exdData;

namespace Core {

   ZoneMgr::ZoneMgr()
   {
   }

   ZoneMgr::~ZoneMgr()
   {
   }

   void ZoneMgr::loadZonePositionMap()
   {
      auto pQR = g_database.query( "SELECT id, target_zone_id, pos_x, pos_y, pos_z, pos_o, radius " \
                                   "FROM zonepositions;" );

      if( !pQR )
         return;

      do
      {
         Db::Field *field = pQR->fetch();
         uint32_t id = field[0].getUInt32();
         uint32_t targetZoneId = field[1].getUInt32();
         Common::FFXIVARR_POSITION3 pos;
         pos.x = field[2].getFloat();
         pos.y = field[3].getFloat();
         pos.z = field[4].getFloat();
         float posO = field[5].getFloat();
         uint32_t radius = field[6].getUInt32();

         m_zonePositionMap[id] = ZonePositionPtr( new ZonePosition( id, targetZoneId, pos, radius, posO ) );

      } while( pQR->nextRow() );
   }

   ZonePositionPtr ZoneMgr::getZonePosition( uint32_t zonePositionId )
   {
      auto it = m_zonePositionMap.find( zonePositionId );

      if( it != m_zonePositionMap.end() )
         return it->second;

      return nullptr;
   }

   bool ZoneMgr::createZones()
   {
      loadZonePositionMap();

      // find zone info from exd
      for( auto zone : g_exdData.m_zoneInfoMap )
      {
         uint32_t zoneId = zone.first;

         auto info = zone.second;
         g_log.Log( LoggingSeverity::info, std::to_string( info.id ) + "\t" + info.zone_str );

         ZonePtr pZone( new Zone( info.id, info.layout_id, info.zone_name, info.zone_str, false ) );
         pZone->init();
         m_zoneMap[info.id] = pZone;
      }

      //do
      //{
      //   Db::Field *field = pQR->fetch();
      //   uint16_t id = field[0].getUInt16();
      //   std::string inName = field[1].getString();
      //   std::string name = field[2].getString();
      //   uint32_t layoutId = field[3].getUInt32();
      //   bool isPrivate = field[4].getBool();

      //   if(!isPrivate)
      //   {
      //      g_log.Log(LoggingSeverity::info, std::to_string(id) + "\t" + inName + " - " + name);

      //      ZonePtr pZone( new Zone( id, layoutId, name, inName, isPrivate ) );

      //      m_zoneMap[id] = pZone;

      //      // start the region worker
      //      // ThreadPool->executeTask(pRegion);
      //   }
      //   else
      //   {
      //      //Console->outTime(" --> %s", inName.c_str());
      //      //Console->outTime("\tCached private instance...", name.c_str());

      //      //// write the instance data into the instance cache for later use
      //      //InstanceCacheEntry * pICE = new InstanceCacheEntry();
      //      //pICE->id		= id;
      //      //pICE->inName	= inName;
      //      //pICE->minX		= minX;
      //      //pICE->maxX		= maxX;
      //      //pICE->minY		= minY;
      //      //pICE->maxY		= maxY;
      //      //pICE->name		= name;
      //      //pICE->layoutId  = layoutId;
      //      //pICE->isPrivate	= isPrivate;

      //      //m_instanceCache[pICE->id] = pICE;
      //      //m_instanceCacheName[inName] = pICE;

      //      //createInstance(pICE);
      //   }

      //} while(pQR->nextRow());

      return true;
   }

   void ZoneMgr::updateZones()
   {
      for( auto zone : m_zoneMap )
      {
         zone.second->runZoneLogic();
      }
   }

   ZonePtr ZoneMgr::getZone( uint32_t zoneId )
   {
      ZoneMap::iterator it;
      it = m_zoneMap.find( zoneId );

      if( it != m_zoneMap.end() )
         return it->second;

      return nullptr;
   }

}
<|endoftext|>


<commit_before>/*
 *  VHDL code generation for logic devices.
 *
 *  Copyright (C) 2008  Nick Gasson (nick@nickg.me.uk)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "vhdl_target.h"
#include "vhdl_element.hh"

#include <cassert>

/*
 * Convert the inputs of a logic gate to a binary expression.
 */
static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op,
                                 ivl_net_logic_t log)
{
   // Not always std_logic but this is probably OK since
   // the program has already been type checked
   vhdl_binop_expr *gate =
      new vhdl_binop_expr(op, vhdl_type::std_logic());

   int npins = ivl_logic_pins(log);
   for (int i = 1; i < npins; i++) {
      ivl_nexus_t input = ivl_logic_pin(log, i);
      gate->add_expr(nexus_to_var_ref(scope, input));
   }

   return gate;
}

/*
 * Convert a gate intput to an unary expression.
 */
static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op,
                                ivl_net_logic_t log)
{
   ivl_nexus_t input = ivl_logic_pin(log, 1);
   assert(input);

   vhdl_expr *operand = nexus_to_var_ref(scope, input);
   return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic());
}

static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0)
{
   ivl_nexus_t output = ivl_logic_pin(log, 0);
   vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);
   assert(lhs);

   vhdl_expr *val = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
   assert(val);

   vhdl_expr *sel = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 2));
   assert(val);

   vhdl_expr *on = new vhdl_const_bit(if0 ? '0' : '1');
   vhdl_expr *cmp = new vhdl_binop_expr(sel, VHDL_BINOP_EQ, on, NULL);

   ivl_signal_t sig = find_signal_named(lhs->get_name(), arch->get_scope());
   char zbit;
   switch (ivl_signal_type(sig)) {
   case IVL_SIT_TRI0:
      zbit = '0';
      break;
   case IVL_SIT_TRI1:
      zbit = '1';
      break;
   case IVL_SIT_TRI:
   default:
      zbit = 'Z';
   }

   vhdl_const_bit *z = new vhdl_const_bit(zbit);
   vhdl_cassign_stmt *cass = new vhdl_cassign_stmt(lhs, z);
   cass->add_condition(val, cmp);

   arch->add_stmt(cass);
}

static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log)
{
   switch (ivl_logic_type(log)) {
   case IVL_LO_NOT:
      return input_to_expr(scope, VHDL_UNARYOP_NOT, log);
   case IVL_LO_AND:
      return inputs_to_expr(scope, VHDL_BINOP_AND, log);
   case IVL_LO_OR:
      return inputs_to_expr(scope, VHDL_BINOP_OR, log);
   case IVL_LO_XOR:
      return inputs_to_expr(scope, VHDL_BINOP_XOR, log);
   case IVL_LO_BUF:
   case IVL_LO_BUFZ:
      return nexus_to_var_ref(scope, ivl_logic_pin(log, 1));
   case IVL_LO_PULLUP:
      return new vhdl_const_bit('1');
   case IVL_LO_PULLDOWN:
      return new vhdl_const_bit('0');
   default:
      error("Don't know how to translate logic type = %d to expression",
            ivl_logic_type(log));
      return NULL;
   }
}

void draw_logic(vhdl_arch *arch, ivl_net_logic_t log)
{
   switch (ivl_logic_type(log)) {
   case IVL_LO_BUFIF0:
      bufif_logic(arch, log, true);
      break;
   case IVL_LO_BUFIF1:
      bufif_logic(arch, log, false);
      break;
   default:
      {
         // The output is always pin zero
         ivl_nexus_t output = ivl_logic_pin(log, 0);
         vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);

         vhdl_expr *rhs = translate_logic_inputs(arch->get_scope(), log);
         vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs);

         ivl_expr_t delay = ivl_logic_delay(log, 1);
         if (delay)
            ass->set_after(translate_time_expr(delay));

         arch->add_stmt(ass);
      }
   }
}
<commit_msg>Stub for UDP logic devices<commit_after>/*
 *  VHDL code generation for logic devices.
 *
 *  Copyright (C) 2008  Nick Gasson (nick@nickg.me.uk)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "vhdl_target.h"
#include "vhdl_element.hh"

#include <cassert>

/*
 * Convert the inputs of a logic gate to a binary expression.
 */
static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op,
                                 ivl_net_logic_t log)
{
   // Not always std_logic but this is probably OK since
   // the program has already been type checked
   vhdl_binop_expr *gate =
      new vhdl_binop_expr(op, vhdl_type::std_logic());

   int npins = ivl_logic_pins(log);
   for (int i = 1; i < npins; i++) {
      ivl_nexus_t input = ivl_logic_pin(log, i);
      gate->add_expr(nexus_to_var_ref(scope, input));
   }

   return gate;
}

/*
 * Convert a gate intput to an unary expression.
 */
static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op,
                                ivl_net_logic_t log)
{
   ivl_nexus_t input = ivl_logic_pin(log, 1);
   assert(input);

   vhdl_expr *operand = nexus_to_var_ref(scope, input);
   return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic());
}

static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0)
{
   ivl_nexus_t output = ivl_logic_pin(log, 0);
   vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);
   assert(lhs);

   vhdl_expr *val = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
   assert(val);

   vhdl_expr *sel = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 2));
   assert(val);

   vhdl_expr *on = new vhdl_const_bit(if0 ? '0' : '1');
   vhdl_expr *cmp = new vhdl_binop_expr(sel, VHDL_BINOP_EQ, on, NULL);

   ivl_signal_t sig = find_signal_named(lhs->get_name(), arch->get_scope());
   char zbit;
   switch (ivl_signal_type(sig)) {
   case IVL_SIT_TRI0:
      zbit = '0';
      break;
   case IVL_SIT_TRI1:
      zbit = '1';
      break;
   case IVL_SIT_TRI:
   default:
      zbit = 'Z';
   }

   vhdl_const_bit *z = new vhdl_const_bit(zbit);
   vhdl_cassign_stmt *cass = new vhdl_cassign_stmt(lhs, z);
   cass->add_condition(val, cmp);

   arch->add_stmt(cass);
}

static void udp_logic(vhdl_arch *arch, ivl_udp_t udp)
{

}

static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log)
{
   switch (ivl_logic_type(log)) {
   case IVL_LO_NOT:
      return input_to_expr(scope, VHDL_UNARYOP_NOT, log);
   case IVL_LO_AND:
      return inputs_to_expr(scope, VHDL_BINOP_AND, log);
   case IVL_LO_OR:
      return inputs_to_expr(scope, VHDL_BINOP_OR, log);
   case IVL_LO_XOR:
      return inputs_to_expr(scope, VHDL_BINOP_XOR, log);
   case IVL_LO_BUF:
   case IVL_LO_BUFZ:
      return nexus_to_var_ref(scope, ivl_logic_pin(log, 1));
   case IVL_LO_PULLUP:
      return new vhdl_const_bit('1');
   case IVL_LO_PULLDOWN:
      return new vhdl_const_bit('0');
   default:
      error("Don't know how to translate logic type = %d to expression",
            ivl_logic_type(log));
      return NULL;
   }
}

void draw_logic(vhdl_arch *arch, ivl_net_logic_t log)
{
   switch (ivl_logic_type(log)) {
   case IVL_LO_BUFIF0:
      bufif_logic(arch, log, true);
      break;
   case IVL_LO_BUFIF1:
      bufif_logic(arch, log, false);
      break;
   case IVL_LO_UDP:
      udp_logic(arch, ivl_logic_udp(log));
      break;
   default:
      {
         // The output is always pin zero
         ivl_nexus_t output = ivl_logic_pin(log, 0);
         vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);

         vhdl_expr *rhs = translate_logic_inputs(arch->get_scope(), log);
         vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs);

         ivl_expr_t delay = ivl_logic_delay(log, 1);
         if (delay)
            ass->set_after(translate_time_expr(delay));

         arch->add_stmt(ass);
      }
   }
}
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; version 3 of the License.
 *
 * This program 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.
 */

#include "../config.h"
#include "../dbmanager.h"
#include "../iconmanager.h"
#include "../mainwindow.h"
#include "../tools/logger.h"
#include "../widgets/resultview.h"

#include "queryeditorwidget.h"

#include <QSqlQuery>

QueryEditorWidget::QueryEditorWidget(QWidget *parent)
  : AbstractTabWidget(parent) {
  setupUi(this);
  setupWidgets();
  setupConnections();

  setAutoDelete(false);

  model       = new QSqlQueryModel(this);
  shortModel  = new QStandardItemModel(this);
  // watcher     = new QFileSystemWatcher(this);
}

AbstractTabWidget::Actions QueryEditorWidget::availableActions() {
  Actions ret = baseActions;
  if (!isSaved()) {
    ret |= Save;
  }

  if (editor->document()->isUndoAvailable()) {
    ret |= Undo;
  }

  if (editor->document()->isRedoAvailable()) {
    ret |= Redo;
  }

  return ret;
}

void QueryEditorWidget::checkDbOpen() {
  DbManager::lastIndex = dbChooser->currentIndex();

  QSqlDatabase *db = DbManager::getDatabase(dbChooser->currentIndex());
  if (db == NULL) {
    runButton->setEnabled(false);
    return;
  }

  runButton->setEnabled(db->isOpen());

  if (!db->isOpen() || db->driverName().startsWith("QOCI")) {
    return;
  }

  QMultiMap<QString, QString> fields;
  QSqlRecord r;
  QStringList tables = db->tables();
  foreach (QString t, tables) {
    r = db->record(t);
    for (int i=0; i<r.count(); i++) {
      fields.insert(t, r.fieldName(i));
    }
  }

  editor->reloadContext(tables, fields);
}

void QueryEditorWidget::closeEvent(QCloseEvent *event) {
  if (isSaved()) {
    event->accept();
  } else {
    if (confirmClose()) {
      event->accept();
    } else {
      event->ignore();
    }
  }
}

bool QueryEditorWidget::confirmClose() {
  // check if it's saved or not
  if (!isSaved()) {
    int ret = QMessageBox::warning(
        this,
        tr( "DbMaster" ),
        tr( "Warning ! All your modifications will be lost.\nDo you want to save ?" ),
        QMessageBox::Cancel | QMessageBox::Save | QMessageBox::Discard,
        QMessageBox::Cancel);

    switch (ret) {
    case QMessageBox::Cancel:
      return false;

    case QMessageBox::Save:
      return save();
    }
  }

  return true;
}

int QueryEditorWidget::confirmCloseAll() {
  if (isSaved()) {
    return QMessageBox::Yes;
  }

  QString msg(tr("Warning ! All your modifications will be lost.\nDo you want to save ?"));
  if (filePath.isNull()) {
    msg = QString(tr("Warning ! %1 hasn't been saved\nDo you want to save ?"))
                  .arg(filePath);
  }

  int ret = QMessageBox::warning(this, tr("DbMaster"), msg,
                                 QMessageBox::Save    | QMessageBox::SaveAll  |
                                 QMessageBox::No      | QMessageBox::NoAll    |
                                 QMessageBox::Cancel,
                                 QMessageBox::Cancel);

  return ret;
}

void QueryEditorWidget::copy() {
  editor->copy();
}

void QueryEditorWidget::cut() {
  editor->cut();
}

QString QueryEditorWidget::file() {
  return filePath;
}

void QueryEditorWidget::onFileChanged(QString path) {
  if (QFile::exists(path)) {
    // Le fichier a été modifié
  } else {
    // Le fichier a été supprimé
  }
}

QIcon QueryEditorWidget::icon() {
  return IconManager::get("accessories-text-editor");
}

QString QueryEditorWidget::id() {
  QString ret = "q";
  if (!filePath.isEmpty()) {
    ret.append(" %1").arg( filePath );
  }
  return ret;
}

bool QueryEditorWidget::isSaved() {
  return !editor->document()->isModified();
}

void QueryEditorWidget::keyPressEvent(QKeyEvent *event) {
  if (event->key() == Qt::Key_Escape) {
    // Appui touche échap = masque le panel de résultat
    tabView->hide();
    resultButton->setChecked(false);
  } else {
    QWidget::keyPressEvent(event);
  }
}

void QueryEditorWidget::lowerCase() {
  QTextCursor tc = editor->textCursor();
  if (tc.selectedText().size() > 0) {
    QString txt = tc.selectedText();
    tc.removeSelectedText();
    tc.insertText(txt.toLower());
    tc.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, txt.size());
    editor->setTextCursor(tc);
  }
}

void QueryEditorWidget::open(QString path) {
  if (!confirmClose())
    return;

  setFilePath(path);
  reloadFile();
}

void QueryEditorWidget::paste() {
  editor->paste();
}

void QueryEditorWidget::print() {
  QPainter painter;
  painter.begin(&m_printer);
  editor->document()->drawContents(&painter);
  painter.end();
}

QPrinter *QueryEditorWidget::printer() {
  return &m_printer;
}

void QueryEditorWidget::redo() {
  editor->redo();
}

void QueryEditorWidget::refresh() {
  checkDbOpen();
}

void QueryEditorWidget::reload() {
  run();
}

/**
 * Called after open(QString)
 */
void QueryEditorWidget::reloadFile() {
  if (!confirmClose()) {
    return;
  }

  editor->clear();

  // loading the file
  QFile file(filePath);
  if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
    // OMG ! an error occured
    QMessageBox::critical(this, tr("DbMaster"),
                          tr("Unable to open the file !"),
                          QMessageBox::Ok );
    return;
  }

  if (Config::editorEncoding == "latin1") {
    editor->append(QString::fromLatin1(file.readAll().data()));
  }

  if (Config::editorEncoding == "utf8") {
    editor->append(QString::fromUtf8(file.readAll().data()));
  }

  file.close();

  editor->document()->setModified(false);

  emit fileChanged(filePath);
}

void QueryEditorWidget::run() {
  QString qtext = editor->textCursor().selectedText();
  if (qtext.isEmpty()) {
    qtext = editor->toPlainText();
  }

  QSqlDatabase* db = DbManager::getDatabase(dbChooser->currentIndex());
  query = QSqlQuery(*db);
  query.exec(qtext);
  model->setQuery(query);

  emit queryFinished();
}

/**
 * @returns false in case of error
 */
bool QueryEditorWidget::save() {
  if (isSaved()) {
    return true;
  }

  if (filePath.isNull()) {
    setFilePath(QFileDialog::getSaveFileName(
        this, tr("DbMaster"), lastDir.path(),
        tr("Query file (*.sql);;All files (*.*)")));

    if(filePath.isNull())
      return false;
  }

  QFile file(filePath);
  lastDir = filePath;

  if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    QMessageBox::critical(this, tr("DbMaster"), tr("Unable to save the file !"),
                          QMessageBox::Ok);
    return false;
  }

  editor->setEnabled(false);
  setCursor(Qt::BusyCursor);

  QTextStream out( &file );
  QStringList list( editor->toPlainText().split( '\n' ) );

  int count = list.count();
  for (int i = 0; i < count; i++) {
    out << list[i];
    if( i != count )
    out << '\n';
  }

  file.close();

  editor->document()->setModified(false);

  editor->setEnabled(true);
  setCursor(Qt::ArrowCursor);

  emit modificationChanged(editor->document()->isModified());
  return true;
}

void QueryEditorWidget::saveAs(QString name) {
  filePath = name;
  save();
}

void QueryEditorWidget::selectAll() {
  editor->selectAll();
}

void QueryEditorWidget::setFilePath(QString path) {
  // watcher->removePath(this->filePath);
  this->filePath = path;

  if(path.size() > 30)
    path = QFileInfo(path).fileName();

  pathLabel->setText(path);
  if (path.length() > 0) {
    // watcher->addPath(path);
  }
}

void QueryEditorWidget::setupConnections() {
  connect(dbChooser, SIGNAL(currentIndexChanged(int)),
          this, SLOT(checkDbOpen()));
  connect(tabView, SIGNAL(reloadRequested()), this, SLOT(reload()));

  connect(runButton, SIGNAL(clicked()), this, SLOT(start()));

  connect(editor->document(), SIGNAL(modificationChanged(bool)),
          this, SIGNAL(modificationChanged(bool)));

  connect(this, SIGNAL(queryFinished()),
          this, SLOT(validateQuery()));

  // connect(watcher, SIGNAL(fileChanged(QString)),
  //         this, SLOT(onFileChanged(QString)));
}

void QueryEditorWidget::setupWidgets() {
  editor->setFont(Config::editorFont);

  tabView->hide();

  statusBar = new QStatusBar(this);
  statusBar->setSizeGripEnabled(false);
  gridLayout->addWidget(statusBar, gridLayout->rowCount(), 0, 1, -1);

  resultButton = new QToolButton(this);
  resultButton->setText(tr("Display result"));
  resultButton->setCheckable(true);
  resultButton->setEnabled(false);
  statusBar->addPermanentWidget(resultButton);
  connect(resultButton, SIGNAL(clicked(bool)),
          tabView, SLOT(setVisible(bool)));

  baseActions = CaseLower | CaseUpper | Copy | Cut | Paste | Print | SaveAs
              | Search | SelectAll;

  dbChooser->setModel(DbManager::model());
  dbChooser->setCurrentIndex(DbManager::lastIndex);

  runButton->setIcon(IconManager::get("player_play"));

  refresh();
}

void QueryEditorWidget::showEvent(QShowEvent *event) {
  editor->setFocus();
}

void QueryEditorWidget::start() {
  resultButton->setChecked(false);
  tabView->setVisible(false);
  resultButton->setEnabled(false);
  runButton->setEnabled(false);

  statusBar->showMessage(tr("Running..."));

  QThreadPool::globalInstance()->start(this);
}

QString QueryEditorWidget::title() {
  QString t;
  if(!filePath.isEmpty())
    t = QFileInfo(filePath).fileName();
  else
    t = tr("Query editor");

  return t;
}

QTextEdit* QueryEditorWidget::textEdit() {
  return editor;
}

void QueryEditorWidget::undo() {
  editor->undo();
}

void QueryEditorWidget::upperCase() {
  QTextCursor tc = editor->textCursor();
  if (tc.selectedText().size() > 0) {
    QString txt = tc.selectedText();
    tc.removeSelectedText();
    tc.insertText(txt.toUpper());
    tc.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, txt.size());
    editor->setTextCursor(tc);
  }
}

void QueryEditorWidget::validateQuery() {
  // tabWidget->setTabEnabled(1, false);

  QString logMsg;

  switch(query.lastError().type()) {
  case QSqlError::NoError:
    tabView->setQuery(model);
    tabView->setVisible(true);
    resultButton->setEnabled(true);
    logMsg = tr("Query executed with success (%1 lines returned)")
        .arg(model->rowCount());
        // .arg(token->duration());

    statusBar->showMessage(logMsg);
    break;

  default:
    logMsg = tr("Unable to run query");
    statusBar->showMessage(logMsg);
    logMsg.append(
          QString("
%1")
            .arg(query.lastError().text()));
    break;
  }

  logMsg.append(
        QString("
%1")
          .arg(query.lastQuery().replace("\n", " ")));
  Logger::instance->log(logMsg);

  runButton->setEnabled(true);
}
<commit_msg>Button error<commit_after>/*
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; version 3 of the License.
 *
 * This program 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.
 */

#include "../config.h"
#include "../dbmanager.h"
#include "../iconmanager.h"
#include "../mainwindow.h"
#include "../tools/logger.h"
#include "../widgets/resultview.h"

#include "queryeditorwidget.h"

#include <QSqlQuery>

QueryEditorWidget::QueryEditorWidget(QWidget *parent)
  : AbstractTabWidget(parent) {
  setupUi(this);
  setupWidgets();
  setupConnections();

  setAutoDelete(false);

  model       = new QSqlQueryModel(this);
  shortModel  = new QStandardItemModel(this);
  // watcher     = new QFileSystemWatcher(this);
}

AbstractTabWidget::Actions QueryEditorWidget::availableActions() {
  Actions ret = baseActions;
  if (!isSaved()) {
    ret |= Save;
  }

  if (editor->document()->isUndoAvailable()) {
    ret |= Undo;
  }

  if (editor->document()->isRedoAvailable()) {
    ret |= Redo;
  }

  return ret;
}

void QueryEditorWidget::checkDbOpen() {
  DbManager::lastIndex = dbChooser->currentIndex();

  QSqlDatabase *db = DbManager::getDatabase(dbChooser->currentIndex());
  if (db == NULL) {
    runButton->setEnabled(false);
    return;
  }

  runButton->setEnabled(db->isOpen());

  if (!db->isOpen() || db->driverName().startsWith("QOCI")) {
    return;
  }

  QMultiMap<QString, QString> fields;
  QSqlRecord r;
  QStringList tables = db->tables();
  foreach (QString t, tables) {
    r = db->record(t);
    for (int i=0; i<r.count(); i++) {
      fields.insert(t, r.fieldName(i));
    }
  }

  editor->reloadContext(tables, fields);
}

void QueryEditorWidget::closeEvent(QCloseEvent *event) {
  if (isSaved()) {
    event->accept();
  } else {
    if (confirmClose()) {
      event->accept();
    } else {
      event->ignore();
    }
  }
}

bool QueryEditorWidget::confirmClose() {
  // check if it's saved or not
  if (!isSaved()) {
    int ret = QMessageBox::warning(
        this,
        tr( "DbMaster" ),
        tr( "Warning ! All your modifications will be lost.\nDo you want to save ?" ),
        QMessageBox::Cancel | QMessageBox::Save | QMessageBox::Discard,
        QMessageBox::Cancel);

    switch (ret) {
    case QMessageBox::Cancel:
      return false;

    case QMessageBox::Save:
      return save();
    }
  }

  return true;
}

int QueryEditorWidget::confirmCloseAll() {
  if (isSaved()) {
    return QMessageBox::Yes;
  }

  QString msg(tr("Warning ! All your modifications will be lost.\nDo you want to save ?"));
  if (filePath.isNull()) {
    msg = QString(tr("Warning ! %1 hasn't been saved\nDo you want to save ?"))
                  .arg(filePath);
  }

  int ret = QMessageBox::warning(this, tr("DbMaster"), msg,
                                 QMessageBox::Save    | QMessageBox::SaveAll  |
                                 QMessageBox::No      | QMessageBox::NoAll    |
                                 QMessageBox::Cancel,
                                 QMessageBox::Cancel);

  return ret;
}

void QueryEditorWidget::copy() {
  editor->copy();
}

void QueryEditorWidget::cut() {
  editor->cut();
}

QString QueryEditorWidget::file() {
  return filePath;
}

void QueryEditorWidget::onFileChanged(QString path) {
  if (QFile::exists(path)) {
    // Le fichier a été modifié
  } else {
    // Le fichier a été supprimé
  }
}

QIcon QueryEditorWidget::icon() {
  return IconManager::get("accessories-text-editor");
}

QString QueryEditorWidget::id() {
  QString ret = "q";
  if (!filePath.isEmpty()) {
    ret.append(" %1").arg( filePath );
  }
  return ret;
}

bool QueryEditorWidget::isSaved() {
  return !editor->document()->isModified();
}

void QueryEditorWidget::keyPressEvent(QKeyEvent *event) {
  if (event->key() == Qt::Key_Escape) {
    // Appui touche échap = masque le panel de résultat
    tabView->hide();
    resultButton->setChecked(false);
  } else {
    QWidget::keyPressEvent(event);
  }
}

void QueryEditorWidget::lowerCase() {
  QTextCursor tc = editor->textCursor();
  if (tc.selectedText().size() > 0) {
    QString txt = tc.selectedText();
    tc.removeSelectedText();
    tc.insertText(txt.toLower());
    tc.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, txt.size());
    editor->setTextCursor(tc);
  }
}

void QueryEditorWidget::open(QString path) {
  if (!confirmClose())
    return;

  setFilePath(path);
  reloadFile();
}

void QueryEditorWidget::paste() {
  editor->paste();
}

void QueryEditorWidget::print() {
  QPainter painter;
  painter.begin(&m_printer);
  editor->document()->drawContents(&painter);
  painter.end();
}

QPrinter *QueryEditorWidget::printer() {
  return &m_printer;
}

void QueryEditorWidget::redo() {
  editor->redo();
}

void QueryEditorWidget::refresh() {
  checkDbOpen();
}

void QueryEditorWidget::reload() {
  run();
}

/**
 * Called after open(QString)
 */
void QueryEditorWidget::reloadFile() {
  if (!confirmClose()) {
    return;
  }

  editor->clear();

  // loading the file
  QFile file(filePath);
  if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
    // OMG ! an error occured
    QMessageBox::critical(this, tr("DbMaster"),
                          tr("Unable to open the file !"),
                          QMessageBox::Ok );
    return;
  }

  if (Config::editorEncoding == "latin1") {
    editor->append(QString::fromLatin1(file.readAll().data()));
  }

  if (Config::editorEncoding == "utf8") {
    editor->append(QString::fromUtf8(file.readAll().data()));
  }

  file.close();

  editor->document()->setModified(false);

  emit fileChanged(filePath);
}

void QueryEditorWidget::run() {
  QString qtext = editor->textCursor().selectedText();
  if (qtext.isEmpty()) {
    qtext = editor->toPlainText();
  }

  QSqlDatabase* db = DbManager::getDatabase(dbChooser->currentIndex());
  query = QSqlQuery(*db);
  query.exec(qtext);
  model->setQuery(query);

  emit queryFinished();
}

/**
 * @returns false in case of error
 */
bool QueryEditorWidget::save() {
  if (isSaved()) {
    return true;
  }

  if (filePath.isNull()) {
    setFilePath(QFileDialog::getSaveFileName(
        this, tr("DbMaster"), lastDir.path(),
        tr("Query file (*.sql);;All files (*.*)")));

    if(filePath.isNull())
      return false;
  }

  QFile file(filePath);
  lastDir = filePath;

  if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    QMessageBox::critical(this, tr("DbMaster"), tr("Unable to save the file !"),
                          QMessageBox::Ok);
    return false;
  }

  editor->setEnabled(false);
  setCursor(Qt::BusyCursor);

  QTextStream out( &file );
  QStringList list( editor->toPlainText().split( '\n' ) );

  int count = list.count();
  for (int i = 0; i < count; i++) {
    out << list[i];
    if( i != count )
    out << '\n';
  }

  file.close();

  editor->document()->setModified(false);

  editor->setEnabled(true);
  setCursor(Qt::ArrowCursor);

  emit modificationChanged(editor->document()->isModified());
  return true;
}

void QueryEditorWidget::saveAs(QString name) {
  filePath = name;
  save();
}

void QueryEditorWidget::selectAll() {
  editor->selectAll();
}

void QueryEditorWidget::setFilePath(QString path) {
  // watcher->removePath(this->filePath);
  this->filePath = path;

  if(path.size() > 30)
    path = QFileInfo(path).fileName();

  pathLabel->setText(path);
  if (path.length() > 0) {
    // watcher->addPath(path);
  }
}

void QueryEditorWidget::setupConnections() {
  connect(dbChooser, SIGNAL(currentIndexChanged(int)),
          this, SLOT(checkDbOpen()));
  connect(tabView, SIGNAL(reloadRequested()), this, SLOT(reload()));

  connect(runButton, SIGNAL(clicked()), this, SLOT(start()));

  connect(editor->document(), SIGNAL(modificationChanged(bool)),
          this, SIGNAL(modificationChanged(bool)));

  connect(this, SIGNAL(queryFinished()),
          this, SLOT(validateQuery()));

  // connect(watcher, SIGNAL(fileChanged(QString)),
  //         this, SLOT(onFileChanged(QString)));
}

void QueryEditorWidget::setupWidgets() {
  editor->setFont(Config::editorFont);

  tabView->hide();

  statusBar = new QStatusBar(this);
  statusBar->setSizeGripEnabled(false);
  gridLayout->addWidget(statusBar, gridLayout->rowCount(), 0, 1, -1);

  resultButton = new QToolButton(this);
  resultButton->setText(tr("Display result"));
  resultButton->setCheckable(true);
  resultButton->setEnabled(false);
  statusBar->addPermanentWidget(resultButton);
  connect(resultButton, SIGNAL(clicked(bool)),
          tabView, SLOT(setVisible(bool)));

  baseActions = CaseLower | CaseUpper | Copy | Cut | Paste | Print | SaveAs
              | Search | SelectAll;

  dbChooser->setModel(DbManager::model());
  dbChooser->setCurrentIndex(DbManager::lastIndex);

  runButton->setIcon(IconManager::get("player_play"));

  refresh();
}

void QueryEditorWidget::showEvent(QShowEvent *event) {
  editor->setFocus();
}

void QueryEditorWidget::start() {
  resultButton->setChecked(false);
  tabView->setVisible(false);
  resultButton->setEnabled(false);
  runButton->setEnabled(false);

  statusBar->showMessage(tr("Running..."));

  QThreadPool::globalInstance()->start(this);
}

QString QueryEditorWidget::title() {
  QString t;
  if(!filePath.isEmpty())
    t = QFileInfo(filePath).fileName();
  else
    t = tr("Query editor");

  return t;
}

QTextEdit* QueryEditorWidget::textEdit() {
  return editor;
}

void QueryEditorWidget::undo() {
  editor->undo();
}

void QueryEditorWidget::upperCase() {
  QTextCursor tc = editor->textCursor();
  if (tc.selectedText().size() > 0) {
    QString txt = tc.selectedText();
    tc.removeSelectedText();
    tc.insertText(txt.toUpper());
    tc.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, txt.size());
    editor->setTextCursor(tc);
  }
}

void QueryEditorWidget::validateQuery() {
  // tabWidget->setTabEnabled(1, false);

  QString logMsg;

  switch(query.lastError().type()) {
  case QSqlError::NoError:
    tabView->setQuery(model);
    tabView->setVisible(true);
    resultButton->setEnabled(true);
    resultButton->setChecked(true);
    logMsg = tr("Query executed with success (%1 lines returned)")
        .arg(model->rowCount());
        // .arg(token->duration());

    statusBar->showMessage(logMsg);
    break;

  default:
    logMsg = tr("Unable to run query");
    statusBar->showMessage(logMsg);
    logMsg.append(
          QString("
%1")
            .arg(query.lastError().text()));
    break;
  }

  logMsg.append(
        QString("
%1")
          .arg(query.lastQuery().replace("\n", " ")));
  Logger::instance->log(logMsg);

  runButton->setEnabled(true);
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*
 * Modified by ScyllaDB
 * Copyright (C) 2015 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 <memory>

#include "utils/data_output.hh"
#include "core/future.hh"
#include "core/shared_ptr.hh"
#include "core/stream.hh"
#include "replay_position.hh"
#include "commitlog_entry.hh"

namespace seastar { class file; }

#include "seastarx.hh"

namespace db {

class config;
class rp_set;
class rp_handle;

/*
 * Commit Log tracks every write operation into the system. The aim of
 * the commit log is to be able to successfully recover data that was
 * not stored to disk via the Memtable.
 *
 * This impl is cassandra log format compatible (for what it is worth).
 * The behaviour is similar, but not 100% identical as "stock cl".
 *
 * Files are managed with "normal" file writes (as normal as seastar
 * gets) - no mmapping. Data is kept in internal buffers which, when
 * full, are written to disk (see below). Files are also flushed
 * periodically (or always), ensuring all data is written + writes are
 * complete.
 *
 * In BATCH mode, every write to the log will also send the data to disk
 * + issue a flush and wait for both to complete.
 *
 * In PERIODIC mode, most writes will only add to the internal memory
 * buffers. If the mem buffer is saturated, data is sent to disk, but we
 * don't wait for the write to complete. However, if periodic (timer)
 * flushing has not been done in X ms, we will write + flush to file. In
 * which case we wait for it.
 *
 * The commitlog does not guarantee any ordering between "add" callers
 * (due to the above). The actual order in the commitlog is however
 * identified by the replay_position returned.
 *
 * Like the stock cl, the log segments keep track of the highest dirty
 * (added) internal position for a given table id (cf_id_type / UUID).
 * Code should ensure to use discard_completed_segments with UUID +
 * highest rp once a memtable has been flushed. This will allow
 * discarding used segments. Failure to do so will keep stuff
 * indefinately.
 */
class commitlog {
public:
    using timeout_clock = lowres_clock;

    class segment_manager;
    class segment;

    friend class rp_handle;
private:
    ::shared_ptr<segment_manager> _segment_manager;
public:
    enum class sync_mode {
        PERIODIC, BATCH
    };
    struct config {
        config() = default;
        config(const config&) = default;
        config(const db::config&);

        sstring commit_log_location;
        sstring metrics_category_name;
        uint64_t commitlog_total_space_in_mb = 0;
        uint64_t commitlog_segment_size_in_mb = 32;
        uint64_t commitlog_sync_period_in_ms = 10 * 1000; //TODO: verify default!
        // Max number of segments to keep in pre-alloc reserve.
        // Not (yet) configurable from scylla.conf.
        uint64_t max_reserve_segments = 12;
        // Max active writes/flushes. Default value
        // zero means try to figure it out ourselves
        uint64_t max_active_writes = 0;
        uint64_t max_active_flushes = 0;

        sync_mode mode = sync_mode::PERIODIC;
        std::string fname_prefix = descriptor::FILENAME_PREFIX;
    };

    struct descriptor {
    private:
        descriptor(std::pair<uint64_t, uint32_t> p, const std::string& fname_prefix);
    public:
        static const std::string SEPARATOR;
        static const std::string FILENAME_PREFIX;
        static const std::string FILENAME_EXTENSION;

        descriptor(descriptor&&) = default;
        descriptor(const descriptor&) = default;
        descriptor(segment_id_type i, const std::string& fname_prefix, uint32_t v = 1);
        descriptor(replay_position p, const std::string& fname_prefix);
        descriptor(const sstring& filename, const std::string& fname_prefix);

        sstring filename() const;
        operator replay_position() const;

        const segment_id_type id;
        const uint32_t ver;
        const std::string filename_prefix = FILENAME_PREFIX;
    };

    commitlog(commitlog&&) noexcept;
    ~commitlog();

    /**
     * Commitlog is created via a factory func.
     * This of course because it needs to access disk to get up to speed.
     * Optionally, could have an "init" func and require calling this.
     */
    static future<commitlog> create_commitlog(config);

    /**
     * Note: To be able to keep impl out of header file,
     * actual data writing is done via a std::function.
     * If it is proven that this has unacceptable overhead, this can be replace
     * by iter an interface or move segments and stuff into the header. But
     * I hope not.
     *
     * A serializing func is provided along with a parameter indicating the size
     * of data to be written. (See add).
     * Don't write less, absolutely don't write more...
     */
    using output = data_output;
    using serializer_func = std::function<void(output&)>;

    /**
     * Add a "Mutation" to the commit log.
     *
     * Resolves with timed_out_error when timeout is reached.
     *
     * @param mutation_func a function that writes 'size' bytes to the log, representing the mutation.
     */
    future<rp_handle> add(const cf_id_type& id, size_t size, timeout_clock::time_point timeout, serializer_func mutation_func);

    /**
     * Template version of add.
     * Resolves with timed_out_error when timeout is reached.
     * @param mu an invokable op that generates the serialized data. (Of size bytes)
     */
    template<typename _MutationOp>
    future<rp_handle> add_mutation(const cf_id_type& id, size_t size, timeout_clock::time_point timeout, _MutationOp&& mu) {
        return add(id, size, timeout, [mu = std::forward<_MutationOp>(mu)](output& out) {
            mu(out);
        });
    }

    /**
     * Template version of add.
     * @param mu an invokable op that generates the serialized data. (Of size bytes)
     */
    template<typename _MutationOp>
    future<rp_handle> add_mutation(const cf_id_type& id, size_t size, _MutationOp&& mu) {
        return add_mutation(id, size, timeout_clock::time_point::max(), std::forward<_MutationOp>(mu));
    }

    /**
     * Add an entry to the commit log.
     * Resolves with timed_out_error when timeout is reached.
     * @param entry_writer a writer responsible for writing the entry
     */
    future<rp_handle> add_entry(const cf_id_type& id, const commitlog_entry_writer& entry_writer, timeout_clock::time_point timeout);

    /**
     * Modifies the per-CF dirty cursors of any commit log segments for the column family according to the position
     * given. Discards any commit log segments that are no longer used.
     *
     * @param cfId    the column family ID that was flushed
     * @param rp_set  the replay positions of the flush
     */
    void discard_completed_segments(const cf_id_type&, const rp_set&);

    void discard_completed_segments(const cf_id_type&);

    /**
     * A 'flush_handler' is invoked when the CL determines that size on disk has
     * exceeded allowable threshold. It is called once for every currently active
     * CF id with the highest replay_position which we would prefer to free "until".
     * I.e. a the highest potentially freeable position in the CL.
     *
     * Whatever the callback does to help (or not) this desire is up to him.
     * This is called synchronously, so callee might want to instigate async ops
     * in the background.
     *
     */
    typedef std::function<void(cf_id_type, replay_position)> flush_handler;
    typedef uint64_t flush_handler_id;

    class flush_handler_anchor {
    public:
        friend class commitlog;
        ~flush_handler_anchor();
        flush_handler_anchor(flush_handler_anchor&&);
        flush_handler_anchor(const flush_handler_anchor&) = delete;

        flush_handler_id release(); // disengage anchor - danger danger.
        void unregister();

    private:
        flush_handler_anchor(commitlog&, flush_handler_id);

        commitlog & _cl;
        flush_handler_id _id;
    };

    flush_handler_anchor add_flush_handler(flush_handler);
    void remove_flush_handler(flush_handler_id);

    /**
     * Returns a vector of the segment names
     */
    std::vector<sstring> get_active_segment_names() const;

    /**
     * Returns a vector of segment paths which were
     * preexisting when this instance of commitlog was created.
     *
     * The list will be empty when called for the second time.
     */
    std::vector<sstring> get_segments_to_replay();

    uint64_t get_total_size() const;
    uint64_t get_completed_tasks() const;
    uint64_t get_flush_count() const;
    uint64_t get_pending_tasks() const;
    uint64_t get_pending_flushes() const;
    uint64_t get_pending_allocations() const;
    uint64_t get_flush_limit_exceeded_count() const;
    uint64_t get_num_segments_created() const;
    uint64_t get_num_segments_destroyed() const;
    /**
     * Get number of inactive (finished), segments lingering
     * due to still being dirty
     */
    uint64_t get_num_dirty_segments() const;
    /**
     * Get number of active segments, i.e. still being allocated to
     */
    uint64_t get_num_active_segments() const;

    /**
     * Returns the largest amount of data that can be written in a single "mutation".
     */
    size_t max_record_size() const;

    /**
     * Return max allowed pending writes (per this shard)
     */
    uint64_t max_active_writes() const;
    /**
     * Return max allowed pending flushes (per this shard)
     */
    uint64_t max_active_flushes() const;

    future<> clear();

    const config& active_config() const;

    /**
     * Issues disk sync on all (allocating) segments. I.e. ensures that
     * all data written up until this call is indeed on disk.
     * _However_, if you issue new "add" ops while this is executing,
     * those can/will be missed.
     */
    future<> sync_all_segments();
    /**
     * Shuts everything down and causes any
     * incoming writes to throw exceptions
     */
    future<> shutdown();
    /**
     * Ensure segments are released, even if we don't free the
     * commitlog proper. (hint, our shutdown is "partial")
     */
    future<> release();

    future<std::vector<descriptor>> list_existing_descriptors() const;
    future<std::vector<descriptor>> list_existing_descriptors(const sstring& dir) const;

    future<std::vector<sstring>> list_existing_segments() const;
    future<std::vector<sstring>> list_existing_segments(const sstring& dir) const;

    typedef std::function<future<>(temporary_buffer<char>, replay_position)> commit_load_reader_func;

    class segment_data_corruption_error: public std::runtime_error {
    public:
        segment_data_corruption_error(std::string msg, uint64_t s)
                : std::runtime_error(msg), _bytes(s) {
        }
        uint64_t bytes() const {
            return _bytes;
        }
    private:
        uint64_t _bytes;
    };

    static subscription<temporary_buffer<char>, replay_position> read_log_file(file, commit_load_reader_func, position_type = 0);
    static future<std::unique_ptr<subscription<temporary_buffer<char>, replay_position>>> read_log_file(
            const sstring&, commit_load_reader_func, position_type = 0);
private:
    commitlog(config);

    struct entry_writer {
        virtual size_t size(segment&) = 0;
        // Returns segment-independent size of the entry. Must be <= than segment-dependant size.
        virtual size_t size() = 0;
        virtual void write(segment&, output&) = 0;
        virtual ~entry_writer() {};
    };
};

}
<commit_msg>Fix compilation of tests/commitlog_test.cc<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*
 * Modified by ScyllaDB
 * Copyright (C) 2015 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 <memory>

#include "utils/data_output.hh"
#include "core/future.hh"
#include "core/shared_ptr.hh"
#include "core/stream.hh"
#include "replay_position.hh"
#include "commitlog_entry.hh"

namespace seastar { class file; }

#include "seastarx.hh"

namespace db {

class config;
class rp_set;
class rp_handle;

/*
 * Commit Log tracks every write operation into the system. The aim of
 * the commit log is to be able to successfully recover data that was
 * not stored to disk via the Memtable.
 *
 * This impl is cassandra log format compatible (for what it is worth).
 * The behaviour is similar, but not 100% identical as "stock cl".
 *
 * Files are managed with "normal" file writes (as normal as seastar
 * gets) - no mmapping. Data is kept in internal buffers which, when
 * full, are written to disk (see below). Files are also flushed
 * periodically (or always), ensuring all data is written + writes are
 * complete.
 *
 * In BATCH mode, every write to the log will also send the data to disk
 * + issue a flush and wait for both to complete.
 *
 * In PERIODIC mode, most writes will only add to the internal memory
 * buffers. If the mem buffer is saturated, data is sent to disk, but we
 * don't wait for the write to complete. However, if periodic (timer)
 * flushing has not been done in X ms, we will write + flush to file. In
 * which case we wait for it.
 *
 * The commitlog does not guarantee any ordering between "add" callers
 * (due to the above). The actual order in the commitlog is however
 * identified by the replay_position returned.
 *
 * Like the stock cl, the log segments keep track of the highest dirty
 * (added) internal position for a given table id (cf_id_type / UUID).
 * Code should ensure to use discard_completed_segments with UUID +
 * highest rp once a memtable has been flushed. This will allow
 * discarding used segments. Failure to do so will keep stuff
 * indefinately.
 */
class commitlog {
public:
    using timeout_clock = lowres_clock;

    class segment_manager;
    class segment;

    friend class rp_handle;
private:
    ::shared_ptr<segment_manager> _segment_manager;
public:
    enum class sync_mode {
        PERIODIC, BATCH
    };
    struct config {
        config() = default;
        config(const config&) = default;
        config(const db::config&);

        sstring commit_log_location;
        sstring metrics_category_name;
        uint64_t commitlog_total_space_in_mb = 0;
        uint64_t commitlog_segment_size_in_mb = 32;
        uint64_t commitlog_sync_period_in_ms = 10 * 1000; //TODO: verify default!
        // Max number of segments to keep in pre-alloc reserve.
        // Not (yet) configurable from scylla.conf.
        uint64_t max_reserve_segments = 12;
        // Max active writes/flushes. Default value
        // zero means try to figure it out ourselves
        uint64_t max_active_writes = 0;
        uint64_t max_active_flushes = 0;

        sync_mode mode = sync_mode::PERIODIC;
        std::string fname_prefix = descriptor::FILENAME_PREFIX;
    };

    struct descriptor {
    private:
        descriptor(std::pair<uint64_t, uint32_t> p, const std::string& fname_prefix);
    public:
        static const std::string SEPARATOR;
        static const std::string FILENAME_PREFIX;
        static const std::string FILENAME_EXTENSION;

        descriptor(descriptor&&) = default;
        descriptor(const descriptor&) = default;
        descriptor(segment_id_type i, const std::string& fname_prefix, uint32_t v = 1);
        descriptor(replay_position p, const std::string& fname_prefix = FILENAME_PREFIX);
        descriptor(const sstring& filename, const std::string& fname_prefix = FILENAME_PREFIX);

        sstring filename() const;
        operator replay_position() const;

        const segment_id_type id;
        const uint32_t ver;
        const std::string filename_prefix = FILENAME_PREFIX;
    };

    commitlog(commitlog&&) noexcept;
    ~commitlog();

    /**
     * Commitlog is created via a factory func.
     * This of course because it needs to access disk to get up to speed.
     * Optionally, could have an "init" func and require calling this.
     */
    static future<commitlog> create_commitlog(config);

    /**
     * Note: To be able to keep impl out of header file,
     * actual data writing is done via a std::function.
     * If it is proven that this has unacceptable overhead, this can be replace
     * by iter an interface or move segments and stuff into the header. But
     * I hope not.
     *
     * A serializing func is provided along with a parameter indicating the size
     * of data to be written. (See add).
     * Don't write less, absolutely don't write more...
     */
    using output = data_output;
    using serializer_func = std::function<void(output&)>;

    /**
     * Add a "Mutation" to the commit log.
     *
     * Resolves with timed_out_error when timeout is reached.
     *
     * @param mutation_func a function that writes 'size' bytes to the log, representing the mutation.
     */
    future<rp_handle> add(const cf_id_type& id, size_t size, timeout_clock::time_point timeout, serializer_func mutation_func);

    /**
     * Template version of add.
     * Resolves with timed_out_error when timeout is reached.
     * @param mu an invokable op that generates the serialized data. (Of size bytes)
     */
    template<typename _MutationOp>
    future<rp_handle> add_mutation(const cf_id_type& id, size_t size, timeout_clock::time_point timeout, _MutationOp&& mu) {
        return add(id, size, timeout, [mu = std::forward<_MutationOp>(mu)](output& out) {
            mu(out);
        });
    }

    /**
     * Template version of add.
     * @param mu an invokable op that generates the serialized data. (Of size bytes)
     */
    template<typename _MutationOp>
    future<rp_handle> add_mutation(const cf_id_type& id, size_t size, _MutationOp&& mu) {
        return add_mutation(id, size, timeout_clock::time_point::max(), std::forward<_MutationOp>(mu));
    }

    /**
     * Add an entry to the commit log.
     * Resolves with timed_out_error when timeout is reached.
     * @param entry_writer a writer responsible for writing the entry
     */
    future<rp_handle> add_entry(const cf_id_type& id, const commitlog_entry_writer& entry_writer, timeout_clock::time_point timeout);

    /**
     * Modifies the per-CF dirty cursors of any commit log segments for the column family according to the position
     * given. Discards any commit log segments that are no longer used.
     *
     * @param cfId    the column family ID that was flushed
     * @param rp_set  the replay positions of the flush
     */
    void discard_completed_segments(const cf_id_type&, const rp_set&);

    void discard_completed_segments(const cf_id_type&);

    /**
     * A 'flush_handler' is invoked when the CL determines that size on disk has
     * exceeded allowable threshold. It is called once for every currently active
     * CF id with the highest replay_position which we would prefer to free "until".
     * I.e. a the highest potentially freeable position in the CL.
     *
     * Whatever the callback does to help (or not) this desire is up to him.
     * This is called synchronously, so callee might want to instigate async ops
     * in the background.
     *
     */
    typedef std::function<void(cf_id_type, replay_position)> flush_handler;
    typedef uint64_t flush_handler_id;

    class flush_handler_anchor {
    public:
        friend class commitlog;
        ~flush_handler_anchor();
        flush_handler_anchor(flush_handler_anchor&&);
        flush_handler_anchor(const flush_handler_anchor&) = delete;

        flush_handler_id release(); // disengage anchor - danger danger.
        void unregister();

    private:
        flush_handler_anchor(commitlog&, flush_handler_id);

        commitlog & _cl;
        flush_handler_id _id;
    };

    flush_handler_anchor add_flush_handler(flush_handler);
    void remove_flush_handler(flush_handler_id);

    /**
     * Returns a vector of the segment names
     */
    std::vector<sstring> get_active_segment_names() const;

    /**
     * Returns a vector of segment paths which were
     * preexisting when this instance of commitlog was created.
     *
     * The list will be empty when called for the second time.
     */
    std::vector<sstring> get_segments_to_replay();

    uint64_t get_total_size() const;
    uint64_t get_completed_tasks() const;
    uint64_t get_flush_count() const;
    uint64_t get_pending_tasks() const;
    uint64_t get_pending_flushes() const;
    uint64_t get_pending_allocations() const;
    uint64_t get_flush_limit_exceeded_count() const;
    uint64_t get_num_segments_created() const;
    uint64_t get_num_segments_destroyed() const;
    /**
     * Get number of inactive (finished), segments lingering
     * due to still being dirty
     */
    uint64_t get_num_dirty_segments() const;
    /**
     * Get number of active segments, i.e. still being allocated to
     */
    uint64_t get_num_active_segments() const;

    /**
     * Returns the largest amount of data that can be written in a single "mutation".
     */
    size_t max_record_size() const;

    /**
     * Return max allowed pending writes (per this shard)
     */
    uint64_t max_active_writes() const;
    /**
     * Return max allowed pending flushes (per this shard)
     */
    uint64_t max_active_flushes() const;

    future<> clear();

    const config& active_config() const;

    /**
     * Issues disk sync on all (allocating) segments. I.e. ensures that
     * all data written up until this call is indeed on disk.
     * _However_, if you issue new "add" ops while this is executing,
     * those can/will be missed.
     */
    future<> sync_all_segments();
    /**
     * Shuts everything down and causes any
     * incoming writes to throw exceptions
     */
    future<> shutdown();
    /**
     * Ensure segments are released, even if we don't free the
     * commitlog proper. (hint, our shutdown is "partial")
     */
    future<> release();

    future<std::vector<descriptor>> list_existing_descriptors() const;
    future<std::vector<descriptor>> list_existing_descriptors(const sstring& dir) const;

    future<std::vector<sstring>> list_existing_segments() const;
    future<std::vector<sstring>> list_existing_segments(const sstring& dir) const;

    typedef std::function<future<>(temporary_buffer<char>, replay_position)> commit_load_reader_func;

    class segment_data_corruption_error: public std::runtime_error {
    public:
        segment_data_corruption_error(std::string msg, uint64_t s)
                : std::runtime_error(msg), _bytes(s) {
        }
        uint64_t bytes() const {
            return _bytes;
        }
    private:
        uint64_t _bytes;
    };

    static subscription<temporary_buffer<char>, replay_position> read_log_file(file, commit_load_reader_func, position_type = 0);
    static future<std::unique_ptr<subscription<temporary_buffer<char>, replay_position>>> read_log_file(
            const sstring&, commit_load_reader_func, position_type = 0);
private:
    commitlog(config);

    struct entry_writer {
        virtual size_t size(segment&) = 0;
        // Returns segment-independent size of the entry. Must be <= than segment-dependant size.
        virtual size_t size() = 0;
        virtual void write(segment&, output&) = 0;
        virtual ~entry_writer() {};
    };
};

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: PresentationViewShell.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-02-07 16:13:48 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SD_PRESENTATION_VIEW_SHELL_HXX
#define SD_PRESENTATION_VIEW_SHELL_HXX

#ifndef SD_DRAW_VIEW_SHELL
#include "DrawViewShell.hxx"
#endif

namespace sd {

/** This view shell is responsible for showing the presentation of an
    Impress document.
*/
class PresentationViewShell
    : public DrawViewShell
{
public:
    TYPEINFO();

    SFX_DECL_VIEWFACTORY(PresViewShell);
    SFX_DECL_INTERFACE( SD_IF_SDPRESVIEWSHELL );

    PresentationViewShell (
        SfxViewFrame* pFrame,
        ViewShellBase& rViewShellBase,
        ::Window* pParentWindow,
        FrameView* pFrameView = NULL);
    static void     CreateFullScreenShow(ViewShell* pOriginShell, SfxRequest& rReq );

    /** This method is used by a simple class that passes some
        arguments from the creator of the new view shell to the new view
        shell object by waiting for its asynchronous creation.
        @param pFrameView
            The frame view that is typically used by the creating object and
            that shall be shared by the created view shell.
        @param rRequest
            A request from which some arguments are extracted by the
            FuSlideShow object.  It usually comes from an Execute() method
            that initiated the creation of the new presentation view shell.
        @param nPageNumber
            The number of the page at which to start the show.
    */
    void FinishInitialization (
        FrameView* pFrameView,
        SfxRequest& rRequest,
        USHORT nPageNumber);

protected:
    virtual SvxRuler* CreateHRuler(::sd::Window* pWin, BOOL bIsFirst);
    virtual SvxRuler* CreateVRuler(::sd::Window* pWin);

private:
    Rectangle       maOldVisArea;
    sal_Bool        mbShowStarted;

    PresentationViewShell (
        SfxViewFrame* pFrame,
        ::Window* pParentWindow,
        const DrawViewShell& rShell);
    virtual ~PresentationViewShell (void);

    virtual void Activate (BOOL bIsMDIActivate);
    virtual void Paint (const Rectangle& rRect, ::sd::Window* pWin);
};

} // end of namespace sd

#endif
<commit_msg>INTEGRATION: CWS ooo19126 (1.4.212); FILE MERGED 2005/09/05 13:22:45 rt 1.4.212.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: PresentationViewShell.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 05:12:15 $
 *
 *  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
 *
 ************************************************************************/

#ifndef SD_PRESENTATION_VIEW_SHELL_HXX
#define SD_PRESENTATION_VIEW_SHELL_HXX

#ifndef SD_DRAW_VIEW_SHELL
#include "DrawViewShell.hxx"
#endif

namespace sd {

/** This view shell is responsible for showing the presentation of an
    Impress document.
*/
class PresentationViewShell
    : public DrawViewShell
{
public:
    TYPEINFO();

    SFX_DECL_VIEWFACTORY(PresViewShell);
    SFX_DECL_INTERFACE( SD_IF_SDPRESVIEWSHELL );

    PresentationViewShell (
        SfxViewFrame* pFrame,
        ViewShellBase& rViewShellBase,
        ::Window* pParentWindow,
        FrameView* pFrameView = NULL);
    static void     CreateFullScreenShow(ViewShell* pOriginShell, SfxRequest& rReq );

    /** This method is used by a simple class that passes some
        arguments from the creator of the new view shell to the new view
        shell object by waiting for its asynchronous creation.
        @param pFrameView
            The frame view that is typically used by the creating object and
            that shall be shared by the created view shell.
        @param rRequest
            A request from which some arguments are extracted by the
            FuSlideShow object.  It usually comes from an Execute() method
            that initiated the creation of the new presentation view shell.
        @param nPageNumber
            The number of the page at which to start the show.
    */
    void FinishInitialization (
        FrameView* pFrameView,
        SfxRequest& rRequest,
        USHORT nPageNumber);

protected:
    virtual SvxRuler* CreateHRuler(::sd::Window* pWin, BOOL bIsFirst);
    virtual SvxRuler* CreateVRuler(::sd::Window* pWin);

private:
    Rectangle       maOldVisArea;
    sal_Bool        mbShowStarted;

    PresentationViewShell (
        SfxViewFrame* pFrame,
        ::Window* pParentWindow,
        const DrawViewShell& rShell);
    virtual ~PresentationViewShell (void);

    virtual void Activate (BOOL bIsMDIActivate);
    virtual void Paint (const Rectangle& rRect, ::sd::Window* pWin);
};

} // end of namespace sd

#endif
<|endoftext|>


<commit_before>#include <cstdlib>
#include <cstdio>
#include <vector>
#include <array>
#include <map>
#include <unordered_map>
#include <memory>
#include <string>
#include <stdlib.h>
#include <complex>
#include <thread>
#if !defined(_WIN32)
#include <unistd.h>
#include <dlfcn.h>
#else
#include <windows.h>
void sleep(unsigned secs) { Sleep(secs * 1000); }
#endif

#include "dir1/debuggee.h"
#include "dir2/debuggee.h"

extern "C" void disassembly1();

extern "C" void sharedlib_entry();

void deepstack(int levelsToGo)
{
    if (levelsToGo > 0)
    {
        deepstack(levelsToGo - 1);
    }
} // #BP2

void inf_loop()
{
    long long i = 0;
    for (;;)
    {
        printf("\r%lld ", i);
        fflush(stdout);
        sleep(1);
        i += 1;
    }
}

void threads(int num_threads)
{
#if !defined(__MINGW32__) || defined(_GLIBCXX_HAS_GTHREADS)
    std::vector<int> alive(num_threads);
    std::vector<std::thread> threads;
    for (int i = 0; i < num_threads; ++i)
    {
        int *am_alive = &alive[i];
        std::thread thread([am_alive](int id) {
            *am_alive = 1;
            printf("I'm thread %d\n", id);
            sleep(id % 4 + 1);
            printf("Thread %d exiting\n", id);
            *am_alive = 0;
        },
                           i);
        threads.push_back(std::move(thread));
    }
    sleep(1);
    for (int i = 0; i < num_threads; ++i)
    {
        printf("Joining %d\n", i);
        threads[i].join();
    }
#else
    sleep(1);
#endif
}

bool check_env(const char *env_name, const char *expected)
{
    const char *val = getenv(env_name);
    printf("%s=%s\n", env_name, val);
    return val && std::string(val) == std::string(expected);
}

void echo()
{
    char buffer[1024];
    do
    {
        fgets(buffer, sizeof(buffer), stdin);
        fputs(buffer, stdout);
    } while (buffer[0] != '\n'); // till empty line is read
}

class Klazz
{
    static int m1;
};
int Klazz::m1 = 42;

void vars()
{
    struct Struct
    {
        int a;
        char b;
        float c;
        int d[4];
    };

    struct DeepStruct
    {
        int a;
        const char *b;
        float c;
        Struct d;
        Struct e[5];
    };

    int a = 10;
    int b = 20;
    for (int i = 0; i < 10; i++)
    {
        int a = 30;
        int b = 40;
        float pi = 3.14159265;
        static int sss = 555;
        const char c[] = "foobar";
        char buffer[10240] = {0};
        int array_int[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        std::vector<std::vector<int>> vec_int(10, {i * 1, i * 2, i * 3, i * 4, i * 5});
        std::vector<std::vector<int>> empty_vec;
        Struct s1 = {i + 1, 'a', 3.0f, {i, i, i, i}};
        Struct s2 = {i + 10, 'b', 999.0f, {i * 10, i * 10, i * 10, i * 10}};
        Struct *s_ptr = &s1;
        Struct *null_s_ptr = nullptr;
        Struct *invalid_s_ptr = (Struct *)1;
        DeepStruct ds1 = {13, "foo", 3.14,                   //
                          {i, 'd', 4.0f, {1, 2, 3, i}},      //
                          {{i * 2, 's', 5.0f, {4, 5, 6, i}}, //
                           {i * 3, 'x', 5.5f, {3, 5, 1, i}}}};
        std::vector<Struct> vec_struct(3, {i * 2, 'b', 4.0f});
        std::array<int, 5> stdarr_int;
        std::map<int, float> ord_map = {{1, 2.34}, {2, 3.56}};
        std::unordered_map<int, float> unord_map = {{1, 2.34}, {2, 3.56}};
        auto shared_ptr = std::make_shared<std::map<int, float>>(ord_map);
        Struct array_struct[5] = {{i * 2, 'b', 4.0f}};
        std::string str1 = "The quick brown fox";
        char invalid_utf8[] = "ABC\xFF\x01\xFEXYZ";
        std::string empty_str;
        std::string *str_ptr = &str1;
        std::string &str_ref = str1;
        wchar_t wstr1[] = L"Превед йожэг!";
        std::wstring wstr2 = L"Ḥ̪͔̦̺E͍̹̯̭͜ C̨͙̹̖̙O̡͍̪͖ͅM̢̗͙̫̬E̜͍̟̟̮S̢̢̪̘̦!";
        int zzz = i; // #BP3
    }
}

void mandelbrot()
{
    const int xdim = 500;
    const int ydim = 500;
    const int max_iter = 100;
    int image[xdim * ydim] = {0};
    for (int y = 0; y < ydim; ++y)
    {
        // /py debugvis.plot_image($image, $xdim, $ydim) if $y % 50 == 0 else False
        for (int x = 0; x < xdim; ++x)
        {
            std::complex<float> xy(-2.05 + x * 3.0 / xdim, -1.5 + y * 3.0 / ydim);
            std::complex<float> z(0, 0);
            int count = max_iter;
            for (int i = 0; i < max_iter; ++i)
            {
                z = z * z + xy;
                if (std::abs(z) >= 2)
                {
                    count = i;
                    break;
                }
            }
            image[y * xdim + x] = count;
        }
    }
    for (int y = 0; y < ydim; y += 10)
    {
        for (int x = 0; x < xdim; x += 5)
        {
            putchar(image[y * xdim + x] < max_iter ? '.' : '#');
        }
        putchar('\n');
    }
}

int main(int argc, char *argv[])
{
    std::vector<std::string> args;
    for (int i = 0; i < argc; ++i)
        args.push_back(argv[i]);

    if (args.size() < 2) // #BP1
    {
        return -1;
    }

    std::string testcase = args[1];
    if (testcase == "crash")
    {
        *(volatile int *)0 = 42;
    }
    else if (testcase == "throw")
    {
        throw std::runtime_error("error");
    }
    else if (testcase == "deepstack")
    {
        deepstack(50);
    }
    else if (testcase == "threads")
    {
        threads(15);
    }
    else if (testcase == "check_env")
    {
        if (argc < 4)
        {
            return -1;
        }
        return (int)check_env(argv[2], argv[3]);
    }
    else if (testcase == "inf_loop")
    {
        inf_loop();
    }
    else if (testcase == "echo")
    {
        echo();
    }
    else if (testcase == "vars")
    {
        vars();
    }
    else if (testcase == "header")
    {
        header_fn1(1);
        header_fn2(2);
#if !defined(_WIN32)
        void *hlib = dlopen("libdebuggee.so", RTLD_NOW);
        auto sharedlib_entry = reinterpret_cast<void (*)()>(dlsym(hlib, "sharedlib_entry"));
#else
        HMODULE hlib = LoadLibrary("libdebuggee.dll");
        auto sharedlib_entry = reinterpret_cast<void (*)()>(GetProcAddress(hlib, "sharedlib_entry"));
#endif
        sharedlib_entry();
    }
    else if (testcase == "mandelbrot")
    {
        mandelbrot();
    }
    else if (testcase == "dasm")
    {
        disassembly1();
    }
    return 0;
}
<commit_msg>Fix dlopen on travis.<commit_after>#include <cstdlib>
#include <cstdio>
#include <vector>
#include <array>
#include <map>
#include <unordered_map>
#include <memory>
#include <string>
#include <stdlib.h>
#include <complex>
#include <thread>
#if !defined(_WIN32)
#include <unistd.h>
#include <dlfcn.h>
#else
#include <windows.h>
void sleep(unsigned secs) { Sleep(secs * 1000); }
#endif

#include "dir1/debuggee.h"
#include "dir2/debuggee.h"

extern "C" void disassembly1();

extern "C" void sharedlib_entry();

void deepstack(int levelsToGo)
{
    if (levelsToGo > 0)
    {
        deepstack(levelsToGo - 1);
    }
} // #BP2

void inf_loop()
{
    long long i = 0;
    for (;;)
    {
        printf("\r%lld ", i);
        fflush(stdout);
        sleep(1);
        i += 1;
    }
}

void threads(int num_threads)
{
#if !defined(__MINGW32__) || defined(_GLIBCXX_HAS_GTHREADS)
    std::vector<int> alive(num_threads);
    std::vector<std::thread> threads;
    for (int i = 0; i < num_threads; ++i)
    {
        int *am_alive = &alive[i];
        std::thread thread([am_alive](int id) {
            *am_alive = 1;
            printf("I'm thread %d\n", id);
            sleep(id % 4 + 1);
            printf("Thread %d exiting\n", id);
            *am_alive = 0;
        },
                           i);
        threads.push_back(std::move(thread));
    }
    sleep(1);
    for (int i = 0; i < num_threads; ++i)
    {
        printf("Joining %d\n", i);
        threads[i].join();
    }
#else
    sleep(1);
#endif
}

bool check_env(const char *env_name, const char *expected)
{
    const char *val = getenv(env_name);
    printf("%s=%s\n", env_name, val);
    return val && std::string(val) == std::string(expected);
}

void echo()
{
    char buffer[1024];
    do
    {
        fgets(buffer, sizeof(buffer), stdin);
        fputs(buffer, stdout);
    } while (buffer[0] != '\n'); // till empty line is read
}

class Klazz
{
    static int m1;
};
int Klazz::m1 = 42;

void vars()
{
    struct Struct
    {
        int a;
        char b;
        float c;
        int d[4];
    };

    struct DeepStruct
    {
        int a;
        const char *b;
        float c;
        Struct d;
        Struct e[5];
    };

    int a = 10;
    int b = 20;
    for (int i = 0; i < 10; i++)
    {
        int a = 30;
        int b = 40;
        float pi = 3.14159265;
        static int sss = 555;
        const char c[] = "foobar";
        char buffer[10240] = {0};
        int array_int[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        std::vector<std::vector<int>> vec_int(10, {i * 1, i * 2, i * 3, i * 4, i * 5});
        std::vector<std::vector<int>> empty_vec;
        Struct s1 = {i + 1, 'a', 3.0f, {i, i, i, i}};
        Struct s2 = {i + 10, 'b', 999.0f, {i * 10, i * 10, i * 10, i * 10}};
        Struct *s_ptr = &s1;
        Struct *null_s_ptr = nullptr;
        Struct *invalid_s_ptr = (Struct *)1;
        DeepStruct ds1 = {13, "foo", 3.14,                   //
                          {i, 'd', 4.0f, {1, 2, 3, i}},      //
                          {{i * 2, 's', 5.0f, {4, 5, 6, i}}, //
                           {i * 3, 'x', 5.5f, {3, 5, 1, i}}}};
        std::vector<Struct> vec_struct(3, {i * 2, 'b', 4.0f});
        std::array<int, 5> stdarr_int;
        std::map<int, float> ord_map = {{1, 2.34}, {2, 3.56}};
        std::unordered_map<int, float> unord_map = {{1, 2.34}, {2, 3.56}};
        auto shared_ptr = std::make_shared<std::map<int, float>>(ord_map);
        Struct array_struct[5] = {{i * 2, 'b', 4.0f}};
        std::string str1 = "The quick brown fox";
        char invalid_utf8[] = "ABC\xFF\x01\xFEXYZ";
        std::string empty_str;
        std::string *str_ptr = &str1;
        std::string &str_ref = str1;
        wchar_t wstr1[] = L"Превед йожэг!";
        std::wstring wstr2 = L"Ḥ̪͔̦̺E͍̹̯̭͜ C̨͙̹̖̙O̡͍̪͖ͅM̢̗͙̫̬E̜͍̟̟̮S̢̢̪̘̦!";
        int zzz = i; // #BP3
    }
}

void mandelbrot()
{
    const int xdim = 500;
    const int ydim = 500;
    const int max_iter = 100;
    int image[xdim * ydim] = {0};
    for (int y = 0; y < ydim; ++y)
    {
        // /py debugvis.plot_image($image, $xdim, $ydim) if $y % 50 == 0 else False
        for (int x = 0; x < xdim; ++x)
        {
            std::complex<float> xy(-2.05 + x * 3.0 / xdim, -1.5 + y * 3.0 / ydim);
            std::complex<float> z(0, 0);
            int count = max_iter;
            for (int i = 0; i < max_iter; ++i)
            {
                z = z * z + xy;
                if (std::abs(z) >= 2)
                {
                    count = i;
                    break;
                }
            }
            image[y * xdim + x] = count;
        }
    }
    for (int y = 0; y < ydim; y += 10)
    {
        for (int x = 0; x < xdim; x += 5)
        {
            putchar(image[y * xdim + x] < max_iter ? '.' : '#');
        }
        putchar('\n');
    }
}

int main(int argc, char *argv[])
{
    std::vector<std::string> args;
    for (int i = 0; i < argc; ++i)
        args.push_back(argv[i]);

    if (args.size() < 2) // #BP1
    {
        return -1;
    }

    std::string testcase = args[1];
    if (testcase == "crash")
    {
        *(volatile int *)0 = 42;
    }
    else if (testcase == "throw")
    {
        throw std::runtime_error("error");
    }
    else if (testcase == "deepstack")
    {
        deepstack(50);
    }
    else if (testcase == "threads")
    {
        threads(15);
    }
    else if (testcase == "check_env")
    {
        if (argc < 4)
        {
            return -1;
        }
        return (int)check_env(argv[2], argv[3]);
    }
    else if (testcase == "inf_loop")
    {
        inf_loop();
    }
    else if (testcase == "echo")
    {
        echo();
    }
    else if (testcase == "vars")
    {
        vars();
    }
    else if (testcase == "header")
    {
        header_fn1(1);
        header_fn2(2);
#if !defined(_WIN32)
        void *hlib = dlopen("./libdebuggee.so", RTLD_NOW);
        auto sharedlib_entry = reinterpret_cast<void (*)()>(dlsym(hlib, "sharedlib_entry"));
#else
        HMODULE hlib = LoadLibrary("libdebuggee.dll");
        auto sharedlib_entry = reinterpret_cast<void (*)()>(GetProcAddress(hlib, "sharedlib_entry"));
#endif
        sharedlib_entry();
    }
    else if (testcase == "mandelbrot")
    {
        mandelbrot();
    }
    else if (testcase == "dasm")
    {
        disassembly1();
    }
    return 0;
}
<|endoftext|>