Source: replica.js

"use strict";

var Strings     = require("./strings"),
    Err         = require("./utils/error"),
    object      = require("./utils/object"),
    async       = require("async");

function write(replica, method, args) {
    if (replica.writeStrategy === "rollback") {
        replica.manager.transaction.set(function (err, trans) {
            if (err) {
                args.callback(err);
            }
            replica.collections.forEach(function (el) {
                trans[el][method](args.item);
            });
            trans.commit(args.context, args.callback);
        });
    } else {
        var fns = [];
        replica.collections.forEach(function (el) {
            fns.push(function (cb) {
                replica.manager[el][method](args.context, args.item, cb);
            });
        });
        async.parallel(fns, args.callback);
    }
}

/**
 * Constructor for the Replica class.
 *
 * Replica sets are used just like regular data collections.
 * Please see {@link Provider} for usage reference.
 *
 * Options:
 *
 * - `master` {string} - Defines the master collection in the replica set.
 * If omitted the first collection in the set is assumed to be the master.
 * - `readStrategy` {string} - Defines the read strategy for the replica set.
 * See {@link Replica#readStrategy}.
 * - `writeStrategy` {string} - Defines the write strategy for the replica set.
 * See {@link Replica#writeStrategy}.
 *
 * @class Represents a replica set.
 * @param {Manager} manager - An EntreeJS instance.
 * @param {string[]} colls - The names of the data collections participating in the replica set.
 * There must be at least two collections in the array.
 * @param {object=} opts - Additional options.
 */
function Replica(manager, colls, opts) {
    if (!Array.isArray(colls) || colls.length < 2) {
        throw new Err(Strings.ERR_COLLS_ARG);
    }

    if (!opts) {
        opts = {};
    }

    /**
     * The EntreJS instance holding this replica set.
     */
    this.manager = manager;

    /**
     * An array of the names of the data collections participating in the replica set.
     */
    this.collections = colls;

    /**
     * Defines the master collection in the replica set.
     * If omitted the first collection in the set is assumed to be the master.
     */
    this.master = opts.master || colls[0];

    /**
     * Defines the read strategy for the replica set. Defaults to `master`.
     *
     * - `"master"` - Only the master collection is used for read operations (e.g. get, select).
     * - `"round-robin"` - All collections in the set are cycled for ever read request.
     * - `"feedback"` (not available yet) - Collections with lower latency are given higher priority.
     *
     * Read strategy allows for simple load and throughput balancing of back-end services.
     */
    this.readStrategy = opts.readStrategy || "master";

    /**
     * Defines the write strategy for the replica set. Defaults to `rollback`.
     *
     * - `"rollback"` - Attempts to recover the state of all collections in case any of them fails to write successfully.
     * - `"none"` - Errors on failures are returned but no actions are taken.
     */
    this.writeStrategy = opts.writeStrategy || "rollback";

    this._curr = 0;
}

Replica.prototype._next = function () {
    switch (this.readStrategy) {
    case "master":
        return this.master;
    case "round-robin":
        if (this._curr === this.collections.length) {
            this._curr = 0;
        }
        return this.collections[this._curr++];
    case "feedback":
        // FUTURE: Implement feedback read strategy.
        throw new Error("Feedback strategy not implemented yet.");
    default:
        throw new Error("Invalid read strategy: " + this.readStrategy);
    }
};

Replica.prototype.get = function () {
    var prov = this.manager[this._next()];
    return prov.get.apply(prov, arguments);
};

Replica.prototype.select = function () {
    // TODO: Have to wrap the cursor to handle bulk update and delete.
    var prov = this.manager[this._next()];
    return prov.select.apply(prov, arguments);
};

Replica.prototype.insert = function () {
    var args = object.validateArgs(arguments, "items");
    if (args) {
        write(this, "insert", args);
    }
};

Replica.prototype.upsert = function () {
    var args = object.validateArgs(arguments, "item");
    if (args) {
        write(this, "upsert", args);
    }
};

Replica.prototype.update = function () {
    var args = object.validateArgs(arguments, "item");
    if (args) {
        write(this, "update", args);
    }
};

Replica.prototype.delete = function () {
    var args = object.validateArgs(arguments, "itemOrID");
    if (args) {
        write(this, "delete", args);
    }
};

module.exports = Replica;
EntreeJS Copyright © 2013-2014 The contributors to the EntreeJS project.
Documentation generated by JSDoc 3.2.2 on Mon May 26 2014 17:43:41 GMT+0300 (EEST) using the DocStrap template.