<commit_before>'use strict';

const { Pool, TimeoutError } = require('sequelize-pool');
const _ = require('lodash');
const semver = require('semver');
const Promise = require('../../promise');
const errors = require('../../errors');
const { logger } = require('../../utils/logger');
const debug = logger.debugContext('pool');

/**
 * Abstract Connection Manager
 *
 * Connection manager which handles pooling & replication.
 * Uses sequelize-pool for pooling
 *
 * @private
 */
class ConnectionManager {
  constructor(dialect, sequelize) {
    const config = _.cloneDeep(sequelize.config);

    this.sequelize = sequelize;
    this.config = config;
    this.dialect = dialect;
    this.versionPromise = null;
    this.dialectName = this.sequelize.options.dialect;

    if (config.pool === false) {
      throw new Error('Support for pool:false was removed in v4.0');
    }

    config.pool = _.defaults(config.pool || {}, {
      max: 5,
      min: 0,
      idle: 10000,
      acquire: 60000,
      evict: 1000,
      validate: this._validate.bind(this)
    });

    this.initPools();
  }

  refreshTypeParser(dataTypes) {
    _.each(dataTypes, dataType => {
      if (Object.prototype.hasOwnProperty.call(dataType, 'parse')) {
        if (dataType.types[this.dialectName]) {
          this._refreshTypeParser(dataType);
        } else {
          throw new Error(`Parse function not supported for type ${dataType.key} in dialect ${this.dialectName}`);
        }
      }
    });
  }

  /**
   * Try to load dialect module from various configured options.
   * Priority goes like dialectModulePath > dialectModule > require(default)
   *
   * @param {string} moduleName Name of dialect module to lookup
   *
   * @private
   * @returns {object}
   */
  _loadDialectModule(moduleName) {
    try {
      if (this.sequelize.config.dialectModulePath) {
        return require(this.sequelize.config.dialectModulePath);
      }
      if (this.sequelize.config.dialectModule) {
        return this.sequelize.config.dialectModule;
      }
      return require(moduleName);

    } catch (err) {
      if (err.code === 'MODULE_NOT_FOUND') {
        if (this.sequelize.config.dialectModulePath) {
          throw new Error(`Unable to find dialect at ${this.sequelize.config.dialectModulePath}`);
        }
        throw new Error(`Please install ${moduleName} package manually`);
      }

      throw err;
    }
  }

  /**
   * Handler which executes on process exit or connection manager shutdown
   *
   * @private
   * @returns {Promise}
   */
  _onProcessExit() {
    if (!this.pool) {
      return Promise.resolve();
    }

    return this.pool.drain().then(() => {
      debug('connection drain due to process exit');
      return this.pool.destroyAllNow();
    });
  }

  /**
   * Drain the pool and close it permanently
   *
   * @returns {Promise}
   */
  close() {
    // Mark close of pool
    this.getConnection = function getConnection() {
      return Promise.reject(new Error('ConnectionManager.getConnection was called after the connection manager was closed!'));
    };

    return this._onProcessExit();
  }

  /**
   * Initialize connection pool. By default pool autostart is set to false, so no connection will be
   * be created unless `pool.acquire` is called.
   */
  initPools() {
    const config = this.config;

    if (!config.replication) {
      this.pool = new Pool({
        name: 'sequelize',
        create: () => this._connect(config),
        destroy: connection => {
          return this._disconnect(connection)
            .then(result => {
              debug('connection destroy');return result;
            });
        },
        validate: config.pool.validate,
        max: config.pool.max,
        min: config.pool.min,
        acquireTimeoutMillis: config.pool.acquire,
        idleTimeoutMillis: config.pool.idle,
        reapIntervalMillis: config.pool.evict,
        maxUses: config.pool.maxUses
      });

      debug(`pool created with max/min: ${config.pool.max}/${config.pool.min}, no replication`);

      return;
    }

    if (!Array.isArray(config.replication.read)) {
      config.replication.read = [config.replication.read];
    }

    // Map main connection config
    config.replication.write = _.defaults(config.replication.write, _.omit(config, 'replication'));

    // Apply defaults to each read config
    config.replication.read = config.replication.read.map(readConfig =>
      _.defaults(readConfig, _.omit(this.config, 'replication'))
    );

    // custom pooling for replication (original author @janmeier)
    let reads = 0;
    this.pool = {
      release: client => {
        if (client.queryType === 'read') {
          this.pool.read.release(client);
        } else {
          this.pool.write.release(client);
        }
      },
      acquire: (queryType, useMaster) => {
        useMaster = useMaster === undefined ? false : useMaster;
        if (queryType === 'SELECT' && !useMaster) {
          return this.pool.read.acquire();
        }
        return this.pool.write.acquire();
      },
      destroy: connection => {
        this.pool[connection.queryType].destroy(connection);
        debug('connection destroy');
      },
      destroyAllNow: () => {
        return Promise.all([
          this.pool.read.destroyAllNow(),
          this.pool.write.destroyAllNow()
        ]).then(() => { debug('all connections destroyed'); });
      },
      drain: () => {
        return Promise.all([
          this.pool.write.drain(),
          this.pool.read.drain()
        ]);
      },
      read: new Pool({
        name: 'sequelize:read',
        create: () => {
          // round robin config
          const nextRead = reads++ % config.replication.read.length;
          return this._connect(config.replication.read[nextRead]).then(connection => {
            connection.queryType = 'read';
            return connection;
          });
        },
        destroy: connection => this._disconnect(connection),
        validate: config.pool.validate,
        max: config.pool.max,
        min: config.pool.min,
        acquireTimeoutMillis: config.pool.acquire,
        idleTimeoutMillis: config.pool.idle,
        reapIntervalMillis: config.pool.evict,
        maxUses: config.pool.maxUses
      }),
      write: new Pool({
        name: 'sequelize:write',
        create: () => {
          return this._connect(config.replication.write).then(connection => {
            connection.queryType = 'write';
            return connection;
          });
        },
        destroy: connection => this._disconnect(connection),
        validate: config.pool.validate,
        max: config.pool.max,
        min: config.pool.min,
        acquireTimeoutMillis: config.pool.acquire,
        idleTimeoutMillis: config.pool.idle,
        reapIntervalMillis: config.pool.evict,
        maxUses: config.pool.maxUses
      })
    };

    debug(`pool created with max/min: ${config.pool.max}/${config.pool.min}, with replication`);
  }

