<commit_before>//
// Copyright (c) 2017 The nanoFramework project contributors
// Portions Copyright (c) Microsoft Corporation.  All rights reserved.
// See LICENSE file in the project root for full license information.
//

#include <string.h>
#include <targetPAL.h>
#include "win_dev_i2c_native.h"
#include "Esp32_DeviceMapping.h"

///////////////////////////////////////////////////////////////////////////////////////
// !!! KEEP IN SYNC WITH Windows.Devices.I2c.I2cSharingMode (in managed code) !!!    //
///////////////////////////////////////////////////////////////////////////////////////
enum I2cSharingMode
{
    Exclusive = 0,
    Shared
};

///////////////////////////////////////////////////////////////////////////////////////
// !!! KEEP IN SYNC WITH Windows.Devices.I2c.I2cTransferStatus (in managed code) !!! //
///////////////////////////////////////////////////////////////////////////////////////
 enum I2cTransferStatus
{
    I2cTransferStatus_FullTransfer = 0,
    I2cTransferStatus_ClockStretchTimeout,
    I2cTransferStatus_PartialTransfer,
    I2cTransferStatus_SlaveAddressNotAcknowledged,
    I2cTransferStatus_UnknownError
};

///////////////////////////////////////////////////////////////////////////////////////
// !!! KEEP IN SYNC WITH Windows.Devices.I2c.I2cBusSpeed (in managed code) !!!       //
///////////////////////////////////////////////////////////////////////////////////////
enum I2cBusSpeed
{
    I2cBusSpeed_StandardMode = 0,
    I2cBusSpeed_FastMode
};

typedef Library_win_dev_i2c_native_Windows_Devices_I2c_I2cConnectionSettings I2cConnectionSettings;

static char Esp_I2C_Initialised_Flag[I2C_NUM_MAX] = {0,0};

void Esp32_I2c_UnitializeAll()
{
    for (int c = 0; c < I2C_NUM_MAX; c++)
    {
        if (Esp_I2C_Initialised_Flag[c])
        {
            // Delete bus driver
            i2c_driver_delete((i2c_port_t)c);
            Esp_I2C_Initialised_Flag[c] = 0;
        }
    }
}

void Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::SetConfig(i2c_port_t bus, CLR_RT_HeapBlock* config)
{
    int busSpeed = config[ I2cConnectionSettings::FIELD___busSpeed ].NumericByRef().s4;

    gpio_num_t DataPin  = (gpio_num_t)Esp32_GetMappedDevicePins( DEV_TYPE_I2C, bus, 0);
    gpio_num_t ClockPin = (gpio_num_t)Esp32_GetMappedDevicePins( DEV_TYPE_I2C, bus, 1);

    i2c_config_t conf;
        conf.mode = I2C_MODE_MASTER;
        conf.sda_io_num =  DataPin;
        conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
        conf.scl_io_num = ClockPin;
        conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
        conf.master.clk_speed = (busSpeed==0)? 100000 : 400000;

   i2c_param_config(bus, &conf);
}

HRESULT IRAM_ATTR Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeInit___VOID( CLR_RT_StackFrame& stack )
{
    NANOCLR_HEADER();
    {
        // get a pointer to the managed object instance and check that it's not NULL
        CLR_RT_HeapBlock* pThis = stack.This();  FAULT_ON_NULL(pThis);

        // get bus index
        // this is coded with a multiplication, need to perform and int division to get the number
        // see the comments in the SpiDevice() constructor in managed code for details, subtract 1 to get ESP32 bus number
        i2c_port_t bus = (i2c_port_t)((pThis[ FIELD___deviceId ].NumericByRef().s4 / 1000) - 1);
        if ( bus != I2C_NUM_0 && bus != I2C_NUM_1)
        {
            NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
        }

        // get a pointer to the managed spi connectionSettings object instance
        CLR_RT_HeapBlock* pConfig = pThis[ FIELD___connectionSettings ].Dereference();

       // Set the Bus parameters
        SetConfig( bus, pConfig);

        esp_err_t res =  i2c_driver_install( bus, I2C_MODE_MASTER, 0, 0, 0);
        if ( res != ESP_OK)
        {
            NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
        }

       // Ensure driver gets unitialized during soft reboot
       HAL_AddSoftRebootHandler(Esp32_I2c_UnitializeAll);
       Esp_I2C_Initialised_Flag[bus] = 1;
   }
   NANOCLR_NOCLEANUP();
}

HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::DisposeNative___VOID( CLR_RT_StackFrame& stack )
{
    NANOCLR_HEADER();
    {
        // get a pointer to the managed object instance and check that it's not NULL
        CLR_RT_HeapBlock* pThis = stack.This();  FAULT_ON_NULL(pThis);

        i2c_port_t bus = (i2c_port_t)((pThis[ FIELD___deviceId ].NumericByRef().s4 / 1000) - 1);

        i2c_driver_delete(bus);

        Esp_I2C_Initialised_Flag[bus] = 0;
    }
    NANOCLR_NOCLEANUP();
}

HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeTransmit___WindowsDevicesI2cI2cTransferResult__SZARRAY_U1__SZARRAY_U1( CLR_RT_StackFrame& stack )
{
    NANOCLR_HEADER();
    {
        unsigned char * writeData = NULL;
        unsigned char * readData = NULL;
        int writeSize = 0;
        int readSize = 0;
        esp_err_t i2cStatus;
        int returnStatus = I2cTransferStatus_FullTransfer;

        CLR_RT_HeapBlock*       result;
        // create the return object (I2cTransferResult)
        CLR_RT_HeapBlock&       top = stack.PushValueAndClear();

        // get a pointer to the managed object instance and check that it's not NULL
        CLR_RT_HeapBlock* pThis = stack.This();  FAULT_ON_NULL(pThis);

        // get a pointer to the managed spi connectionSettings object instance
        CLR_RT_HeapBlock* pConfig = pThis[ FIELD___connectionSettings ].Dereference();

        // get bus index
        // this is coded with a multiplication, need to perform and int division to get the number
        // see the comments in the SpiDevice() constructor in managed code for details, subtract 1 to get ESP32 bus number
        i2c_port_t bus = (i2c_port_t)((pThis[ FIELD___deviceId ].NumericByRef().s4 / 1000) - 1);

        // Set the Bus parameters
        SetConfig( bus, pConfig);

        int slaveAddress = pConfig[ I2cConnectionSettings::FIELD___slaveAddress ].NumericByRef().s4;

        // dereference the write and read buffers from the arguments
        CLR_RT_HeapBlock_Array* writeBuffer = stack.Arg1().DereferenceArray();
        if (writeBuffer != NULL)
        {
            // grab the pointer to the array by getting the first element of the array
            writeData = writeBuffer->GetFirstElement();

            // get the size of the buffer by reading the number of elements in the HeapBlock array
            writeSize = writeBuffer->m_numOfElements;
        }

        CLR_RT_HeapBlock_Array* readBuffer = stack.Arg3().DereferenceArray();
        if (readBuffer != NULL)
        {
            // grab the pointer to the array by getting the first element of the array
            readData = readBuffer->GetFirstElement();

            // get the size of the buffer by reading the number of elements in the HeapBlock array
            readSize = readBuffer->m_numOfElements;
        }

        i2c_cmd_handle_t cmd = i2c_cmd_link_create();
        i2c_master_start(cmd);
        i2c_master_write_byte( cmd, ( slaveAddress << 1 ) | I2C_MASTER_WRITE, 1);

        if ( writeSize != 0 )  // Write
        {
            i2c_master_write(cmd, &writeData[0], writeSize,  true);
        }
        if (readSize != 0 )  // Read
        {
            i2cStatus = i2c_master_read(cmd, &readData[0], readSize, true);
        }

        i2c_master_stop(cmd);

        i2cStatus = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS);
        i2c_cmd_link_delete(cmd);

        // create return object
        NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(top, g_CLR_RT_WellKnownTypes.m_I2cTransferResult));
        result = top.Dereference(); FAULT_ON_NULL(result);

        if (i2cStatus != ESP_OK)
        {
            // set the result field
            if ( i2cStatus == ESP_FAIL )
            {
                result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___status ].SetInteger((CLR_UINT32)I2cTransferStatus_SlaveAddressNotAcknowledged);
            }
            else
            {
                result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___status ].SetInteger((CLR_UINT32)I2cTransferStatus_UnknownError);
            }

            // set the bytes transferred field
            result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___bytesTransferred ].SetInteger(0);
        }
        else
        {
            result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___status ].SetInteger((CLR_UINT32)I2cTransferStatus_FullTransfer);

            // set the bytes transferred field
            result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___bytesTransferred ].SetInteger((CLR_UINT32)(writeSize + readSize));

            if(readSize > 0)
            {
                // because this was a Read transaction, need to copy from DMA buffer to managed buffer
                memcpy(readBuffer->GetFirstElement(), &readData[0], readSize);
            }
        }

        // null pointers and vars
        writeData = NULL;
        readData = NULL;
        writeBuffer = NULL;
        readBuffer = NULL;
        pThis = NULL;

        stack.SetResult_I4(returnStatus);
    }
    NANOCLR_NOCLEANUP();
}

HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::GetDeviceSelector___STATIC__STRING( CLR_RT_StackFrame& stack )
{
    NANOCLR_HEADER();
   {
       // declare the device selector string whose max size is "I2C1,I2C2,I2C3," + terminator and init with the terminator
       char deviceSelectorString[ 15 + 1] = { 0 };

       strcat(deviceSelectorString, "I2C1,I2C2");

       // because the caller is expecting a result to be returned
       // we need set a return result in the stack argument using the appropriate SetResult according to the variable type (a string here)
       stack.SetResult_String(deviceSelectorString);
   }
   NANOCLR_NOCLEANUP();
}
<commit_msg>Fix error introduced in last ESP32 I2C change (#674)<commit_after>//
// Copyright (c) 2017 The nanoFramework project contributors
// Portions Copyright (c) Microsoft Corporation.  All rights reserved.
// See LICENSE file in the project root for full license information.
//

#include <string.h>
#include <targetPAL.h>
#include "win_dev_i2c_native.h"
#include "Esp32_DeviceMapping.h"

///////////////////////////////////////////////////////////////////////////////////////
// !!! KEEP IN SYNC WITH Windows.Devices.I2c.I2cSharingMode (in managed code) !!!    //
///////////////////////////////////////////////////////////////////////////////////////
enum I2cSharingMode
{
    Exclusive = 0,
    Shared
};

///////////////////////////////////////////////////////////////////////////////////////
// !!! KEEP IN SYNC WITH Windows.Devices.I2c.I2cTransferStatus (in managed code) !!! //
///////////////////////////////////////////////////////////////////////////////////////
 enum I2cTransferStatus
{
    I2cTransferStatus_FullTransfer = 0,
    I2cTransferStatus_ClockStretchTimeout,
    I2cTransferStatus_PartialTransfer,
    I2cTransferStatus_SlaveAddressNotAcknowledged,
    I2cTransferStatus_UnknownError
};

///////////////////////////////////////////////////////////////////////////////////////
// !!! KEEP IN SYNC WITH Windows.Devices.I2c.I2cBusSpeed (in managed code) !!!       //
///////////////////////////////////////////////////////////////////////////////////////
enum I2cBusSpeed
{
    I2cBusSpeed_StandardMode = 0,
    I2cBusSpeed_FastMode
};

typedef Library_win_dev_i2c_native_Windows_Devices_I2c_I2cConnectionSettings I2cConnectionSettings;

static char Esp_I2C_Initialised_Flag[I2C_NUM_MAX] = {0,0};

void Esp32_I2c_UnitializeAll()
{
    for (int c = 0; c < I2C_NUM_MAX; c++)
    {
        if (Esp_I2C_Initialised_Flag[c])
        {
            // Delete bus driver
            i2c_driver_delete((i2c_port_t)c);
            Esp_I2C_Initialised_Flag[c] = 0;
        }
    }
}

void Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::SetConfig(i2c_port_t bus, CLR_RT_HeapBlock* config)
{
    int busSpeed = config[ I2cConnectionSettings::FIELD___busSpeed ].NumericByRef().s4;

    gpio_num_t DataPin  = (gpio_num_t)Esp32_GetMappedDevicePins( DEV_TYPE_I2C, bus, 0);
    gpio_num_t ClockPin = (gpio_num_t)Esp32_GetMappedDevicePins( DEV_TYPE_I2C, bus, 1);

    i2c_config_t conf;
        conf.mode = I2C_MODE_MASTER;
        conf.sda_io_num =  DataPin;
        conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
        conf.scl_io_num = ClockPin;
        conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
        conf.master.clk_speed = (busSpeed==0)? 100000 : 400000;

   i2c_param_config(bus, &conf);
}

HRESULT IRAM_ATTR Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeInit___VOID( CLR_RT_StackFrame& stack )
{
    NANOCLR_HEADER();
    {
        // get a pointer to the managed object instance and check that it's not NULL
        CLR_RT_HeapBlock* pThis = stack.This();  FAULT_ON_NULL(pThis);

        // get bus index
        // this is coded with a multiplication, need to perform and int division to get the number
        // see the comments in the SpiDevice() constructor in managed code for details, subtract 1 to get ESP32 bus number
        i2c_port_t bus = (i2c_port_t)((pThis[ FIELD___deviceId ].NumericByRef().s4 / 1000) - 1);
        if ( bus != I2C_NUM_0 && bus != I2C_NUM_1)
        {
            NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
        }

        // get a pointer to the managed spi connectionSettings object instance
        CLR_RT_HeapBlock* pConfig = pThis[ FIELD___connectionSettings ].Dereference();

       // Set the Bus parameters
        SetConfig( bus, pConfig);

        esp_err_t res =  i2c_driver_install( bus, I2C_MODE_MASTER, 0, 0, 0);
        if ( res != ESP_OK)
        {
            NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
        }

       // Ensure driver gets unitialized during soft reboot
       HAL_AddSoftRebootHandler(Esp32_I2c_UnitializeAll);
       Esp_I2C_Initialised_Flag[bus] = 1;
   }
   NANOCLR_NOCLEANUP();
}

HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::DisposeNative___VOID( CLR_RT_StackFrame& stack )
{
    NANOCLR_HEADER();
    {
        // get a pointer to the managed object instance and check that it's not NULL
        CLR_RT_HeapBlock* pThis = stack.This();  FAULT_ON_NULL(pThis);

        i2c_port_t bus = (i2c_port_t)((pThis[ FIELD___deviceId ].NumericByRef().s4 / 1000) - 1);

        i2c_driver_delete(bus);

        Esp_I2C_Initialised_Flag[bus] = 0;
    }
    NANOCLR_NOCLEANUP();
}

HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::NativeTransmit___WindowsDevicesI2cI2cTransferResult__SZARRAY_U1__SZARRAY_U1( CLR_RT_StackFrame& stack )
{
    NANOCLR_HEADER();
    {
        unsigned char * writeData = NULL;
        unsigned char * readData = NULL;
        int writeSize = 0;
        int readSize = 0;
        esp_err_t i2cStatus;
        int returnStatus = I2cTransferStatus_FullTransfer;

        CLR_RT_HeapBlock*       result;
        // create the return object (I2cTransferResult)
        CLR_RT_HeapBlock&       top = stack.PushValueAndClear();

        // get a pointer to the managed object instance and check that it's not NULL
        CLR_RT_HeapBlock* pThis = stack.This();  FAULT_ON_NULL(pThis);

        // get a pointer to the managed spi connectionSettings object instance
        CLR_RT_HeapBlock* pConfig = pThis[ FIELD___connectionSettings ].Dereference();

        // get bus index
        // this is coded with a multiplication, need to perform and int division to get the number
        // see the comments in the SpiDevice() constructor in managed code for details, subtract 1 to get ESP32 bus number
        i2c_port_t bus = (i2c_port_t)((pThis[ FIELD___deviceId ].NumericByRef().s4 / 1000) - 1);

        // Set the Bus parameters
        SetConfig( bus, pConfig);

        int slaveAddress = pConfig[ I2cConnectionSettings::FIELD___slaveAddress ].NumericByRef().s4;

        // dereference the write and read buffers from the arguments
        CLR_RT_HeapBlock_Array* writeBuffer = stack.Arg1().DereferenceArray();
        if (writeBuffer != NULL)
        {
            // grab the pointer to the array by getting the first element of the array
            writeData = writeBuffer->GetFirstElement();

            // get the size of the buffer by reading the number of elements in the HeapBlock array
            writeSize = writeBuffer->m_numOfElements;
        }

        CLR_RT_HeapBlock_Array* readBuffer = stack.Arg2().DereferenceArray();
        if (readBuffer != NULL)
        {
            // grab the pointer to the array by getting the first element of the array
            readData = readBuffer->GetFirstElement();

            // get the size of the buffer by reading the number of elements in the HeapBlock array
            readSize = readBuffer->m_numOfElements;
        }

        i2c_cmd_handle_t cmd = i2c_cmd_link_create();
        i2c_master_start(cmd);
        i2c_master_write_byte( cmd, ( slaveAddress << 1 ) | I2C_MASTER_WRITE, 1);

        if ( writeSize != 0 )  // Write
        {
            i2c_master_write(cmd, &writeData[0], writeSize,  true);
        }
        if (readSize != 0 )  // Read
        {
            i2cStatus = i2c_master_read(cmd, &readData[0], readSize, true);
        }

        i2c_master_stop(cmd);

        i2cStatus = i2c_master_cmd_begin(bus, cmd, 1000 / portTICK_RATE_MS);
        i2c_cmd_link_delete(cmd);

        // create return object
        NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(top, g_CLR_RT_WellKnownTypes.m_I2cTransferResult));
        result = top.Dereference(); FAULT_ON_NULL(result);

        if (i2cStatus != ESP_OK)
        {
            // set the result field
            if ( i2cStatus == ESP_FAIL )
            {
                result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___status ].SetInteger((CLR_UINT32)I2cTransferStatus_SlaveAddressNotAcknowledged);
            }
            else
            {
                result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___status ].SetInteger((CLR_UINT32)I2cTransferStatus_UnknownError);
            }

            // set the bytes transferred field
            result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___bytesTransferred ].SetInteger(0);
        }
        else
        {
            result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___status ].SetInteger((CLR_UINT32)I2cTransferStatus_FullTransfer);

            // set the bytes transferred field
            result[ Library_win_dev_i2c_native_Windows_Devices_I2c_I2cTransferResult::FIELD___bytesTransferred ].SetInteger((CLR_UINT32)(writeSize + readSize));

            if(readSize > 0)
            {
                // because this was a Read transaction, need to copy from DMA buffer to managed buffer
                memcpy(readBuffer->GetFirstElement(), &readData[0], readSize);
            }
        }

        // null pointers and vars
        writeData = NULL;
        readData = NULL;
        writeBuffer = NULL;
        readBuffer = NULL;
        pThis = NULL;

        stack.SetResult_I4(returnStatus);
    }
    NANOCLR_NOCLEANUP();
}

HRESULT Library_win_dev_i2c_native_Windows_Devices_I2c_I2cDevice::GetDeviceSelector___STATIC__STRING( CLR_RT_StackFrame& stack )
{
    NANOCLR_HEADER();
   {
       // declare the device selector string whose max size is "I2C1,I2C2,I2C3," + terminator and init with the terminator
       char deviceSelectorString[ 15 + 1] = { 0 };

       strcat(deviceSelectorString, "I2C1,I2C2");

       // because the caller is expecting a result to be returned
       // we need set a return result in the stack argument using the appropriate SetResult according to the variable type (a string here)
       stack.SetResult_String(deviceSelectorString);
   }
   NANOCLR_NOCLEANUP();
}
<|endoftext|>


<commit_before>/*

    Copyright (C) 2003-2010  Egon Wanke <blitzortung@gmx.org>
    Copyright (C) 2010       Andreas Würl <awuerl@gmx.net>

*/

#include <iostream>
#include <string>

#include <boost/program_options.hpp>

#include "namespaces.h"
#include "hardware/comm/SerialPort.h"
#include "hardware/comm/Serial.h"
#include "hardware/gps/Garmin.h"
#include "hardware/gps/Sirf.h"
#include "hardware/gps/Sjn.h"
#include "hardware/pcb/V4.h"
#include "hardware/pcb/V6.h"
#include "data/sample/V1.h"
#include "network/Base.h"
#include "util/RingBuffer.h"
#include "exception/Base.h"
#include "Logger.h"

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

  std::string username, password, servername;
  unsigned short serverport;
  std::string serialPortName = "/dev/ttyUSB0";
  std::string outputFile = "";
  int serialBaudRate = 19200;
  int sleepTime = 20;
  int sampleVersion = 1;
  int pcbVersion = 6;
  double eventRateLimit = 1.0;
  std::string gpsType = "sirf";

  bo::Logger logger("");

  // programm arguments/options
  boost::program_options::options_description desc("program options");
  desc.add_options()
    ("help", "show program help")
    ("serial-device,d", po::value<std::string>(&serialPortName)->default_value(serialPortName), "path to serial device")
    ("baud-rate,b", po::value<int>(&serialBaudRate)->default_value(serialBaudRate), "baud rate of serial port (4800, 9600, 19200, 38400)")
    ("username,u", po::value<std::string>(&username), "username of blitzortung.org")
    ("password,p", po::value<std::string>(&password), "password of blitzortung.org")
    ("server-host,h", po::value<std::string>(&servername), "blitzortung.org servername")
    ("server-port", po::value<unsigned short>(&serverport)->default_value(8308), "blitzortung.org serverport")
    ("sleep-time,s", po::value<int>(&sleepTime)->default_value(sleepTime), "sleep time between data transmission")
    ("gps-type,g", po::value<std::string>(&gpsType)->default_value(gpsType), "type of gps device (sjn, garmin or sirf)")
    ("pcb-version", po::value<int>(&pcbVersion)->default_value(pcbVersion), "version of PCB (4 or 6)")
    ("event-rate-limit,l", po::value<double>(&eventRateLimit)->default_value(eventRateLimit), "limit of event rate (in events per second) 1.0 means max. 3600 events per hour")
    ("output,o", po::value<std::string>(&outputFile), "output file name (e.g. Name_%Y%m%d.bor)")
    ("verbose,v", "verbose mode")
    ("debug", "debug mode")
    ;

  // parse command line options
  po::variables_map vm;
  po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
  po::notify(vm);

  // help output or no 'sql-statement' given
  if (vm.count("help")) {
    std::cout << argv[0] << " [options]" << std::endl << std::endl;
    std::cout << desc << std::endl;
    std::cout << std::endl;

    return 1;
  }

  if (! vm.count("username")) {
    std::cerr << "'username' missing\n";
    return 5;
  }

  if (! vm.count("password")) {
    std::cerr << "'password' missing\n";
    return 5;
  }

  if (! vm.count("server-host")) {
    std::cerr << "'server-host' missing\n";
    return 5;
  }

  // logging setup

  logger.setPriority(log4cpp::Priority::NOTICE);

  if (vm.count("verbose")) {
    logger.setPriority(log4cpp::Priority::INFO);
  }

  if (vm.count("debug")) {
    logger.setPriority(log4cpp::Priority::DEBUG);
  }

  switch (serialBaudRate) {
    case 4800:
    case 9600:
    case 19200:
    case 38400:
      break;

    default:
      std::ostringstream oss;
      oss << "invalid serial baud rate: " << serialBaudRate;
      throw bo::exception::Base(oss.str());
  }

  // create serial port object

  bo::hardware::comm::SerialPort serialPort(serialPortName, serialBaudRate);
  bo::hardware::comm::Serial serial(serialPort);

  // select type of gps hardware

  bo::hardware::gps::Base::AP gps;

  if (gpsType == "garmin") {
    gps = bo::hardware::gps::Base::AP(new bo::hardware::gps::Garmin(serial));
  } else if (gpsType == "sirf") {
    gps = bo::hardware::gps::Base::AP(new bo::hardware::gps::Sirf(serial));
  } else if (gpsType == "sjn") {
    gps = bo::hardware::gps::Base::AP(new bo::hardware::gps::Sjn(serial));
  } else {
    std::ostringstream oss;
    oss << "invalid value of gps-type: '" << gpsType << "'";
    throw bo::exception::Base(oss.str());
  }

  // create sample creator object
  std::auto_ptr<bo::data::sample::Base::Creator> sampleCreator;

  switch (sampleVersion) {
    case 1:
      sampleCreator = std::auto_ptr<bo::data::sample::Base::Creator>(new bo::data::sample::V1::Creator());
      break;

    default:
      std::ostringstream oss;
      oss << "invalid sample version: " << pcbVersion;
      throw bo::exception::Base(oss.str());
  }

  // create hardware driver object for blitzortung measurement hardware
  bo::hardware::pcb::Base::AP hardware;

  switch (pcbVersion) {
    case 4:
      hardware = bo::hardware::pcb::Base::AP(new bo::hardware::pcb::V4(serial, *gps, *sampleCreator));
      break;

    case 6:
      hardware = bo::hardware::pcb::Base::AP(new bo::hardware::pcb::V6(serial, *gps, *sampleCreator));
      break;

    default:
      std::ostringstream oss;
      oss << "invalid pcb version: " << pcbVersion;
      throw bo::exception::Base(oss.str());
  }

  //! set credentials/parameters for network connection
  bo::network::Creds creds;
  creds.setServername(servername);
  creds.setServerport(serverport);
  creds.setUsername(username);
  creds.setPassword(password);

  //! create object of network driver for sample transmission
  bo::network::Base::AP network(new bo::network::Base(creds, sleepTime, eventRateLimit, outputFile));

  while (hardware->isOpen()) {

    bo::data::sample::Base::AP sample = hardware->read();

    if (sample.get() != 0) {
      network->push(sample);
    }

  }

}
<commit_msg>fix error message<commit_after>/*

    Copyright (C) 2003-2010  Egon Wanke <blitzortung@gmx.org>
    Copyright (C) 2010       Andreas Würl <awuerl@gmx.net>

*/

#include <iostream>
#include <string>

#include <boost/program_options.hpp>

#include "namespaces.h"
#include "hardware/comm/SerialPort.h"
#include "hardware/comm/Serial.h"
#include "hardware/gps/Garmin.h"
#include "hardware/gps/Sirf.h"
#include "hardware/gps/Sjn.h"
#include "hardware/pcb/V4.h"
#include "hardware/pcb/V6.h"
#include "data/sample/V1.h"
#include "network/Base.h"
#include "util/RingBuffer.h"
#include "exception/Base.h"
#include "Logger.h"

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

  std::string username, password, servername;
  unsigned short serverport;
  std::string serialPortName = "/dev/ttyUSB0";
  std::string outputFile = "";
  int serialBaudRate = 19200;
  int sleepTime = 20;
  int sampleVersion = 1;
  int pcbVersion = 6;
  double eventRateLimit = 1.0;
  std::string gpsType = "sirf";

  bo::Logger logger("");

  // programm arguments/options
  boost::program_options::options_description desc("program options");
  desc.add_options()
    ("help", "show program help")
    ("serial-device,d", po::value<std::string>(&serialPortName)->default_value(serialPortName), "path to serial device")
    ("baud-rate,b", po::value<int>(&serialBaudRate)->default_value(serialBaudRate), "baud rate of serial port (4800, 9600, 19200, 38400)")
    ("username,u", po::value<std::string>(&username), "username of blitzortung.org")
    ("password,p", po::value<std::string>(&password), "password of blitzortung.org")
    ("server-host,h", po::value<std::string>(&servername), "blitzortung.org servername")
    ("server-port", po::value<unsigned short>(&serverport)->default_value(8308), "blitzortung.org serverport")
    ("sleep-time,s", po::value<int>(&sleepTime)->default_value(sleepTime), "sleep time between data transmission")
    ("gps-type,g", po::value<std::string>(&gpsType)->default_value(gpsType), "type of gps device (sjn, garmin or sirf)")
    ("pcb-version", po::value<int>(&pcbVersion)->default_value(pcbVersion), "version of PCB (4 or 6)")
    ("event-rate-limit,l", po::value<double>(&eventRateLimit)->default_value(eventRateLimit), "limit of event rate (in events per second) 1.0 means max. 3600 events per hour")
    ("output,o", po::value<std::string>(&outputFile), "output file name (e.g. Name_%Y%m%d.bor)")
    ("verbose,v", "verbose mode")
    ("debug", "debug mode")
    ;

  // parse command line options
  po::variables_map vm;
  po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
  po::notify(vm);

  // help output or no 'sql-statement' given
  if (vm.count("help")) {
    std::cout << argv[0] << " [options]" << std::endl << std::endl;
    std::cout << desc << std::endl;
    std::cout << std::endl;

    return 1;
  }

  if (! vm.count("username")) {
    std::cerr << "'username' missing\n";
    return 5;
  }

  if (! vm.count("password")) {
    std::cerr << "'password' missing\n";
    return 5;
  }

  if (! vm.count("server-host")) {
    std::cerr << "'server-host' missing\n";
    return 5;
  }

  // logging setup

  logger.setPriority(log4cpp::Priority::NOTICE);

  if (vm.count("verbose")) {
    logger.setPriority(log4cpp::Priority::INFO);
  }

  if (vm.count("debug")) {
    logger.setPriority(log4cpp::Priority::DEBUG);
  }

  switch (serialBaudRate) {
    case 4800:
    case 9600:
    case 19200:
    case 38400:
      break;

    default:
      std::ostringstream oss;
      oss << "invalid serial baud rate: " << serialBaudRate;
      throw bo::exception::Base(oss.str());
  }

  // create serial port object

  bo::hardware::comm::SerialPort serialPort(serialPortName, serialBaudRate);
  bo::hardware::comm::Serial serial(serialPort);

  // select type of gps hardware

  bo::hardware::gps::Base::AP gps;

  if (gpsType == "garmin") {
    gps = bo::hardware::gps::Base::AP(new bo::hardware::gps::Garmin(serial));
  } else if (gpsType == "sirf") {
    gps = bo::hardware::gps::Base::AP(new bo::hardware::gps::Sirf(serial));
  } else if (gpsType == "sjn") {
    gps = bo::hardware::gps::Base::AP(new bo::hardware::gps::Sjn(serial));
  } else {
    std::ostringstream oss;
    oss << "invalid value of gps-type: '" << gpsType << "'";
    throw bo::exception::Base(oss.str());
  }

  // create sample creator object
  std::auto_ptr<bo::data::sample::Base::Creator> sampleCreator;

  switch (sampleVersion) {
    case 1:
      sampleCreator = std::auto_ptr<bo::data::sample::Base::Creator>(new bo::data::sample::V1::Creator());
      break;

    default:
      std::ostringstream oss;
      oss << "invalid sample version: " << sampleVersion;
      throw bo::exception::Base(oss.str());
  }

  // create hardware driver object for blitzortung measurement hardware
  bo::hardware::pcb::Base::AP hardware;

  switch (pcbVersion) {
    case 4:
      hardware = bo::hardware::pcb::Base::AP(new bo::hardware::pcb::V4(serial, *gps, *sampleCreator));
      break;

    case 6:
      hardware = bo::hardware::pcb::Base::AP(new bo::hardware::pcb::V6(serial, *gps, *sampleCreator));
      break;

    default:
      std::ostringstream oss;
      oss << "invalid pcb version: " << pcbVersion;
      throw bo::exception::Base(oss.str());
  }

  //! set credentials/parameters for network connection
  bo::network::Creds creds;
  creds.setServername(servername);
  creds.setServerport(serverport);
  creds.setUsername(username);
  creds.setPassword(password);

  //! create object of network driver for sample transmission
  bo::network::Base::AP network(new bo::network::Base(creds, sleepTime, eventRateLimit, outputFile));

  while (hardware->isOpen()) {

    bo::data::sample::Base::AP sample = hardware->read();

    if (sample.get() != 0) {
      network->push(sample);
    }

  }

}
<|endoftext|>


<commit_before>#include "StatScreen.h"
#include "RenderTarget.h"
#include "RenderContext.h"
#include "gum/StringHelper.h"

#include <gimg_typedef.h>
#include <gimg_export.h>
#include <unirender/UR_RenderContext.h>
#include <dtex2/DebugDraw.h>

#include <time.h>