  /**
   * Get connection from pool. It sets database version if it's not already set.
   * Call pool.acquire to get a connection
   *
   * @param {object}   [options]                 Pool options
   * @param {string}   [options.type]            Set which replica to use. Available options are `read` and `write`
   * @param {boolean}  [options.useMaster=false] Force master or write replica to get connection from
   *
   * @returns {Promise<Connection>}
   */
  getConnection(options) {
    options = options || {};

    let promise;
    if (this.sequelize.options.databaseVersion === 0) {
      if (this.versionPromise) {
        promise = this.versionPromise;
      } else {
        promise = this.versionPromise = this._connect(this.config.replication.write || this.config)
          .then(connection => {
            const _options = {};

            _options.transaction = { connection }; // Cheat .query to use our private connection
            _options.logging = () => {};
            _options.logging.__testLoggingFn = true;

            //connection might have set databaseVersion value at initialization,
            //avoiding a useless round trip
            if (this.sequelize.options.databaseVersion === 0) {
              return this.sequelize.databaseVersion(_options).then(version => {
                const parsedVersion = _.get(semver.coerce(version), 'version') || version;
                this.sequelize.options.databaseVersion = semver.valid(parsedVersion)
                  ? parsedVersion
                  : this.defaultVersion;
                this.versionPromise = null;
                return this._disconnect(connection);
              });
            }

            this.versionPromise = null;
            return this._disconnect(connection);
          }).catch(err => {
            this.versionPromise = null;
            throw err;
          });
      }
    } else {
      promise = Promise.resolve();
    }

    return promise.then(() => {
      return this.pool.acquire(options.type, options.useMaster)
        .catch(error => {
          if (error instanceof TimeoutError) throw new errors.ConnectionAcquireTimeoutError(error);
          throw error;
        });
    }).then(result => {
      debug('connection acquired');return result;
    });
  }

  /**
   * Release a pooled connection so it can be utilized by other connection requests
   *
   * @param {Connection} connection
   *
   * @returns {Promise}
   */
  releaseConnection(connection) {
    return Promise.resolve().then(() => {
      this.pool.release(connection);
      debug('connection released');
    });
  }

  /**
   * Call dialect library to get connection
   *
   * @param {*} config Connection config
   * @private
   * @returns {Promise<Connection>}
   */
  _connect(config) {
    return this.sequelize.runHooks('beforeConnect', config)
      .then(() => this.dialect.connectionManager.connect(config))
      .then(connection => this.sequelize.runHooks('afterConnect', connection, config).then(() => connection));
  }

  /**
   * Call dialect library to disconnect a connection
   *
   * @param {Connection} connection
   * @private
   * @returns {Promise}
   */
  _disconnect(connection) {
    return this.sequelize.runHooks('beforeDisconnect', connection)
      .then(() => this.dialect.connectionManager.disconnect(connection))
      .then(() => this.sequelize.runHooks('afterDisconnect', connection));
  }

  /**
   * Determine if a connection is still valid or not
   *
   * @param {Connection} connection
   *
   * @returns {boolean}
   */
  _validate(connection) {
    if (!this.dialect.connectionManager.validate) {
      return true;
    }

    return this.dialect.connectionManager.validate(connection);
  }
}