namespace gum
{

SINGLETON_DEFINITION(StatScreen);

StatScreen::StatScreen()
	: m_enable(false)
	, m_rt(NULL)
	, m_x(0)
	, m_y(0)
{
}

void StatScreen::Enable(bool enable)
{
	if (m_enable == enable) {
		return;
	}

	m_enable = enable;

	if (enable) {
		m_rt = new RenderTarget(RT_EDGE, RT_EDGE);
#ifdef __ANDROID__
		std::string filepath = "/sdcard/lr_stat_screen.bin";
#else
		std::string filepath = "lr_stat_screen.bin";
#endif // __ANDROID__
		m_fout.open(filepath.c_str(), std::ofstream::out | std::ofstream::binary | std::ofstream::app);
	} else {
		delete m_rt;

		m_fout.close();
	}
}

void StatScreen::Print(const RenderTarget* src)
{
	if (!m_enable) {
		return;
	}

	time_t t = time(NULL);
	m_timestamps[m_y * GRID_COUNT + m_x] = t;

	sm::rect r_src;
	r_src.xmin = r_src.ymin = 0;
	r_src.xmax = r_src.ymax = 1;

	sm::rect r_dst;
	static const float GRID_TEXCOORD_EDGE = 1.0f / GRID_COUNT;
	r_dst.xmin = static_cast<float>(m_x) / GRID_COUNT;
	r_dst.xmax = r_dst.xmin + GRID_TEXCOORD_EDGE;
	r_dst.ymin = static_cast<float>(m_y) / GRID_COUNT;
	r_dst.ymax = r_dst.ymin + GRID_TEXCOORD_EDGE;

	m_rt->Bind();
	src->Draw(r_src, r_dst, RT_EDGE, RT_EDGE);
	m_rt->Unbind();

	// to next grid
	++m_x;
	if (m_x == GRID_COUNT) {
		m_x = 0;
		++m_y;
	}
	if (m_y == GRID_COUNT) {
		m_y = 0;
	}
}

void StatScreen::Clear()
{
	m_x = m_y = 0;
	memset(m_timestamps, 0, sizeof(m_timestamps));
}

void StatScreen::Flush()
{
	if (!m_enable) {
		return;
	}

	time_t first_time = m_timestamps[0];

	for (int y = 0; y < GRID_COUNT; ++y) {
		for (int x = 0; x < GRID_COUNT; ++x) {
			int idx = y * GRID_COUNT + x;
			time_t time = m_timestamps[idx];
			if (time != 0) {
				m_fout << "timestamp " << time << ", x " << x << ", y " << y << ", file " << first_time << ".png" << '\n';
			}
		}
	}
	m_fout.flush();

	int next = m_y * GRID_COUNT + m_x;

	m_rt->Bind();

	uint8_t* pixels = new uint8_t[RT_EDGE * RT_EDGE * 3];
	memset(pixels, 0, RT_EDGE * RT_EDGE * 3);
	RenderContext::Instance()->GetImpl()->ReadPixels(pixels, 3, 0, 0, RT_EDGE, RT_EDGE);
	std::string filepath = StringHelper::ToString(first_time) + ".png";
	gimg_export(filepath.c_str(), pixels, RT_EDGE, RT_EDGE, GPF_RGB, true);
	delete[] pixels;

	m_rt->Unbind();
}

void StatScreen::DebugDraw() const
{
	if (m_enable) {
		int texid = m_rt->GetTexID();
		dtex::DebugDraw::Draw(texid, 1);
	}
}

}<commit_msg>fix include<commit_after>#include "StatScreen.h"
#include "RenderTarget.h"
#include "RenderContext.h"
#include "gum/StringHelper.h"

#include <gimg_typedef.h>
#include <gimg_export.h>
#include <unirender/UR_RenderContext.h>
#include <dtex2/DebugDraw.h>

#include <time.h>
#include <string.h>

namespace gum
{

SINGLETON_DEFINITION(StatScreen);

StatScreen::StatScreen()
	: m_enable(false)
	, m_rt(NULL)
	, m_x(0)
	, m_y(0)
{
}

void StatScreen::Enable(bool enable)
{
	if (m_enable == enable) {
		return;
	}

	m_enable = enable;

	if (enable) {
		m_rt = new RenderTarget(RT_EDGE, RT_EDGE);
#ifdef __ANDROID__
		std::string filepath = "/sdcard/lr_stat_screen.bin";
#else
		std::string filepath = "lr_stat_screen.bin";
#endif // __ANDROID__
		m_fout.open(filepath.c_str(), std::ofstream::out | std::ofstream::binary | std::ofstream::app);
	} else {
		delete m_rt;

		m_fout.close();
	}
}

void StatScreen::Print(const RenderTarget* src)
{
	if (!m_enable) {
		return;
	}

	time_t t = time(NULL);
	m_timestamps[m_y * GRID_COUNT + m_x] = t;

	sm::rect r_src;
	r_src.xmin = r_src.ymin = 0;
	r_src.xmax = r_src.ymax = 1;

	sm::rect r_dst;
	static const float GRID_TEXCOORD_EDGE = 1.0f / GRID_COUNT;
	r_dst.xmin = static_cast<float>(m_x) / GRID_COUNT;
	r_dst.xmax = r_dst.xmin + GRID_TEXCOORD_EDGE;
	r_dst.ymin = static_cast<float>(m_y) / GRID_COUNT;
	r_dst.ymax = r_dst.ymin + GRID_TEXCOORD_EDGE;

	m_rt->Bind();
	src->Draw(r_src, r_dst, RT_EDGE, RT_EDGE);
	m_rt->Unbind();

	// to next grid
	++m_x;
	if (m_x == GRID_COUNT) {
		m_x = 0;
		++m_y;
	}
	if (m_y == GRID_COUNT) {
		m_y = 0;
	}
}

void StatScreen::Clear()
{
	m_x = m_y = 0;
	memset(m_timestamps, 0, sizeof(m_timestamps));
}

void StatScreen::Flush()
{
	if (!m_enable) {
		return;
	}

	time_t first_time = m_timestamps[0];

	for (int y = 0; y < GRID_COUNT; ++y) {
		for (int x = 0; x < GRID_COUNT; ++x) {
			int idx = y * GRID_COUNT + x;
			time_t time = m_timestamps[idx];
			if (time != 0) {
				m_fout << "timestamp " << time << ", x " << x << ", y " << y << ", file " << first_time << ".png" << '\n';
			}
		}
	}
	m_fout.flush();

	int next = m_y * GRID_COUNT + m_x;

	m_rt->Bind();

	uint8_t* pixels = new uint8_t[RT_EDGE * RT_EDGE * 3];
	memset(pixels, 0, RT_EDGE * RT_EDGE * 3);
	RenderContext::Instance()->GetImpl()->ReadPixels(pixels, 3, 0, 0, RT_EDGE, RT_EDGE);
	std::string filepath = StringHelper::ToString(first_time) + ".png";
	gimg_export(filepath.c_str(), pixels, RT_EDGE, RT_EDGE, GPF_RGB, true);
	delete[] pixels;

	m_rt->Unbind();
}

void StatScreen::DebugDraw() const
{
	if (m_enable) {
		int texid = m_rt->GetTexID();
		dtex::DebugDraw::Draw(texid, 1);
	}
}

}<|endoftext|>


<commit_before>#include <efsw/FileWatcherWin32.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/System.hpp>

#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32

namespace efsw
{

FileWatcherWin32::FileWatcherWin32( FileWatcher * parent ) :
	FileWatcherImpl( parent ),
	mLastWatchID(0),
	mThread( NULL )
{
	mInitOK = true;
}

FileWatcherWin32::~FileWatcherWin32()
{
	WatchVector::iterator iter = mWatches.begin();

	for(; iter != mWatches.end(); ++iter)
	{
		DestroyWatch((*iter));
	}

	mHandles.clear();
	mWatches.clear();

	mInitOK = false;

	mThread->wait();

	efSAFE_DELETE( mThread );
}

WatchID FileWatcherWin32::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
{
	std::string dir( directory );

	FileInfo fi( dir );

	if ( !fi.isDirectory() )
	{
		return Errors::Log::createLastError( Errors::FileNotFound, dir );
	}
	else if ( !fi.isReadable() )
	{
		return Errors::Log::createLastError( Errors::FileNotReadable, dir );
	}

	FileSystem::dirAddSlashAtEnd( dir );

	WatchID watchid = ++mLastWatchID;

	WatcherStructWin32 * watch = CreateWatch( dir.c_str(), recursive,	FILE_NOTIFY_CHANGE_CREATION |
																			FILE_NOTIFY_CHANGE_SIZE |
																			FILE_NOTIFY_CHANGE_FILE_NAME |
																			FILE_NOTIFY_CHANGE_DIR_NAME
	);

	if( NULL == watch )
	{
		return Errors::Log::createLastError( Errors::FileNotFound, dir );
	}

	if ( pathInWatches( dir ) )
	{
		return Errors::Log::createLastError( Errors::FileRepeated, dir );
	}

	// Add the handle to the handles vector
	watch->Watch->ID = watchid;
	watch->Watch->Watch = this;
	watch->Watch->Listener = watcher;
	watch->Watch->DirName = new char[dir.length()+1];
	strcpy(watch->Watch->DirName, dir.c_str());

	mWatchesLock.lock();
	mHandles.push_back( watch->Watch->DirHandle );
	mWatches.push_back( watch );
	mWatchesLock.unlock();

	return watchid;
}

void FileWatcherWin32::removeWatch(const std::string& directory)
{
	mWatchesLock.lock();

	WatchVector::iterator iter = mWatches.begin();

	for(; iter != mWatches.end(); ++iter)
	{
		if(directory == (*iter)->Watch->DirName)
		{
			removeWatch((*iter)->Watch->ID);
			return;
		}
	}

	mWatchesLock.unlock();
}

void FileWatcherWin32::removeWatch(WatchID watchid)
{
	mWatchesLock.lock();

	WatchVector::iterator iter = mWatches.begin();

	WatcherStructWin32* watch = NULL;

	for(; iter != mWatches.end(); ++iter)
	{
		// Find the watch ID
		if ( (*iter)->Watch->ID == watchid )
		{
			watch	= (*iter);

			mWatches.erase( iter );

			// Remove handle from the handle vector
			HandleVector::iterator it = mHandles.begin();

			for ( ; it != mHandles.end(); it++ )
			{
				if ( watch->Watch->DirHandle == (*it) )
				{
					mHandles.erase( it );
					break;
				}
			}

			DestroyWatch(watch);

			break;
		}
	}

	mWatchesLock.unlock();
}

void FileWatcherWin32::watch()
{
	if ( NULL == mThread )
	{
		mThread = new Thread( &FileWatcherWin32::run, this );
		mThread->launch();
	}
}

void FileWatcherWin32::run()
{
	do
	{
		DWORD wait_result = WaitForMultipleObjectsEx( mHandles.size(), &mHandles[0], FALSE, 1000, FALSE );

		switch ( wait_result )
		{
			case WAIT_ABANDONED_0:
			case WAIT_ABANDONED_0 + 1:
				//"Wait abandoned."
				break;
			case WAIT_TIMEOUT:
				break;
			case WAIT_FAILED:
				//"Wait failed."
				break;
			default:
			{
				mWatchesLock.lock();

				// Don't trust the result - multiple objects may be signalled during a single call.
				if ( wait_result >=  WAIT_OBJECT_0 && wait_result < WAIT_OBJECT_0 + mWatches.size() )
				{
					WatcherStructWin32 * watch = mWatches[ wait_result ];

					// First ensure that the handle is the same, this means that the watch was not removed.
					if ( mHandles[ wait_result ] == watch->Watch->DirHandle && HasOverlappedIoCompleted( &watch->Overlapped ) )
					{
						DWORD bytes;

						if ( GetOverlappedResult( watch->Watch->DirHandle, &watch->Overlapped, &bytes, FALSE ) )
						{
							WatchCallback( ERROR_SUCCESS, bytes, &watch->Overlapped );
						}
						else
						{
							//"GetOverlappedResult failed."
						}

						break;
					}
				}
				else
				{
					//"Unknown return value from WaitForMultipleObjectsEx."
				}

				mWatchesLock.unlock();
			}
		}
	} while ( mInitOK );
}

void FileWatcherWin32::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename)
{
	Action fwAction;

	switch(action)
	{
	case FILE_ACTION_RENAMED_OLD_NAME:
		watch->OldFileName = filename;
		break;
	case FILE_ACTION_ADDED:
		fwAction = Actions::Add;
		break;
	case FILE_ACTION_RENAMED_NEW_NAME:
	{
		fwAction = Actions::Moved;

		std::string fpath( watch->Directory + filename );

		// Update the directory path
		if ( watch->Recursive && FileSystem::isDirectory( fpath ) )
		{
			// Update the new directory path
			std::string opath( watch->Directory + watch->OldFileName );
			FileSystem::dirAddSlashAtEnd( opath );
			FileSystem::dirAddSlashAtEnd( fpath );

			for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
			{
				if ( (*it)->Watch->Directory == opath )
				{
					(*it)->Watch->Directory = fpath;

					break;
				}
			}
		}

		watch->Listener->handleFileAction(watch->ID, static_cast<WatcherWin32*>( watch )->DirName, filename, fwAction, watch->OldFileName);
		return;
	}
	case FILE_ACTION_REMOVED:
		fwAction = Actions::Delete;
		break;
	case FILE_ACTION_MODIFIED:
		fwAction = Actions::Modified;
		break;
	};

	watch->Listener->handleFileAction(watch->ID, static_cast<WatcherWin32*>( watch )->DirName, filename, fwAction);
}

std::list<std::string> FileWatcherWin32::directories()
{
	std::list<std::string> dirs;

	mWatchesLock.lock();

	for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
	{
		dirs.push_back( std::string( (*it)->Watch->DirName ) );
	}

	mWatchesLock.unlock();

	return dirs;
}

bool FileWatcherWin32::pathInWatches( const std::string& path )
{
	for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
	{
		if ( (*it)->Watch->DirName == path )
		{
			return true;
		}
	}

	return false;
}

}

#endif
<commit_msg>Small fix in Win32 backend.<commit_after>#include <efsw/FileWatcherWin32.hpp>
#include <efsw/FileSystem.hpp>
#include <efsw/System.hpp>

#if EFSW_PLATFORM == EFSW_PLATFORM_WIN32

namespace efsw
{

FileWatcherWin32::FileWatcherWin32( FileWatcher * parent ) :
	FileWatcherImpl( parent ),
	mLastWatchID(0),
	mThread( NULL )
{
	mInitOK = true;
}

FileWatcherWin32::~FileWatcherWin32()
{
	WatchVector::iterator iter = mWatches.begin();

	for(; iter != mWatches.end(); ++iter)
	{
		DestroyWatch((*iter));
	}

	mHandles.clear();
	mWatches.clear();

	mInitOK = false;

	mThread->wait();

	efSAFE_DELETE( mThread );
}

WatchID FileWatcherWin32::addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive)
{
	std::string dir( directory );

	FileInfo fi( dir );

	if ( !fi.isDirectory() )
	{
		return Errors::Log::createLastError( Errors::FileNotFound, dir );
	}
	else if ( !fi.isReadable() )
	{
		return Errors::Log::createLastError( Errors::FileNotReadable, dir );
	}

	FileSystem::dirAddSlashAtEnd( dir );

	WatchID watchid = ++mLastWatchID;

	WatcherStructWin32 * watch = CreateWatch( dir.c_str(), recursive,	FILE_NOTIFY_CHANGE_CREATION |
																			FILE_NOTIFY_CHANGE_SIZE |
																			FILE_NOTIFY_CHANGE_FILE_NAME |
																			FILE_NOTIFY_CHANGE_DIR_NAME
	);

	if( NULL == watch )
	{
		return Errors::Log::createLastError( Errors::FileNotFound, dir );
	}

	if ( pathInWatches( dir ) )
	{
		return Errors::Log::createLastError( Errors::FileRepeated, dir );
	}

	// Add the handle to the handles vector
	watch->Watch->ID = watchid;
	watch->Watch->Watch = this;
	watch->Watch->Listener = watcher;
	watch->Watch->DirName = new char[dir.length()+1];
	strcpy(watch->Watch->DirName, dir.c_str());

	mWatchesLock.lock();
	mHandles.push_back( watch->Watch->DirHandle );
	mWatches.push_back( watch );
	mWatchesLock.unlock();

	return watchid;
}

void FileWatcherWin32::removeWatch(const std::string& directory)
{
	mWatchesLock.lock();

	WatchVector::iterator iter = mWatches.begin();

	for(; iter != mWatches.end(); ++iter)
	{
		if(directory == (*iter)->Watch->DirName)
		{
			removeWatch((*iter)->Watch->ID);
			return;
		}
	}

	mWatchesLock.unlock();
}

void FileWatcherWin32::removeWatch(WatchID watchid)
{
	mWatchesLock.lock();

	WatchVector::iterator iter = mWatches.begin();

	WatcherStructWin32* watch = NULL;

	for(; iter != mWatches.end(); ++iter)
	{
		// Find the watch ID
		if ( (*iter)->Watch->ID == watchid )
		{
			watch	= (*iter);

			mWatches.erase( iter );

			// Remove handle from the handle vector
			HandleVector::iterator it = mHandles.begin();

			for ( ; it != mHandles.end(); it++ )
			{
				if ( watch->Watch->DirHandle == (*it) )
				{
					mHandles.erase( it );
					break;
				}
			}

			DestroyWatch(watch);

			break;
		}
	}

	mWatchesLock.unlock();
}

void FileWatcherWin32::watch()
{
	if ( NULL == mThread )
	{
		mThread = new Thread( &FileWatcherWin32::run, this );
		mThread->launch();
	}
}

void FileWatcherWin32::run()
{
	do
	{
		DWORD wait_result = WaitForMultipleObjectsEx( mHandles.size(), &mHandles[0], FALSE, 1000, FALSE );

		switch ( wait_result )
		{
			case WAIT_ABANDONED_0:
			case WAIT_ABANDONED_0 + 1:
				//"Wait abandoned."
				break;
			case WAIT_TIMEOUT:
				break;
			case WAIT_FAILED:
				//"Wait failed."
				break;
			default:
			{
				mWatchesLock.lock();

				// Don't trust the result - multiple objects may be signalled during a single call.
				if ( wait_result >=  WAIT_OBJECT_0 && wait_result < WAIT_OBJECT_0 + mWatches.size() )
				{
					WatcherStructWin32 * watch = mWatches[ wait_result ];

					// First ensure that the handle is the same, this means that the watch was not removed.
					if ( mHandles[ wait_result ] == watch->Watch->DirHandle && HasOverlappedIoCompleted( &watch->Overlapped ) )
					{
						DWORD bytes;

						if ( GetOverlappedResult( watch->Watch->DirHandle, &watch->Overlapped, &bytes, FALSE ) )
						{
							WatchCallback( ERROR_SUCCESS, bytes, &watch->Overlapped );
						}
						else
						{
							//"GetOverlappedResult failed."
						}

						break;
					}
				}
				else
				{
					//"Unknown return value from WaitForMultipleObjectsEx."
				}

				mWatchesLock.unlock();
			}
		}
	} while ( mInitOK );
}

void FileWatcherWin32::handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename)
{
	Action fwAction;

	switch(action)
	{
	case FILE_ACTION_RENAMED_OLD_NAME:
		watch->OldFileName = filename;
		return;
	case FILE_ACTION_ADDED:
		fwAction = Actions::Add;
		break;
	case FILE_ACTION_RENAMED_NEW_NAME:
	{
		fwAction = Actions::Moved;

		std::string fpath( watch->Directory + filename );

		// Update the directory path
		if ( watch->Recursive && FileSystem::isDirectory( fpath ) )
		{
			// Update the new directory path
			std::string opath( watch->Directory + watch->OldFileName );
			FileSystem::dirAddSlashAtEnd( opath );
			FileSystem::dirAddSlashAtEnd( fpath );

			for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
			{
				if ( (*it)->Watch->Directory == opath )
				{
					(*it)->Watch->Directory = fpath;

					break;
				}
			}
		}

		watch->Listener->handleFileAction(watch->ID, static_cast<WatcherWin32*>( watch )->DirName, filename, fwAction, watch->OldFileName);
		return;
	}
	case FILE_ACTION_REMOVED:
		fwAction = Actions::Delete;
		break;
	case FILE_ACTION_MODIFIED:
		fwAction = Actions::Modified;
		break;
	};

	watch->Listener->handleFileAction(watch->ID, static_cast<WatcherWin32*>( watch )->DirName, filename, fwAction);
}

std::list<std::string> FileWatcherWin32::directories()
{
	std::list<std::string> dirs;

	mWatchesLock.lock();

	for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
	{
		dirs.push_back( std::string( (*it)->Watch->DirName ) );
	}

	mWatchesLock.unlock();

	return dirs;
}

bool FileWatcherWin32::pathInWatches( const std::string& path )
{
	for ( WatchVector::iterator it = mWatches.begin(); it != mWatches.end(); it++ )
	{
		if ( (*it)->Watch->DirName == path )
		{
			return true;
		}
	}

	return false;
}

}

#endif
<|endoftext|>


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

#include "rocksdb_engine.hpp"
#include "codec.hpp"
#include "util/helpers.hpp"
#include "rocksdb/env.h"
#include "rocksdb/rate_limiter.h"
#include "rocksdb/table.h"
#include <string.h>
#include <stdarg.h>

#define ROCKSDB_SLICE(slice) rocksdb::Slice(slice.data(), slice.size())
#define ARDB_SLICE(slice) Slice(slice.data(), slice.size())

namespace ardb
{
    class RocksDBLogger: public rocksdb::Logger
    {
        private:
            void Logv(const char* format, va_list ap)
            {
                char logbuf[1024];
                int len = vsnprintf(logbuf, sizeof(logbuf), format, ap);
                if(len < sizeof(logbuf))
                {
                    INFO_LOG(logbuf);
                }
            }
    };

    int RocksDBComparator::Compare(const rocksdb::Slice& a, const rocksdb::Slice& b) const
    {
        return CommonComparator::Compare(a.data(), a.size(), b.data(), b.size());
    }

    void RocksDBComparator::FindShortestSeparator(std::string* start, const rocksdb::Slice& limit) const
    {
    }

    void RocksDBComparator::FindShortSuccessor(std::string* key) const
    {
    }

    RocksDBEngineFactory::RocksDBEngineFactory(const Properties& props)
    {
        ParseConfig(props, m_cfg);
    }

    void RocksDBEngineFactory::ParseConfig(const Properties& props, RocksDBConfig& cfg)
    {
        cfg.path = ".";
        conf_get_string(props, "data-dir", cfg.path);
        conf_get_int64(props, "rocksdb.block_cache_size", cfg.block_cache_size);
        conf_get_int64(props, "rocksdb.block_cache_compressed", cfg.block_cache_compressed_size);
        conf_get_int64(props, "rocksdb.write_buffer_size", cfg.write_buffer_size);
        conf_get_int64(props, "rocksdb.max_open_files", cfg.max_open_files);
        conf_get_int64(props, "rocksdb.block_size", cfg.block_size);
        conf_get_int64(props, "rocksdb.block_restart_interval", cfg.block_restart_interval);
        conf_get_int64(props, "rocksdb.bloom_bits", cfg.bloom_bits);
        conf_get_int64(props, "rocksdb.batch_commit_watermark", cfg.batch_commit_watermark);
        conf_get_string(props, "rocksdb.compression", cfg.compression);
        conf_get_bool(props, "rocksdb.logenable", cfg.logenable);
        conf_get_bool(props, "rocksdb.skip_log_error_on_recovery", cfg.skip_log_error_on_recovery);
        conf_get_int64(props, "rocksdb.flush_compact_rate_bytes_per_sec", cfg.flush_compact_rate_bytes_per_sec);
        conf_get_double(props, "rocksdb.hard_rate_limit", cfg.hard_rate_limit);
        conf_get_bool(props, "rocksdb.disableWAL", cfg.disableWAL);
        conf_get_int64(props, "rocksdb.max_manifest_file_size", cfg.max_manifest_file_size);
        conf_get_string(props, "rocksdb.compacton_style", cfg.compacton_style);
    }