module.exports = ConnectionManager;
module.exports.ConnectionManager = ConnectionManager;
module.exports.default = ConnectionManager;
<commit_msg>refactor(dialects/abstract): asyncify methods (#12128)<commit_after>'use strict';

const { Pool, TimeoutError } = require('sequelize-pool');
const _ = require('lodash');
const semver = require('semver');
const Promise = require('../../promise');
const errors = require('../../errors');
const { logger } = require('../../utils/logger');
const debug = logger.debugContext('pool');

/**
 * Abstract Connection Manager
 *
 * Connection manager which handles pooling & replication.
 * Uses sequelize-pool for pooling
 *
 * @private
 */
class ConnectionManager {
  constructor(dialect, sequelize) {
    const config = _.cloneDeep(sequelize.config);

    this.sequelize = sequelize;
    this.config = config;
    this.dialect = dialect;
    this.versionPromise = null;
    this.dialectName = this.sequelize.options.dialect;

    if (config.pool === false) {
      throw new Error('Support for pool:false was removed in v4.0');
    }

    config.pool = _.defaults(config.pool || {}, {
      max: 5,
      min: 0,
      idle: 10000,
      acquire: 60000,
      evict: 1000,
      validate: this._validate.bind(this)
    });

    this.initPools();
  }

  refreshTypeParser(dataTypes) {
    _.each(dataTypes, dataType => {
      if (Object.prototype.hasOwnProperty.call(dataType, 'parse')) {
        if (dataType.types[this.dialectName]) {
          this._refreshTypeParser(dataType);
        } else {
          throw new Error(`Parse function not supported for type ${dataType.key} in dialect ${this.dialectName}`);
        }
      }
    });
  }

  /**
   * Try to load dialect module from various configured options.
   * Priority goes like dialectModulePath > dialectModule > require(default)
   *
   * @param {string} moduleName Name of dialect module to lookup
   *
   * @private
   * @returns {object}
   */
  _loadDialectModule(moduleName) {
    try {
      if (this.sequelize.config.dialectModulePath) {
        return require(this.sequelize.config.dialectModulePath);
      }
      if (this.sequelize.config.dialectModule) {
        return this.sequelize.config.dialectModule;
      }
      return require(moduleName);

    } catch (err) {
      if (err.code === 'MODULE_NOT_FOUND') {
        if (this.sequelize.config.dialectModulePath) {
          throw new Error(`Unable to find dialect at ${this.sequelize.config.dialectModulePath}`);
        }
        throw new Error(`Please install ${moduleName} package manually`);
      }

      throw err;
    }
  }

  /**
   * Handler which executes on process exit or connection manager shutdown
   *
   * @private
   * @returns {Promise}
   */
  async _onProcessExit() {
    if (!this.pool) {
      return;
    }

    await this.pool.drain();
    debug('connection drain due to process exit');

    return await this.pool.destroyAllNow();
  }

  /**
   * Drain the pool and close it permanently
   *
   * @returns {Promise}
   */
  async close() {
    // Mark close of pool
    this.getConnection = async function getConnection() {
      throw new Error('ConnectionManager.getConnection was called after the connection manager was closed!');
    };

    return await this._onProcessExit();
  }

  /**
   * Initialize connection pool. By default pool autostart is set to false, so no connection will be
   * be created unless `pool.acquire` is called.
   */
  initPools() {
    const config = this.config;

    if (!config.replication) {
      this.pool = new Pool({
        name: 'sequelize',
        create: () => this._connect(config),
        destroy: async connection => {
          const result = await this._disconnect(connection);
          debug('connection destroy');
          return result;
        },
        validate: config.pool.validate,
        max: config.pool.max,
        min: config.pool.min,
        acquireTimeoutMillis: config.pool.acquire,
        idleTimeoutMillis: config.pool.idle,
        reapIntervalMillis: config.pool.evict,
        maxUses: config.pool.maxUses
      });

      debug(`pool created with max/min: ${config.pool.max}/${config.pool.min}, no replication`);

      return;
    }

    if (!Array.isArray(config.replication.read)) {
      config.replication.read = [config.replication.read];
    }

    // Map main connection config
    config.replication.write = _.defaults(config.replication.write, _.omit(config, 'replication'));

    // Apply defaults to each read config
    config.replication.read = config.replication.read.map(readConfig =>
      _.defaults(readConfig, _.omit(this.config, 'replication'))
    );

    // custom pooling for replication (original author @janmeier)
    let reads = 0;
    this.pool = {
      release: client => {
        if (client.queryType === 'read') {
          this.pool.read.release(client);
        } else {
          this.pool.write.release(client);
        }
      },
      acquire: (queryType, useMaster) => {
        useMaster = useMaster === undefined ? false : useMaster;
        if (queryType === 'SELECT' && !useMaster) {
          return this.pool.read.acquire();
        }
        return this.pool.write.acquire();
      },
      destroy: connection => {
        this.pool[connection.queryType].destroy(connection);
        debug('connection destroy');
      },
      destroyAllNow: async () => {
        await Promise.all([
          this.pool.read.destroyAllNow(),
          this.pool.write.destroyAllNow()
        ]);

        debug('all connections destroyed');
      },
      drain: async () => Promise.all([
        this.pool.write.drain(),
        this.pool.read.drain()
      ]),
      read: new Pool({
        name: 'sequelize:read',
        create: async () => {
          // round robin config
          const nextRead = reads++ % config.replication.read.length;
          const connection = await this._connect(config.replication.read[nextRead]);
          connection.queryType = 'read';
          return connection;
        },
        destroy: connection => this._disconnect(connection),
        validate: config.pool.validate,
        max: config.pool.max,
        min: config.pool.min,
        acquireTimeoutMillis: config.pool.acquire,
        idleTimeoutMillis: config.pool.idle,
        reapIntervalMillis: config.pool.evict,
        maxUses: config.pool.maxUses
      }),
      write: new Pool({
        name: 'sequelize:write',
        create: async () => {
          const connection = await this._connect(config.replication.write);
          connection.queryType = 'write';
          return connection;
        },
        destroy: connection => this._disconnect(connection),
        validate: config.pool.validate,
        max: config.pool.max,
        min: config.pool.min,
        acquireTimeoutMillis: config.pool.acquire,
        idleTimeoutMillis: config.pool.idle,
        reapIntervalMillis: config.pool.evict,
        maxUses: config.pool.maxUses
      })
    };

    debug(`pool created with max/min: ${config.pool.max}/${config.pool.min}, with replication`);
  }

  /**
   * Get connection from pool. It sets database version if it's not already set.
   * Call pool.acquire to get a connection
   *
   * @param {object}   [options]                 Pool options
   * @param {string}   [options.type]            Set which replica to use. Available options are `read` and `write`
   * @param {boolean}  [options.useMaster=false] Force master or write replica to get connection from
   *
   * @returns {Promise<Connection>}
   */
  async getConnection(options) {
    options = options || {};

    if (this.sequelize.options.databaseVersion === 0) {
      if (!this.versionPromise) {
        this.versionPromise = (async () => {
          try {
            const connection = await this._connect(this.config.replication.write || this.config);
            const _options = {};

            _options.transaction = { connection }; // Cheat .query to use our private connection
            _options.logging = () => {};
            _options.logging.__testLoggingFn = true;

            //connection might have set databaseVersion value at initialization,
            //avoiding a useless round trip
            if (this.sequelize.options.databaseVersion === 0) {
              const version = await this.sequelize.databaseVersion(_options);
              const parsedVersion = _.get(semver.coerce(version), 'version') || version;
              this.sequelize.options.databaseVersion = semver.valid(parsedVersion)
                ? parsedVersion
                : this.defaultVersion;
            }

            this.versionPromise = null;
            return await this._disconnect(connection);
          } catch (err) {
            this.versionPromise = null;
            throw err;
          }
        })();
      }
      await this.versionPromise;
    }

    let result;

    try {
      result = await this.pool.acquire(options.type, options.useMaster);
    } catch (error) {
      if (error instanceof TimeoutError) throw new errors.ConnectionAcquireTimeoutError(error);
      throw error;
    }

    debug('connection acquired');

    return result;
  }

  /**
   * Release a pooled connection so it can be utilized by other connection requests
   *
   * @param {Connection} connection
   *
   * @returns {Promise}
   */
  async releaseConnection(connection) {
    this.pool.release(connection);
    debug('connection released');
  }

  /**
   * Call dialect library to get connection
   *
   * @param {*} config Connection config
   * @private
   * @returns {Promise<Connection>}
   */
  async _connect(config) {
    await this.sequelize.runHooks('beforeConnect', config);
    const connection = await this.dialect.connectionManager.connect(config);
    await this.sequelize.runHooks('afterConnect', connection, config);
    return connection;
  }

  /**
   * Call dialect library to disconnect a connection
   *
   * @param {Connection} connection
   * @private
   * @returns {Promise}
   */
  async _disconnect(connection) {
    await this.sequelize.runHooks('beforeDisconnect', connection);
    await this.dialect.connectionManager.disconnect(connection);
    return this.sequelize.runHooks('afterDisconnect', connection);
  }

  /**
   * Determine if a connection is still valid or not
   *
   * @param {Connection} connection
   *
   * @returns {boolean}
   */
  _validate(connection) {
    if (!this.dialect.connectionManager.validate) {
      return true;
    }

    return this.dialect.connectionManager.validate(connection);
  }
}

module.exports = ConnectionManager;
module.exports.ConnectionManager = ConnectionManager;
module.exports.default = ConnectionManager;
<|endoftext|>


<commit_before>const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;

let mainWindow = null;

function createWindow() {
  // We want kiosk mode. Kiosk mode eg: https://developer.apple.com/library/mac/technotes/tn2062/_index.html
  // mainWindow = new BrowserWindow({
  //   kiosk: true,
  //   toolbar: false,
  //   title: 'Rebecca',
  //   frame: false
  // });

  // We set fullscreen for dev only
  mainWindow = new BrowserWindow({
    fullscreen: true,
    toolbar: false,
    title: 'Rebecca',
    frame: false
  });

  // Load index.html of the app
  mainWindow.loadURL(`file://${__dirname}/app/index.html`);

  // To open the devTools
  mainWindow.webContents.openDevTools();

  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element
    mainWindow = null;
  });
}

app.on('ready', createWindow);

app.on('window-all-closed', function() {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if(process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', function() {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open
  if(mainWindow === null) {
    createWindow();
  }
})<commit_msg>Change file to load from /www/index.html instead of /app/index.html<commit_after>const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;

let mainWindow = null;

function createWindow() {
  // We want kiosk mode. Kiosk mode eg: https://developer.apple.com/library/mac/technotes/tn2062/_index.html
  // mainWindow = new BrowserWindow({
  //   kiosk: true,
  //   toolbar: false,
  //   title: 'Rebecca',
  //   frame: false
  // });

  // We set fullscreen for dev only
  mainWindow = new BrowserWindow({
    fullscreen: true,
    toolbar: false,
    title: 'Rebecca',
    frame: false
  });

  // Load index.html of the app
  mainWindow.loadURL(`file://${__dirname}/www/index.html`);

  // To open the devTools
  mainWindow.webContents.openDevTools();

  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element
    mainWindow = null;
  });
}

app.on('ready', createWindow);

app.on('window-all-closed', function() {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if(process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', function() {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open
  if(mainWindow === null) {
    createWindow();
  }
})<|endoftext|>


<commit_before>// Some functions for inserting quickly (unack'ed writes) (Create)
// Preheating data to get it into memory (Read)
// Changing the data, with/without growth (Update)
// Removing data (Delete)

// First function is used to create a random set of data, the C in CRUD
// Defaults/Assumptions: _id index only, collection always called "data"
// Takes 3 arguments:
// numGB is the approximate data size to create in GiB (integer usually, but any number should work)
// dbName is the database to use (defaults to a collection called data)
// usePowerOf2 is a boolean to allow you to select the storage strategy

createData = function(numGB, dbName, usePowerOf2) {
    var db1 = db.getSiblingDB(dbName);
    // set powerOf2 per the boolean, but need to handle it differently if it currently exists or not
    // NOTE that second option will turn it off for all new collections

    if(db1.data.findOne()){
        db1.runCommand({ collMod : "data", usePowerOf2Sizes : usePowerOf2 });
    } else {
        db1.adminCommand({ setParameter: 1, newCollectionsUsePowerOf2Sizes: usePowerOf2 });
    };

    // check the shell version, if 2.5+ set legacy mode for unacked writes (for speed)
    var shellVersion = version().split('.').map(Number);
    if ( shellVersion[0] > 2 ) {
	    db1.getMongo().forceWriteMode("legacy");
	} else if (shellVersion[0] == 2) {
		if (shellVersion[1] > 4) {
		db1.getMongo().forceWriteMode("legacy");
		}
	};

    // with the document we are using, 68 iterations of this loop will get you ~1033MiB of data (not uncluding indexes), so use that as a multiplier
    var startTime = new Date();

    for(var j = 0; j < (numGB * 68); j++){
        // going to create a big array of docs, then insert them
        var bigDoc = [];
        for(var i = 0; i < 66400; i++){  // 132800 gets pretty close to the max doc size but takes a bit too long to generate on my machine, leaving gaps, so divide by 2
            var randomNum = Math.random(); // generate a single random number per loop iteration
            var ranDate = new Date(Math.floor(1500000000000 * randomNum));
            // let's construct a random ObjectId based on the number, basically construct a string with the info we need and some randomness
            // first piece is 4 bytes (8 hex digits), need to pad with zeroes for low values (same with random end piece)
            // next pieces per the spec are 6 hex digits for the machine, 4 digits for the PID
            // instead we will insert 10 placeholder characters for expedience
            // then, round things out with 3 bytes of randomness per the spec, and use the increment on the loop to avoid collisions
            var ranString = (Math.floor(randomNum * 1500000000).toString(16)).pad(8, false, 0) + "adacefd123" + ((Math.floor(randomNum * 16710815) + i).toString(16)).pad(6, false, 0);
            // this one would be better, but too slow to generate:
            // var ranString = ((Math.floor(1500000000 * randomNum)).toString(16)).pad(8, false, "0") + db1.version().replace(/\./g, "") + "adacefd" + ((Math.floor(randomNum * 9920329) + i).toString(16)).pad(6, false, "0");
            var ranId = new ObjectId(ranString);
            // To explain the document:
            // _id and ranDate are both based on the same randomly generated date, but ranDate has millis and is a bit easier to parse
            // After that we add an integer, boolean and a small array with a string and a number (array is useful for growth later)
            bigDoc.push({_id : ranId, ranDate : ranDate, ranInt : Math.floor(randomNum * 1000000), ranBool : (randomNum < 0.5 ? true : false), smallArray : [randomNum, randomNum.toString()]});
        };
        db1.data.insert(bigDoc);

        if(j == (numGB * 34)){
            print("Approximately 50% done: " + (j * 66400) + " docs inserted in " + (new Date() - startTime)/1000 + " seconds");
        };

    };
    var timeTaken = ((new Date() - startTime)/1000);
    print("Run complete: " + (numGB * 68 * 66400) + " docs inserted in " + timeTaken + " seconds.  Average insertion rate: " + ((numGB * 136 * 33200)/timeTaken) + " docs per second");
    // clean up the write mode if altered at the top
    if(db1.getMongo().writeMode() == "legacy"){
	    db1.getMongo().forceWriteMode("commands");
    }
};

// Sample runs of the createData script on a standalone mongod, both run on same 8 core Linux host, not IO bound
// Single thread CPU for shell was close to max, as was database lock on mongod - results within margin of error for the versions:

// 2.6.3 - Run complete: 4515200 docs inserted in 148.452 seconds.  Average insertion rate: 30415.218387088084 docs per second
// 2.4.10 - Run complete: 4515200 docs inserted in 146.916 seconds.  Average insertion rate: 30733.20809169866 docs per second

// Next, the reads - we'll do this randomly across the set
// Takes 2 arguments:
// numGB is the approximate data size to create in GiB (integer usually, but any number should work)
// dbName is the database to use (defaults to a collection called data)

preHeatRandomData = function(numGB, dbName) {

// We will brute force this basically, the _id is indexed and we know how it was constructed
// The first 8 hex digits of the pseudo ObjectID we created have a maximum of 16^6 docs, but likely far less
// A bit of experimentation tells me that using all 8 digits is too slow (low hit rate)
// Even 6 digits is still only 256 second ranges and yielded an average of less than 2 docs per range in limited tests
// Hence, we will do a range query using the first 5 digits plus fixed strings to create the start/end of the range
// Thats 16^3 or 4096 secs, so not an unreasonable range to query in general (1GiB set tests yielded ~12 docs per range)
// Every time we do the range query, we will call explain, and then increment the results by the nscanned count
//
// Note: decent chance there will be collisions, so may need to "oversubscribe" the amount of data to be touched

var docHits = 0;
var noHits = 0;
var iterations = 0;   // not really needed other than for stats

var db1 = db.getSiblingDB(dbName);

var startTime = new Date(); // time the loop
while(docHits < (5000000 * numGB)) {
	// the creation of the string is identical to the creation code
    var randomNum = Math.random();
    var ranString = (Math.floor(randomNum * 1500000000).toString(16)).pad(8, false, 0);
    // we just strip the last 3 characters to allow us to create ranges - 3 characters is only 4096 seconds
    ranString = ranString.substring(0, ranString.length - 3)
    var beginId = new ObjectId(ranString + "000adacefd123000000");
    var endId = new ObjectId(ranString + "fffadacefd123ffffff");
    // simple ranged query on _id with an explicit hint and an explain so we exhaust the cursor and get useful stats back
    var result = db1.data.find({_id : {$gte : beginId, $lte : endId}}).hint({_id : 1}).explain();
    if(result.nscanned > 0) {
        docHits += result.nscanned; //increment by number of scanned if not empty
    } else {
        noHits++;  // record the lack of hits
    };
    iterations++; // total iterations
    // warn about low hit rates at each 250k no hit occurrences
	if((noHits % 250000) == 0  && noHits > 0){
        print("Warning: hit rate is poor - just passed " + noHits + " iterations with no hits (current hits doc hits are: " + docHits + " out of " + (5000000 * numGB) + " or " + docHits/(50000 * numGB) + "%).");
	};
};
var endTime = new Date();
// some info on the time taken, hit rate etc.
print(numGB + "GiB of data loaded (" + (numGB * 5000000) + " docs), took " + (endTime - startTime)/1000 + " seconds to complete (average: " + (numGB * 5000000)/((endTime - startTime)/1000) + " docs/sec)")
print(noHits + " queries hit 0 documents (" + (noHits*100)/iterations + "%) and there were " + iterations + " total iterations." );
print("Average number of docs scanned per iteration (hits only): " + (numGB * 5000000)/(iterations - noHits) );
};

// update docs, optionally making them grow (creates free list)

updateRandomData = function(numGB, dbName, growDocs){

// quick test shows that with powerOf2Sizes, need to add 9 ObjectIds to the smallArray to trigger a move
// so growing the docs will take a lot more updates in order to complete the run
// testing for a move is a little clunky, but basically do a push, check the diskLoc
var db1 = db.getSiblingDB(dbName);
var updateHits = 0;
var growthOverhead = 0;
var startTime = new Date(); // time the loop
while(updateHits < (5000000 * numGB)){
    // we'll re-use the logic from the finds, create a range to look for a candidate document
    var randomNum = Math.random();
    var ranString = (Math.floor(randomNum * 1500000000).toString(16)).pad(8, false, 0);
    // we just strip the last 3 characters to allow us to create ranges - 3 characters is only 4096 seconds
    ranString = ranString.substring(0, ranString.length - 3)
    var beginId = new ObjectId(ranString + "000adacefd123000000");
    var endId = new ObjectId(ranString + "fffadacefd123ffffff");
    // simple findOne on _id with an explicit hint
	var result = 0;
	// loop until we have a valid result (in case of misses), and we will use the ranInt to not hit docs twice
	while(result == 0){
        result = db1.data.find({_id : {$gte : beginId, $lte : endId}, ranInt : {$lte : 1000000}}).hint({_id : 1}).next();
    }
    if(growDocs){
        growthOverhead += pushUntilMoved(genTest, result._id, false);
        db1.data.update({_id : result._id}, {$inc : {ranInt : 1000000}});
        updateHits++;
    } else {
	    db1.data.update({_id : result._id}, {$inc : {ranInt : 1000000}});
        updateHits++;
	}
}
var endTime = new Date();

if(growDocs){
    print("Updated " + updateHits + " docs in " + (endTime - startTime)/1000 + " seconds (avg: " + (5000000 * numGB)/((endTime - startTime)/1000) + " docs/sec. Growth required an average of " + (growthOverhead/updateHits) + " pushes to the array.");
} else {
    print("Updated " + updateHits + " docs in " + (endTime - startTime)/1000 + " seconds (avg: " + (5000000 * numGB)/((endTime - startTime)/1000) + " docs/sec.");
};

}

// this little function will take an ObjectID, then push new IDs to the smallArray until the document moves on disk
// verbose toggles information about old/new location and number of pushes required (will be more for powerOf2 docs)
// it's needed to provide the move functionality in the update function
pushUntilMoved = function(dbName, docID, verbose){
	var db1 = db.getSiblingDB(dbName);
	var currentLoc = db1.data.find({_id : docID}).showDiskLoc().next().$diskLoc;
	var newLoc = currentLoc;
	var pushes = 0;
	while((currentLoc.file == newLoc.file) && (currentLoc.offset == newLoc.offset)){
		db1.data.update({_id : docID}, {$push : {smallArray : new ObjectId()}});
		newLoc = db1.data.find({_id : docID}).showDiskLoc().next().$diskLoc;
		pushes++;
	}
	if(verbose){
		print("Old location: file: " + currentLoc.file + " offset: " + currentLoc.offset);
		print("New location: file: " + newLoc.file + " offset: " + newLoc.offset);
		print("Pushes required: " + pushes);
    }
	return pushes;
}

// delete docs, create holes and a free list

deleteRandomData = function(numGB, dbName){

}<commit_msg>fixed growth typo, cleaned up comments<commit_after>// Some functions for inserting quickly (unack'ed writes) (Create)
// Preheating data to get it into memory (Read)
// Changing the data, with/without growth (Update)
// Removing data (Delete)

// First function is used to create a random set of data, the C in CRUD
// Defaults/Assumptions: _id index only, collection always called "data"
// Takes 3 arguments:
// numGB is the approximate data size to create in GiB (integer usually, but any number should work)
// dbName is the database to use (defaults to a collection called data)
// usePowerOf2 is a boolean to allow you to select the storage strategy

createData = function(numGB, dbName, usePowerOf2) {
    var db1 = db.getSiblingDB(dbName);
    // set powerOf2 per the boolean, but need to handle it differently if it currently exists or not
    // NOTE that second option will turn it off for all new collections

    if(db1.data.findOne()){
        db1.runCommand({ collMod : "data", usePowerOf2Sizes : usePowerOf2 });
    } else {
        db1.adminCommand({ setParameter: 1, newCollectionsUsePowerOf2Sizes: usePowerOf2 });
    };

    // check the shell version, if 2.5+ set legacy mode for unacked writes (for speed)
    var shellVersion = version().split('.').map(Number);
    if ( shellVersion[0] > 2 ) {
	    db1.getMongo().forceWriteMode("legacy");
	} else if (shellVersion[0] == 2) {
		if (shellVersion[1] > 4) {
		db1.getMongo().forceWriteMode("legacy");
		}
	};

    // with the document we are using, 68 iterations of this loop will get you ~1033MiB of data (not uncluding indexes), so use that as a multiplier
    var startTime = new Date();

    for(var j = 0; j < (numGB * 68); j++){
        // going to create a big array of docs, then insert them
        var bigDoc = [];
        for(var i = 0; i < 66400; i++){  // 132800 gets pretty close to the max doc size but takes a bit too long to generate on my machine, leaving gaps, so divide by 2
            var randomNum = Math.random(); // generate a single random number per loop iteration
            var ranDate = new Date(Math.floor(1500000000000 * randomNum));
            // let's construct a random ObjectId based on the number, basically construct a string with the info we need and some randomness
            // first piece is 4 bytes (8 hex digits), need to pad with zeroes for low values (same with random end piece)
            // next pieces per the spec are 6 hex digits for the machine, 4 digits for the PID
            // instead we will insert 10 placeholder characters for expedience
            // then, round things out with 3 bytes of randomness per the spec, and use the increment on the loop to avoid collisions
            var ranString = (Math.floor(randomNum * 1500000000).toString(16)).pad(8, false, 0) + "adacefd123" + ((Math.floor(randomNum * 16710815) + i).toString(16)).pad(6, false, 0);
            // this one would be better, but too slow to generate:
            // var ranString = ((Math.floor(1500000000 * randomNum)).toString(16)).pad(8, false, "0") + db1.version().replace(/\./g, "") + "adacefd" + ((Math.floor(randomNum * 9920329) + i).toString(16)).pad(6, false, "0");
            var ranId = new ObjectId(ranString);
            // To explain the document:
            // _id and ranDate are both based on the same randomly generated date, but ranDate has millis and is a bit easier to parse
            // After that we add an integer, boolean and a small array with a string and a number (array is useful for growth later)
            bigDoc.push({_id : ranId, ranDate : ranDate, ranInt : Math.floor(randomNum * 1000000), ranBool : (randomNum < 0.5 ? true : false), smallArray : [randomNum, randomNum.toString()]});
        };
        db1.data.insert(bigDoc);

        if(j == (numGB * 34)){
            print("Approximately 50% done: " + (j * 66400) + " docs inserted in " + (new Date() - startTime)/1000 + " seconds");
        };

    };
    var timeTaken = ((new Date() - startTime)/1000);
    print("Run complete: " + (numGB * 68 * 66400) + " docs inserted in " + timeTaken + " seconds.  Average insertion rate: " + ((numGB * 136 * 33200)/timeTaken) + " docs per second");
    // clean up the write mode if altered at the top
    if(db1.getMongo().writeMode() == "legacy"){
	    db1.getMongo().forceWriteMode("commands");
    }
};

// Sample runs of the createData script on a standalone mongod, both run on same 8 core Linux host, not IO bound
// Single thread CPU for shell was close to max, as was database lock on mongod - results within margin of error for the versions:

// 2.6.3 - Run complete: 4515200 docs inserted in 148.452 seconds.  Average insertion rate: 30415.218387088084 docs per second
// 2.4.10 - Run complete: 4515200 docs inserted in 146.916 seconds.  Average insertion rate: 30733.20809169866 docs per second

// Next, the reads - we'll do this randomly across the set
// Takes 2 arguments:
// numGB is the approximate data size to create in GiB (integer usually, but any number should work)
// dbName is the database to use (defaults to a collection called data)

preHeatRandomData = function(numGB, dbName) {

// We will brute force this basically, the _id is indexed and we know how it was constructed
// The first 8 hex digits of the pseudo ObjectID we created have a maximum of 16^6 docs, but likely far less
// A bit of experimentation tells me that using all 8 digits is too slow (low hit rate)
// Even 6 digits is still only 256 second ranges and yielded an average of less than 2 docs per range in limited tests
// Hence, we will do a range query using the first 5 digits plus fixed strings to create the start/end of the range
// Thats 16^3 or 4096 secs, so not an unreasonable range to query in general (1GiB set tests yielded ~12 docs per range)
// Every time we do the range query, we will call explain, and then increment the results by the nscanned count
//
// Note: decent chance there will be collisions, so may need to "oversubscribe" the amount of data to be touched

var docHits = 0;
var noHits = 0;
var iterations = 0;   // not really needed other than for stats

var db1 = db.getSiblingDB(dbName);

var startTime = new Date(); // time the loop
while(docHits < (5000000 * numGB)) {
	// the creation of the string is identical to the creation code
    var randomNum = Math.random();
    var ranString = (Math.floor(randomNum * 1500000000).toString(16)).pad(8, false, 0);
    // we just strip the last 3 characters to allow us to create ranges - 3 characters is only 4096 seconds
    ranString = ranString.substring(0, ranString.length - 3)
    var beginId = new ObjectId(ranString + "000adacefd123000000");
    var endId = new ObjectId(ranString + "fffadacefd123ffffff");
    // simple ranged query on _id with an explicit hint and an explain so we exhaust the cursor and get useful stats back
    var result = db1.data.find({_id : {$gte : beginId, $lte : endId}}).hint({_id : 1}).explain();
    if(result.nscanned > 0) {
        docHits += result.nscanned; //increment by number of scanned if not empty
    } else {
        noHits++;  // record the lack of hits
    };
    iterations++; // total iterations
    // warn about low hit rates at each 250k no hit occurrences
	if((noHits % 250000) == 0  && noHits > 0){
        print("Warning: hit rate is poor - just passed " + noHits + " iterations with no hits (current hits doc hits are: " + docHits + " out of " + (5000000 * numGB) + " or " + docHits/(50000 * numGB) + "%).");
	};
};
var endTime = new Date();
// some info on the time taken, hit rate etc.
print(numGB + "GiB of data loaded (" + (numGB * 5000000) + " docs), took " + (endTime - startTime)/1000 + " seconds to complete (average: " + (numGB * 5000000)/((endTime - startTime)/1000) + " docs/sec)")
print(noHits + " queries hit 0 documents (" + (noHits*100)/iterations + "%) and there were " + iterations + " total iterations." );
print("Average number of docs scanned per iteration (hits only): " + (numGB * 5000000)/(iterations - noHits) );
};

// update docs, optionally making them grow (creates free list)

updateRandomData = function(numGB, dbName, growDocs){

// quick test shows that with powerOf2Sizes, need to add 9 ObjectIds to the smallArray to trigger a move
// so growing the docs will take a lot more updates in order to complete the run
// testing for a move is a little clunky until we get better write command stats, so pushing that to its own function for now
var db1 = db.getSiblingDB(dbName);
var updateHits = 0;
var growthOverhead = 0;
var startTime = new Date(); // time the loop
while(updateHits < (5000000 * numGB)){
    // we'll re-use the logic from the finds, create a range to look for a candidate document
    var randomNum = Math.random();
    var ranString = (Math.floor(randomNum * 1500000000).toString(16)).pad(8, false, 0);
    // we just strip the last 3 characters to allow us to create ranges - 3 characters is only 4096 seconds
    ranString = ranString.substring(0, ranString.length - 3)
    var beginId = new ObjectId(ranString + "000adacefd123000000");
    var endId = new ObjectId(ranString + "fffadacefd123ffffff");
    // simple findOne on _id with an explicit hint
	var result = 0;
	// loop until we have a valid result (in case of misses), and we will use the ranInt to not hit docs twice
	while(result == 0){
        result = db1.data.find({_id : {$gte : beginId, $lte : endId}, ranInt : {$lte : 1000000}}).hint({_id : 1}).next();
    }
    if(growDocs){
        growthOverhead += pushUntilMoved(dbName, result._id, false);
        db1.data.update({_id : result._id}, {$inc : {ranInt : 1000000}});
        updateHits++;
    } else {
	    db1.data.update({_id : result._id}, {$inc : {ranInt : 1000000}});
        updateHits++;
	}
}
var endTime = new Date();

if(growDocs){
    print("Updated " + updateHits + " docs in " + (endTime - startTime)/1000 + " seconds (avg: " + (5000000 * numGB)/((endTime - startTime)/1000) + " docs/sec. Growth required an average of " + (growthOverhead/updateHits) + " pushes to the array.");
} else {
    print("Updated " + updateHits + " docs in " + (endTime - startTime)/1000 + " seconds (avg: " + (5000000 * numGB)/((endTime - startTime)/1000) + " docs/sec.");
};

}

// this little function will take an ObjectID, then push new IDs to the smallArray until the document moves on disk
// verbose toggles information about old/new location and number of pushes required (will be more for powerOf2 docs)
// it's needed to provide the move functionality in the update function
pushUntilMoved = function(dbName, docID, verbose){
	var db1 = db.getSiblingDB(dbName);
	var currentLoc = db1.data.find({_id : docID}).showDiskLoc().next().$diskLoc;
	var newLoc = currentLoc;
	var pushes = 0;
	while((currentLoc.file == newLoc.file) && (currentLoc.offset == newLoc.offset)){
		db1.data.update({_id : docID}, {$push : {smallArray : new ObjectId()}});
		newLoc = db1.data.find({_id : docID}).showDiskLoc().next().$diskLoc;
		pushes++;
	}
	if(verbose){
		print("Old location: file: " + currentLoc.file + " offset: " + currentLoc.offset);
		print("New location: file: " + newLoc.file + " offset: " + newLoc.offset);
		print("Pushes required: " + pushes);
    }
	return pushes;
}

// delete docs, create holes and a free list

deleteRandomData = function(numGB, dbName){

}<|endoftext|>


<commit_before>/* eslint react/no-find-dom-node: 0 */

import { Component } from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import ScrollSyncContext from './support/ScrollSyncContext'

/**
 * ScrollSyncPane Component
 *
 * Wrap your content in it to keep its scroll position in sync with other panes
 *
 * @example ./example.md
 */

export default class ScrollSyncPane extends Component {
  static contextType = ScrollSyncContext;

  static propTypes = {
    children: PropTypes.node.isRequired,
    attachTo: PropTypes.object,
    group: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
    enabled: PropTypes.bool
  }

  static defaultProps = {
    group: 'default',
    enabled: true
  }

  static contextTypes = {
    registerPane: PropTypes.func,
    unregisterPane: PropTypes.func
  }

  componentDidMount() {
    if (this.props.enabled) {
      this.node = this.props.attachTo || ReactDOM.findDOMNode(this)
      this.context.registerPane(this.node, this.toArray(this.props.group))
    }
  }

  componentDidUpdate(prevProps) {
    if (this.props.enabled && this.props.group !== prevProps.group) {
      this.context.unregisterPane(this.node, this.toArray(prevProps.group))
      this.context.registerPane(this.node, this.toArray(this.props.group))
    }
  }

  componentWillUnmount() {
    if (this.props.enabled) {
      this.context.unregisterPane(this.node, this.toArray(this.props.group))
    }
  }

  toArray = groups => [].concat(groups)

  render() {
    return this.props.children
  }
}
<commit_msg>feat: Remove warnings on Strict Mode and update on props change (#76)<commit_after>/* eslint react/no-find-dom-node: 0 */

import { Component, Children, createRef, cloneElement } from 'react'
import PropTypes from 'prop-types'
import ScrollSyncContext from './support/ScrollSyncContext'

/**
 * ScrollSyncPane Component
 *
 * Wrap your content in it to keep its scroll position in sync with other panes
 *
 * @example ./example.md
 */

export default class ScrollSyncPane extends Component {
  static contextType = ScrollSyncContext;

  static propTypes = {
    children: PropTypes.node.isRequired,
    attachTo: PropTypes.oneOfType([
      PropTypes.func,
      PropTypes.shape({ current: PropTypes.any })
    ]),
    group: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
    enabled: PropTypes.bool
  }

  static defaultProps = {
    group: 'default',
    enabled: true
  }

  constructor(props) {
    super(props)
    this.childRef = createRef()
  }

  componentDidMount() {
    if (this.props.enabled) {
      this.updateNode()
      if (this.node) {
        this.context.registerPane(this.node, this.toArray(this.props.group))
      }
    }
  }

  componentDidUpdate(prevProps) {
    if (this.props.attachTo !== prevProps.attachTo) {
      if (this.node) {
        this.context.unregisterPane(this.node, this.toArray(prevProps.group))
      }
      this.updateNode()
      if (this.node) {
        this.context.registerPane(this.node, this.toArray(prevProps.group))
      }
    }
    if (this.node && this.props.enabled !== prevProps.enabled) {
      if (this.props.enabled) {
        this.context.registerPane(this.node, this.toArray(prevProps.group))
      } else {
        this.context.unregisterPane(this.node, this.toArray(prevProps.group))
      }
    }
    if (this.node && this.props.enabled && this.props.group !== prevProps.group) {
      this.context.unregisterPane(this.node, this.toArray(prevProps.group))
      this.context.registerPane(this.node, this.toArray(this.props.group))
    }
  }

  componentWillUnmount() {
    if (this.node && this.props.enabled) {
      this.context.unregisterPane(this.node, this.toArray(this.props.group))
    }
  }

  toArray = groups => [].concat(groups)

  updateNode = () => {
    if (this.props.attachTo) {
      this.node = this.props.attachTo.current
    } else {
      this.node = this.childRef.current
    }
  }

  render() {
    if (this.props.attachTo) {
      return this.props.children
    }
    return cloneElement(Children.only(this.props.children), { ref: this.childRef })
  }
}
<|endoftext|>


<commit_before>// Handle status changes
function handleStatusChange(response) {
    alert(JSON.stringify(response));
    if (response.authResponse) {
        $('#login').addClass('hide');
        updateUserInfo(response);
    }
    else {
        $('#login').removeClass('hide');
    }
}

function promptLogin() {
    FB.login(function(response) {
        alert(JSON.stringify(response));
    }, {scope: 'email'});
}

function updateUserInfo(response) {
    FB.api('/me',
        {fields: "name,first_name,picture"},
        function (response) {
            $('#info').html('Hæ, ' + response.name).removeClass('hide');
        });
}

function handleGenericError(e) {
    console.log("Error ..." + JSON.stringify(e));
}

function reauthorizeForPublishPermissions() {
    console.log("[reauthorizeForPublishPermissions] asking for additional permissions.");
    // If successful, try publishing action again
    // else, just show error
    FB.login(
        function (response) {
            if (!response || response.error) {
                handleGenericError(response.error);
            } else {
            }
        }, {scope: 'publish_actions'}
    );
}

$(function() {
    $('#login').click(function() {
        promptLogin();
    });
});<commit_msg>Remove alerts.<commit_after>// Handle status changes
function handleStatusChange(response) {
    if (response.authResponse) {
        $('#login').addClass('hide');
        updateUserInfo(response);
    }
    else {
        $('#login').removeClass('hide');
    }
}

function promptLogin() {
    FB.login(function(response) {
    }, {scope: 'email'});
}

function updateUserInfo(response) {
    FB.api('/me',
        {fields: "name,first_name,picture"},
        function (response) {
            $('#info').html('Hæ, ' + response.name).removeClass('hide');
        });
}

function handleGenericError(e) {
    console.log("Error ..." + JSON.stringify(e));
}

function reauthorizeForPublishPermissions() {
    console.log("[reauthorizeForPublishPermissions] asking for additional permissions.");
    // If successful, try publishing action again
    // else, just show error
    FB.login(
        function (response) {
            if (!response || response.error) {
                handleGenericError(response.error);
            } else {
            }
        }, {scope: 'publish_actions'}
    );
}

$(function() {
    $('#login').click(function() {
        promptLogin();
    });
});<|endoftext|>