    KeyValueEngine* RocksDBEngineFactory::CreateDB(const std::string& name)
    {
        RocksDBEngine* engine = new RocksDBEngine();
        RocksDBConfig cfg = m_cfg;
        char tmp[cfg.path.size() + name.size() + 10];
        sprintf(tmp, "%s/%s", cfg.path.c_str(), name.c_str());
        cfg.path = tmp;
        if (engine->Init(cfg) != 0)
        {
            DELETE(engine);
            ERROR_LOG("Failed to create DB:%s", name.c_str());
            return NULL;
        }
        return engine;
    }
    void RocksDBEngineFactory::DestroyDB(KeyValueEngine* engine)
    {
        RocksDBEngine* RocksDB = (RocksDBEngine*) engine;
        std::string path = RocksDB->m_db_path;
        DELETE(engine);
        rocksdb::Options options;
        rocksdb::DestroyDB(path, options);
    }

    void RocksDBEngineFactory::CloseDB(KeyValueEngine* engine)
    {
        DELETE(engine);
    }
    void RocksDBIterator::SeekToFirst()
    {
        m_iter->SeekToFirst();
    }
    void RocksDBIterator::SeekToLast()
    {
        m_iter->SeekToLast();
    }
    void RocksDBIterator::Seek(const Slice& target)
    {
        m_iter->Seek(ROCKSDB_SLICE(target));
    }
    void RocksDBIterator::Next()
    {
        m_iter->Next();
    }
    void RocksDBIterator::Prev()
    {
        m_iter->Prev();
    }
    Slice RocksDBIterator::Key() const
    {
        return ARDB_SLICE(m_iter->key());
    }
    Slice RocksDBIterator::Value() const
    {
        return ARDB_SLICE(m_iter->value());
    }
    bool RocksDBIterator::Valid()
    {
        return m_iter->Valid();
    }

    RocksDBEngine::RocksDBEngine() :
            m_db(NULL)
    {

    }
    RocksDBEngine::~RocksDBEngine()
    {
        DELETE(m_db);
    }
    int RocksDBEngine::Init(const RocksDBConfig& cfg)
    {
        m_cfg = cfg;
        m_options.create_if_missing = true;
        m_options.comparator = &m_comparator;
        rocksdb::BlockBasedTableOptions block_options;
        if (cfg.block_cache_size > 0)
        {
            block_options.block_cache = rocksdb::NewLRUCache(cfg.block_cache_size);
            //m_options.block_cache_compressed = rocksdb::NewLRUCache(cfg.block_cache_compressed_size);
        }else if(cfg.block_cache_size < 0)
        {
            block_options.no_block_cache = true;
        }
        if (cfg.block_size > 0)
        {
            block_options.block_size = cfg.block_size;
        }
        if (cfg.block_restart_interval > 0)
        {
            block_options.block_restart_interval = cfg.block_restart_interval;
        }
        m_options.table_factory.reset(rocksdb::NewBlockBasedTableFactory(block_options));

        if (cfg.write_buffer_size > 0)
        {
            m_options.write_buffer_size = cfg.write_buffer_size;
        }
        m_options.max_open_files = cfg.max_open_files;
        if (cfg.bloom_bits > 0)
        {
            block_options.filter_policy = rocksdb::NewBloomFilterPolicy(cfg.bloom_bits);
        }

        if (!strcasecmp(cfg.compression.c_str(), "none"))
        {
            m_options.compression = rocksdb::kNoCompression;
        }
        else
        {
            m_options.compression = rocksdb::kSnappyCompression;
        }
        if(cfg.flush_compact_rate_bytes_per_sec > 0)
        {
            m_options.rate_limiter.reset(rocksdb::NewGenericRateLimiter(cfg.flush_compact_rate_bytes_per_sec));
        }
        m_options.hard_rate_limit = cfg.hard_rate_limit;
        if(m_cfg.max_manifest_file_size > 0)
        {
            m_options.max_manifest_file_size = m_cfg.max_manifest_file_size;
        }
        if(!strcasecmp(m_cfg.compacton_style.c_str(), "universal"))
        {
            m_options.OptimizeUniversalStyleCompaction();
        }else
        {
            m_options.OptimizeLevelStyleCompaction();
        }
        m_options.IncreaseParallelism();

        if(cfg.logenable)
        {
            m_options.info_log.reset(new RocksDBLogger);
        }
        make_dir(cfg.path);
        m_db_path = cfg.path;
        rocksdb::Status status = rocksdb::DB::Open(m_options, cfg.path.c_str(), &m_db);
        do
        {
            if (status.ok())
            {
                break;
            }
            else if (status.IsCorruption())
            {
                ERROR_LOG("Failed to init engine:%s", status.ToString().c_str());
                status = rocksdb::RepairDB(cfg.path.c_str(), m_options);
                if (!status.ok())
                {
                    ERROR_LOG("Failed to repair:%s for %s", cfg.path.c_str(), status.ToString().c_str());
                    return -1;
                }
                status = rocksdb::DB::Open(m_options, cfg.path.c_str(), &m_db);
            }
            else
            {
                ERROR_LOG("Failed to init engine:%s", status.ToString().c_str());
                break;
            }
        } while (1);
        return status.ok() ? 0 : -1;
    }

    int RocksDBEngine::BeginBatchWrite()
    {
        m_context.GetValue().AddRef();
        return 0;
    }
    int RocksDBEngine::CommitBatchWrite()
    {
        ContextHolder& holder = m_context.GetValue();
        holder.ReleaseRef();
        if (holder.EmptyRef())
        {
            return FlushWriteBatch(holder);
        }
        return 0;
    }
    int RocksDBEngine::DiscardBatchWrite()
    {
        ContextHolder& holder = m_context.GetValue();
        holder.ReleaseRef();
        holder.Clear();
        return 0;
    }

    int RocksDBEngine::FlushWriteBatch(ContextHolder& holder)
    {
        rocksdb::WriteOptions options;
        options.disableWAL = m_cfg.disableWAL;
        rocksdb::Status s = m_db->Write(options, &holder.batch);
        holder.Clear();
        return s.ok() ? 0 : -1;
    }

    void RocksDBEngine::CompactRange(const Slice& begin, const Slice& end)
    {
        rocksdb::Slice s(begin.data(), begin.size());
        rocksdb::Slice e(end.data(), end.size());
        rocksdb::Slice* start = s.size() > 0 ? &s : NULL;
        rocksdb::Slice* endpos = e.size() > 0 ? &e : NULL;
        m_db->CompactRange(start, endpos);
    }

    void RocksDBEngine::ContextHolder::Put(const Slice& key, const Slice& value)
    {
        batch.Put(ROCKSDB_SLICE(key), ROCKSDB_SLICE(value));
        count++;
    }
    void RocksDBEngine::ContextHolder::Del(const Slice& key)
    {
        batch.Delete(ROCKSDB_SLICE(key));
        count++;
    }

    int RocksDBEngine::Put(const Slice& key, const Slice& value, const Options& options)
    {
        rocksdb::Status s = rocksdb::Status::OK();
        ContextHolder& holder = m_context.GetValue();
        if (!holder.EmptyRef())
        {
            holder.Put(key, value);
            if (holder.count >= (uint32) m_cfg.batch_commit_watermark)
            {
                FlushWriteBatch(holder);
            }
        }
        else
        {
            rocksdb::WriteOptions options;
            options.disableWAL = m_cfg.disableWAL;
            s = m_db->Put(options, ROCKSDB_SLICE(key), ROCKSDB_SLICE(value));
        }
        return s.ok() ? 0 : -1;
    }
    int RocksDBEngine::Get(const Slice& key, std::string* value, const Options& options)
    {
        rocksdb::ReadOptions read_options;
        read_options.fill_cache = options.read_fill_cache;
        read_options.verify_checksums = false;
        ContextHolder& holder = m_context.GetValue();
        read_options.snapshot = holder.snapshot;
        rocksdb::Status s = m_db->Get(read_options, ROCKSDB_SLICE(key), value);
        return s.ok() ? 0 : -1;
    }
    int RocksDBEngine::Del(const Slice& key, const Options& options)
    {
        rocksdb::Status s = rocksdb::Status::OK();
        ContextHolder& holder = m_context.GetValue();
        if (!holder.EmptyRef())
        {
            holder.Del(key);
            if (holder.count >= (uint32) m_cfg.batch_commit_watermark)
            {
                FlushWriteBatch(holder);
            }
        }
        else
        {
            s = m_db->Delete(rocksdb::WriteOptions(), ROCKSDB_SLICE(key));
        }
        return s.ok() ? 0 : -1;
    }

    Iterator* RocksDBEngine::Find(const Slice& findkey, const Options& options)
    {
        rocksdb::ReadOptions read_options;
        read_options.fill_cache = options.seek_fill_cache;
        ContextHolder& holder = m_context.GetValue();
        if (NULL == holder.snapshot)
        {
            holder.snapshot = m_db->GetSnapshot();
        }
        holder.snapshot_ref++;
        read_options.snapshot = holder.snapshot;
        rocksdb::Iterator* iter = m_db->NewIterator(read_options);
        iter->Seek(ROCKSDB_SLICE(findkey));
        return new RocksDBIterator(this, iter);
    }

    void RocksDBEngine::ReleaseContextSnapshot()
    {
        ContextHolder& holder = m_context.GetValue();
        if (NULL != holder.snapshot)
        {
            holder.snapshot_ref--;
            if (holder.snapshot_ref == 0)
            {
                m_db->ReleaseSnapshot(holder.snapshot);
                holder.snapshot = NULL;
            }
        }
    }

    const std::string RocksDBEngine::Stats()
    {
        std::string str, version_info;

        m_db->GetProperty("rocksdb.stats", &str);
        std::string numkeys;
        m_db->GetProperty("rocksdb.estimate-num-keys", &numkeys);
        numkeys = "estimate-num-keys: " + numkeys + "\r\n";
        version_info.append("RocksDB version:").append(stringfromll(rocksdb::kMajorVersion)).append(".").append(
                stringfromll(rocksdb::kMinorVersion)).append(".").append(stringfromll(ROCKSDB_PATCH)).append("\r\n");
        return version_info + numkeys + str;
    }

    int RocksDBEngine::MaxOpenFiles()
    {
        return m_options.max_open_files;
    }

    RocksDBIterator::~RocksDBIterator()
    {
        delete m_iter;
        m_engine->ReleaseContextSnapshot();
    }

}

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

#include "rocksdb_engine.hpp"
#include "codec.hpp"
#include "util/helpers.hpp"
#include "rocksdb/env.h"
#include "rocksdb/rate_limiter.h"
#include "rocksdb/table.h"
#include <string.h>
#include <stdarg.h>

#define ROCKSDB_SLICE(slice) rocksdb::Slice(slice.data(), slice.size())
#define ARDB_SLICE(slice) Slice(slice.data(), slice.size())

namespace ardb
{
    class RocksDBLogger: public rocksdb::Logger
    {
        private:
            void Logv(const char* format, va_list ap)
            {
                char logbuf[1024];
                int len = vsnprintf(logbuf, sizeof(logbuf), format, ap);
                if(len < sizeof(logbuf))
                {
                    INFO_LOG(logbuf);
                }
            }
    };

    int RocksDBComparator::Compare(const rocksdb::Slice& a, const rocksdb::Slice& b) const
    {
        return CommonComparator::Compare(a.data(), a.size(), b.data(), b.size());
    }

    void RocksDBComparator::FindShortestSeparator(std::string* start, const rocksdb::Slice& limit) const
    {
    }

    void RocksDBComparator::FindShortSuccessor(std::string* key) const
    {
    }

    RocksDBEngineFactory::RocksDBEngineFactory(const Properties& props)
    {
        ParseConfig(props, m_cfg);
    }

    void RocksDBEngineFactory::ParseConfig(const Properties& props, RocksDBConfig& cfg)
    {
        cfg.path = ".";
        conf_get_string(props, "data-dir", cfg.path);
        conf_get_int64(props, "rocksdb.block_cache_size", cfg.block_cache_size);
        conf_get_int64(props, "rocksdb.block_cache_compressed", cfg.block_cache_compressed_size);
        conf_get_int64(props, "rocksdb.write_buffer_size", cfg.write_buffer_size);
        conf_get_int64(props, "rocksdb.max_open_files", cfg.max_open_files);
        conf_get_int64(props, "rocksdb.block_size", cfg.block_size);
        conf_get_int64(props, "rocksdb.block_restart_interval", cfg.block_restart_interval);
        conf_get_int64(props, "rocksdb.bloom_bits", cfg.bloom_bits);
        conf_get_int64(props, "rocksdb.batch_commit_watermark", cfg.batch_commit_watermark);
        conf_get_string(props, "rocksdb.compression", cfg.compression);
        conf_get_bool(props, "rocksdb.logenable", cfg.logenable);
        conf_get_bool(props, "rocksdb.skip_log_error_on_recovery", cfg.skip_log_error_on_recovery);
        conf_get_int64(props, "rocksdb.flush_compact_rate_bytes_per_sec", cfg.flush_compact_rate_bytes_per_sec);
        conf_get_double(props, "rocksdb.hard_rate_limit", cfg.hard_rate_limit);
        conf_get_bool(props, "rocksdb.disableWAL", cfg.disableWAL);
        conf_get_int64(props, "rocksdb.max_manifest_file_size", cfg.max_manifest_file_size);
        conf_get_string(props, "rocksdb.compacton_style", cfg.compacton_style);
    }

    KeyValueEngine* RocksDBEngineFactory::CreateDB(const std::string& name)
    {
        RocksDBEngine* engine = new RocksDBEngine();
        RocksDBConfig cfg = m_cfg;
        char tmp[cfg.path.size() + name.size() + 10];
        sprintf(tmp, "%s/%s", cfg.path.c_str(), name.c_str());
        cfg.path = tmp;
        if (engine->Init(cfg) != 0)
        {
            DELETE(engine);
            ERROR_LOG("Failed to create DB:%s", name.c_str());
            return NULL;
        }
        return engine;
    }
    void RocksDBEngineFactory::DestroyDB(KeyValueEngine* engine)
    {
        RocksDBEngine* RocksDB = (RocksDBEngine*) engine;
        std::string path = RocksDB->m_db_path;
        DELETE(engine);
        rocksdb::Options options;
        rocksdb::DestroyDB(path, options);
    }

    void RocksDBEngineFactory::CloseDB(KeyValueEngine* engine)
    {
        DELETE(engine);
    }
    void RocksDBIterator::SeekToFirst()
    {
        m_iter->SeekToFirst();
    }
    void RocksDBIterator::SeekToLast()
    {
        m_iter->SeekToLast();
    }
    void RocksDBIterator::Seek(const Slice& target)
    {
        m_iter->Seek(ROCKSDB_SLICE(target));
    }
    void RocksDBIterator::Next()
    {
        m_iter->Next();
    }
    void RocksDBIterator::Prev()
    {
        m_iter->Prev();
    }
    Slice RocksDBIterator::Key() const
    {
        return ARDB_SLICE(m_iter->key());
    }
    Slice RocksDBIterator::Value() const
    {
        return ARDB_SLICE(m_iter->value());
    }
    bool RocksDBIterator::Valid()
    {
        return m_iter->Valid();
    }

    RocksDBEngine::RocksDBEngine() :
            m_db(NULL)
    {

    }
    RocksDBEngine::~RocksDBEngine()
    {
        DELETE(m_db);
    }
    int RocksDBEngine::Init(const RocksDBConfig& cfg)
    {
        m_cfg = cfg;
        m_options.create_if_missing = true;
        m_options.comparator = &m_comparator;
        rocksdb::BlockBasedTableOptions block_options;
        if (cfg.block_cache_size > 0)
        {
            block_options.block_cache = rocksdb::NewLRUCache(cfg.block_cache_size);
            //m_options.block_cache_compressed = rocksdb::NewLRUCache(cfg.block_cache_compressed_size);
        }else if(cfg.block_cache_size < 0)
        {
            block_options.no_block_cache = true;
        }
        if (cfg.block_size > 0)
        {
            block_options.block_size = cfg.block_size;
        }
        if (cfg.block_restart_interval > 0)
        {
            block_options.block_restart_interval = cfg.block_restart_interval;
        }
        if (cfg.bloom_bits > 0)
        {
            block_options.filter_policy.reset(rocksdb::NewBloomFilterPolicy(cfg.bloom_bits));
        }
        m_options.table_factory.reset(rocksdb::NewBlockBasedTableFactory(block_options));

        if (cfg.write_buffer_size > 0)
        {
            m_options.write_buffer_size = cfg.write_buffer_size;
        }
        m_options.max_open_files = cfg.max_open_files;

        if (!strcasecmp(cfg.compression.c_str(), "none"))
        {
            m_options.compression = rocksdb::kNoCompression;
        }
        else
        {
            m_options.compression = rocksdb::kSnappyCompression;
        }
        if(cfg.flush_compact_rate_bytes_per_sec > 0)
        {
            m_options.rate_limiter.reset(rocksdb::NewGenericRateLimiter(cfg.flush_compact_rate_bytes_per_sec));
        }
        m_options.hard_rate_limit = cfg.hard_rate_limit;
        if(m_cfg.max_manifest_file_size > 0)
        {
            m_options.max_manifest_file_size = m_cfg.max_manifest_file_size;
        }
        if(!strcasecmp(m_cfg.compacton_style.c_str(), "universal"))
        {
            m_options.OptimizeUniversalStyleCompaction();
        }else
        {
            m_options.OptimizeLevelStyleCompaction();
        }
        m_options.IncreaseParallelism();

        if(cfg.logenable)
        {
            m_options.info_log.reset(new RocksDBLogger);
        }
        make_dir(cfg.path);
        m_db_path = cfg.path;
        rocksdb::Status status = rocksdb::DB::Open(m_options, cfg.path.c_str(), &m_db);
        do
        {
            if (status.ok())
            {
                break;
            }
            else if (status.IsCorruption())
            {
                ERROR_LOG("Failed to init engine:%s", status.ToString().c_str());
                status = rocksdb::RepairDB(cfg.path.c_str(), m_options);
                if (!status.ok())
                {
                    ERROR_LOG("Failed to repair:%s for %s", cfg.path.c_str(), status.ToString().c_str());
                    return -1;
                }
                status = rocksdb::DB::Open(m_options, cfg.path.c_str(), &m_db);
            }
            else
            {
                ERROR_LOG("Failed to init engine:%s", status.ToString().c_str());
                break;
            }
        } while (1);
        return status.ok() ? 0 : -1;
    }

    int RocksDBEngine::BeginBatchWrite()
    {
        m_context.GetValue().AddRef();
        return 0;
    }
    int RocksDBEngine::CommitBatchWrite()
    {
        ContextHolder& holder = m_context.GetValue();
        holder.ReleaseRef();
        if (holder.EmptyRef())
        {
            return FlushWriteBatch(holder);
        }
        return 0;
    }
    int RocksDBEngine::DiscardBatchWrite()
    {
        ContextHolder& holder = m_context.GetValue();
        holder.ReleaseRef();
        holder.Clear();
        return 0;
    }

    int RocksDBEngine::FlushWriteBatch(ContextHolder& holder)
    {
        rocksdb::WriteOptions options;
        options.disableWAL = m_cfg.disableWAL;
        rocksdb::Status s = m_db->Write(options, &holder.batch);
        holder.Clear();
        return s.ok() ? 0 : -1;
    }

    void RocksDBEngine::CompactRange(const Slice& begin, const Slice& end)
    {
        rocksdb::Slice s(begin.data(), begin.size());
        rocksdb::Slice e(end.data(), end.size());
        rocksdb::Slice* start = s.size() > 0 ? &s : NULL;
        rocksdb::Slice* endpos = e.size() > 0 ? &e : NULL;
        m_db->CompactRange(start, endpos);
    }

    void RocksDBEngine::ContextHolder::Put(const Slice& key, const Slice& value)
    {
        batch.Put(ROCKSDB_SLICE(key), ROCKSDB_SLICE(value));
        count++;
    }
    void RocksDBEngine::ContextHolder::Del(const Slice& key)
    {
        batch.Delete(ROCKSDB_SLICE(key));
        count++;
    }

    int RocksDBEngine::Put(const Slice& key, const Slice& value, const Options& options)
    {
        rocksdb::Status s = rocksdb::Status::OK();
        ContextHolder& holder = m_context.GetValue();
        if (!holder.EmptyRef())
        {
            holder.Put(key, value);
            if (holder.count >= (uint32) m_cfg.batch_commit_watermark)
            {
                FlushWriteBatch(holder);
            }
        }
        else
        {
            rocksdb::WriteOptions options;
            options.disableWAL = m_cfg.disableWAL;
            s = m_db->Put(options, ROCKSDB_SLICE(key), ROCKSDB_SLICE(value));
        }
        return s.ok() ? 0 : -1;
    }
    int RocksDBEngine::Get(const Slice& key, std::string* value, const Options& options)
    {
        rocksdb::ReadOptions read_options;
        read_options.fill_cache = options.read_fill_cache;
        read_options.verify_checksums = false;
        ContextHolder& holder = m_context.GetValue();
        read_options.snapshot = holder.snapshot;
        rocksdb::Status s = m_db->Get(read_options, ROCKSDB_SLICE(key), value);
        return s.ok() ? 0 : -1;
    }
    int RocksDBEngine::Del(const Slice& key, const Options& options)
    {
        rocksdb::Status s = rocksdb::Status::OK();
        ContextHolder& holder = m_context.GetValue();
        if (!holder.EmptyRef())
        {
            holder.Del(key);
            if (holder.count >= (uint32) m_cfg.batch_commit_watermark)
            {
                FlushWriteBatch(holder);
            }
        }
        else
        {
            s = m_db->Delete(rocksdb::WriteOptions(), ROCKSDB_SLICE(key));
        }
        return s.ok() ? 0 : -1;
    }

    Iterator* RocksDBEngine::Find(const Slice& findkey, const Options& options)
    {
        rocksdb::ReadOptions read_options;
        read_options.fill_cache = options.seek_fill_cache;
        ContextHolder& holder = m_context.GetValue();
        if (NULL == holder.snapshot)
        {
            holder.snapshot = m_db->GetSnapshot();
        }
        holder.snapshot_ref++;
        read_options.snapshot = holder.snapshot;
        rocksdb::Iterator* iter = m_db->NewIterator(read_options);
        iter->Seek(ROCKSDB_SLICE(findkey));
        return new RocksDBIterator(this, iter);
    }

    void RocksDBEngine::ReleaseContextSnapshot()
    {
        ContextHolder& holder = m_context.GetValue();
        if (NULL != holder.snapshot)
        {
            holder.snapshot_ref--;
            if (holder.snapshot_ref == 0)
            {
                m_db->ReleaseSnapshot(holder.snapshot);
                holder.snapshot = NULL;
            }
        }
    }

    const std::string RocksDBEngine::Stats()
    {
        std::string str, version_info;

        m_db->GetProperty("rocksdb.stats", &str);
        std::string numkeys;
        m_db->GetProperty("rocksdb.estimate-num-keys", &numkeys);
        numkeys = "estimate-num-keys: " + numkeys + "\r\n";
        version_info.append("RocksDB version:").append(stringfromll(rocksdb::kMajorVersion)).append(".").append(
                stringfromll(rocksdb::kMinorVersion)).append(".").append(stringfromll(ROCKSDB_PATCH)).append("\r\n");
        return version_info + numkeys + str;
    }

    int RocksDBEngine::MaxOpenFiles()
    {
        return m_options.max_open_files;
    }

    RocksDBIterator::~RocksDBIterator()
    {
        delete m_iter;
        m_engine->ReleaseContextSnapshot();
    }

}

<|endoftext|>


<commit_before>// RUN: cat %s | %cling | FileCheck %s

// This test makes sure the interpreter doesn't create many useless empty
// transactions.

// Author: Vassil Vassilev

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Transaction.h"

#include "clang/AST/Decl.h"

#include <stdio.h>

.rawInput 1

using namespace cling;

void generateNestedTransaction(int depth) {
  if (!depth)
    return;
  cling::Interpreter::PushTransactionRAII RAIIT(gCling);
  if (depth | 0x1) { // if odd
    char buff[100];
    sprintf(buff, "int i%d;", depth);
    gCling->process(buff);
  } // this will cause every even transaction to be reused.
  generateNestedTransaction(--depth);
}

.rawInput 0

generateNestedTransaction(5);
const cling::Transaction* T = gCling->getFirstTransaction();
while(T) {
  if (!T->size())
    printf("Empty transaction detected!\n");
  if (T->getWrapperFD()->getKind() != clang::Decl::Function)
    printf("Unexpected wrapper kind!\n");
  if (T->getState() != Transaction::kCommitted)
    printf("Unexpected transaction state!\n");
  //T->printStructure();
  T = T->getNext();
}
printf("Just make FileCheck(CHECK-NOT) happy.\n")
//CHECK-NOT:Empty transaction detected!
//CHECK-NOT:Unexpected wrapper kind!
//CHECK-NOT:Unexpected transaction state!
.q
<commit_msg>Some transactions don't have a wrapper.<commit_after>// RUN: cat %s | %cling | FileCheck %s

// This test makes sure the interpreter doesn't create many useless empty
// transactions.

// Author: Vassil Vassilev

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Transaction.h"

#include "clang/AST/Decl.h"

#include <stdio.h>

.rawInput 1

using namespace cling;

void generateNestedTransaction(int depth) {
  if (!depth)
    return;
  cling::Interpreter::PushTransactionRAII RAIIT(gCling);
  if (depth | 0x1) { // if odd
    char buff[100];
    sprintf(buff, "int i%d;", depth);
    gCling->process(buff);
  } // this will cause every even transaction to be reused.
  generateNestedTransaction(--depth);
}

.rawInput 0

generateNestedTransaction(5);
const cling::Transaction* T = gCling->getFirstTransaction();
while(T) {
  if (!T->size())
    printf("Empty transaction detected!\n");
  else if (T->getWrapperFD() && T->getWrapperFD()->getKind() != clang::Decl::Function)
    printf("Unexpected wrapper kind!\n");
  if (T->getState() != Transaction::kCommitted)
    printf("Unexpected transaction state!\n");
  //T->printStructure();
  T = T->getNext();
}
printf("Just make FileCheck(CHECK-NOT) happy.\n")
//CHECK-NOT:Empty transaction detected!
//CHECK-NOT:Unexpected wrapper kind!
//CHECK-NOT:Unexpected transaction state!
.q
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016 zScale Technology GmbH <legal@zscale.io>
 * Authors:
 *   - Paul Asmuth <paul@zscale.io>
 *   - Laura Schlimmer <laura@zscale.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * 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 license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <eventql/cli/cli_config.h>
#include <eventql/util/inspect.h>
#include <eventql/util/io/fileutil.h>
#include <inih/ini.h>

namespace eventql {
namespace cli {

struct IniParserState {
  IniParserState(CLIConfig* _cfg) : cfg(_cfg), status(Status::success()) {}
  CLIConfig* cfg;
  Status status;
};

static int ini_parse_handler(
    void* user,
    const char* section,
    const char* name,
    const char* value) {
  auto parser_state = (IniParserState*) user;
  auto status = parser_state->cfg->setConfigOption(section, name, value);
  if (status.isSuccess()) {
    return 1;
  } else {
    parser_state->status = status;
    return 0;
  }
}

CLIConfig::CLIConfig() {}

Status CLIConfig::loadDefaultConfigFile() {
  char* homedir = getenv("HOME");
  if (!homedir) {
    return Status::success();
  }

  String confg_file_path = FileUtil::joinPaths(homedir, ".evqlrc");
  if (!FileUtil::exists(confg_file_path)) {
    return Status::success();
  }

  return loadConfigFile(confg_file_path);
}

Status CLIConfig::loadConfigFile(const String& config_file) {
  IniParserState parser_state(this);
  if (ini_parse(config_file.c_str(), &ini_parse_handler, &parser_state) < 0) {
    parser_state.status = Status(eParseError, "invalid config file");
  }

  return parser_state.status;
}

Status CLIConfig::setConfigOption(
    const String& section,
    const String& key,
    const String& value) {
  if (section == "evql") {
    if (key == "host") {
      return setHost(value);
    }
    if (key == "port") {
      return setPort(stoi(value));
    }
    if (key == "auth_token") {
      return setAuthToken(value);
    }
    if (key == "batch_mode") {
      return setBatchMode(value);
    }
  }
  return Status(eParseError);
}

Status CLIConfig::setHost(const String& host /* = "localhost" */) {
  //FIXME check host format
  server_host_ = host;
  return Status::success();
}

Status CLIConfig::setPort(const int port /* = 80 */) {
  //FIXME check port format
  server_port_ = port;
  return Status::success();
}

Status CLIConfig::setAuthToken(const String& auth_token) {
  //FIXME check auth format
  server_auth_token_ = auth_token;
  return Status::success();
}

Status CLIConfig::setBatchMode(const String& batch_mode) {
  if (batch_mode == "false") {
    batch_mode_ = false;
    return Status::success();
  } else if (batch_mode == "true") {
    batch_mode_ = true;
    return Status::success();
  } else {
    return Status(eParseError);
  }
}

Option<String> CLIConfig::getHost() const {
  if (server_host_.size() > 0) {
    return Some<String>(server_host_);
  } else {
    return None<String>();
  }
}

Option<int> CLIConfig::getPort() const {
  if (server_port_) {
    return Some<int>(server_port_);
  } else {
    return None<int>();
  }
}

Option<String> CLIConfig::getAuthToken() const {
  if (server_auth_token_.size() > 0) {
    return Some<String>(server_auth_token_);
  } else {
    return None<String>();
  }
}

Option<String> CLIConfig::getFile() const {
  return file_;
}

Option<String> CLIConfig::getExec() const {
  return exec_;
}

Option<bool> CLIConfig::getBatchMode() const {
  return batch_mode_;
}

} // namespace cli
} // namespace eventql

<commit_msg>validate port number<commit_after>/**
 * Copyright (c) 2016 zScale Technology GmbH <legal@zscale.io>
 * Authors:
 *   - Paul Asmuth <paul@zscale.io>
 *   - Laura Schlimmer <laura@zscale.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * 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 license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include <eventql/cli/cli_config.h>
#include <eventql/util/inspect.h>
#include <eventql/util/io/fileutil.h>
#include <inih/ini.h>

namespace eventql {
namespace cli {

struct IniParserState {
  IniParserState(CLIConfig* _cfg) : cfg(_cfg), status(Status::success()) {}
  CLIConfig* cfg;
  Status status;
};

static int ini_parse_handler(
    void* user,
    const char* section,
    const char* name,
    const char* value) {
  auto parser_state = (IniParserState*) user;
  auto status = parser_state->cfg->setConfigOption(section, name, value);
  if (status.isSuccess()) {
    return 1;
  } else {
    parser_state->status = status;
    return 0;
  }
}

CLIConfig::CLIConfig() {}

Status CLIConfig::loadDefaultConfigFile() {
  char* homedir = getenv("HOME");
  if (!homedir) {
    return Status::success();
  }

  String confg_file_path = FileUtil::joinPaths(homedir, ".evqlrc");
  if (!FileUtil::exists(confg_file_path)) {
    return Status::success();
  }

  return loadConfigFile(confg_file_path);
}

Status CLIConfig::loadConfigFile(const String& config_file) {
  IniParserState parser_state(this);
  if (ini_parse(config_file.c_str(), &ini_parse_handler, &parser_state) < 0) {
    parser_state.status = Status(eParseError, "invalid config file");
  }

  return parser_state.status;
}

Status CLIConfig::setConfigOption(
    const String& section,
    const String& key,
    const String& value) {
  if (section == "evql") {
    if (key == "host") {
      return setHost(value);
    }
    if (key == "port") {
      return setPort(stoi(value));
    }
    if (key == "auth_token") {
      return setAuthToken(value);
    }
    if (key == "batch_mode") {
      return setBatchMode(value);
    }
  }
  return Status(eParseError);
}

Status CLIConfig::setHost(const String& host /* = "localhost" */) {
  server_host_ = host; //FIXME check host format
  return Status::success();
}

Status CLIConfig::setPort(const int port /* = 80 */) {
  if (port < 0 || port > 65535) {
    return Status(eFlagError, StringUtil::format("invalid port: $0", port));
  }

  server_port_ = port;
  return Status::success();
}

Status CLIConfig::setAuthToken(const String& auth_token) {
  server_auth_token_ = auth_tokken;
  return Status::success();
}

Status CLIConfig::setBatchMode(const String& batch_mode) {
  if (batch_mode == "false") {
    batch_mode_ = false;
    return Status::success();
  } else if (batch_mode == "true") {
    batch_mode_ = true;
    return Status::success();
  } else {
    return Status(eParseError);
  }
}

Option<String> CLIConfig::getHost() const {
  if (server_host_.size() > 0) {
    return Some<String>(server_host_);
  } else {
    return None<String>();
  }
}

Option<int> CLIConfig::getPort() const {
  if (server_port_) {
    return Some<int>(server_port_);
  } else {
    return None<int>();
  }
}

Option<String> CLIConfig::getAuthToken() const {
  if (server_auth_token_.size() > 0) {
    return Some<String>(server_auth_token_);
  } else {
    return None<String>();
  }
}

Option<String> CLIConfig::getFile() const {
  return file_;
}

Option<String> CLIConfig::getExec() const {
  return exec_;
}

Option<bool> CLIConfig::getBatchMode() const {
  return batch_mode_;
}

} // namespace cli
} // namespace eventql

<|endoftext|>