├── .nvmrc
├── .gitignore
├── examples
└── voter
│ └── voter
│ ├── public
│ ├── images
│ │ └── logo.png
│ └── stylesheets
│ │ ├── style.css
│ │ ├── images
│ │ ├── ui-icons_222222_256x240.png
│ │ ├── ui-icons_228ef1_256x240.png
│ │ ├── ui-icons_ef8c08_256x240.png
│ │ ├── ui-icons_ffd27a_256x240.png
│ │ ├── ui-icons_ffffff_256x240.png
│ │ ├── ui-bg_flat_10_000000_40x100.png
│ │ ├── ui-bg_glass_100_f6f6f6_1x400.png
│ │ ├── ui-bg_glass_100_fdf5ce_1x400.png
│ │ ├── ui-bg_glass_65_ffffff_1x400.png
│ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png
│ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png
│ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png
│ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png
│ │ └── ui-bg_highlight-soft_100_eeeeee_1x100.png
│ │ └── jquery-ui-1.8.17.custom.css
│ ├── package.json
│ ├── views
│ ├── layout.jade
│ └── index.jade
│ ├── routes
│ └── index.js
│ ├── jsons
│ └── votes.js
│ ├── app.js
│ └── models
│ └── volt.js
├── tools
└── testdb
│ ├── deployment.xml
│ ├── ddl-drop.sql
│ ├── ddl.sql
│ ├── project.xml
│ ├── src
│ └── com
│ │ └── voltdb
│ │ └── test
│ │ └── typetest
│ │ └── proc
│ │ ├── InitTestType.java
│ │ └── Insert.java
│ └── run.sh
├── .eslintrc.json
├── LICENSE
├── package.json
├── lib
├── configuration.js
├── query.js
├── voltconstants.js
├── message.js
├── client.js
├── connection.js
├── parser.js
└── ctype.js
├── CONTRIBUTING.md
├── test
├── util
│ ├── test-context.js
│ └── docker-util.js
├── testrunner.js
└── cases
│ ├── connections.js
│ ├── typestest.js
│ └── bufferTest.js
├── writer.js
├── README.md
└── voternoui.js
/.nvmrc:
--------------------------------------------------------------------------------
1 | 6.11.0
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | tools/testdb/voltdbroot/
3 | tools/testdb/obj/
4 | tools/testdb/log/
5 | tools/testdb/typetest.jar
6 |
--------------------------------------------------------------------------------
/examples/voter/voter/public/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/images/logo.png
--------------------------------------------------------------------------------
/tools/testdb/deployment.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 50px;
3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
4 | }
5 |
6 | a {
7 | color: #00B7FF;
8 | }
--------------------------------------------------------------------------------
/examples/voter/voter/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Voterjs"
3 | , "version": "0.0.1"
4 | , "private": true
5 | , "dependencies": {
6 | "express": "2.5.8"
7 | , "jade": ">= 0.0.1"
8 | }
9 | }
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-icons_228ef1_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-icons_228ef1_256x240.png
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-icons_ef8c08_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-icons_ef8c08_256x240.png
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-icons_ffd27a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-icons_ffd27a_256x240.png
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-icons_ffffff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-icons_ffffff_256x240.png
--------------------------------------------------------------------------------
/tools/testdb/ddl-drop.sql:
--------------------------------------------------------------------------------
1 | DROP PROCEDURE com.voltdb.test.typetest.proc.Insert IF EXISTS;
2 |
3 | DROP PROCEDURE com.voltdb.test.typetest.proc.InitTestType IF EXISTS;
4 |
5 | DROP TABLE typetest IF EXISTS;
6 |
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-bg_flat_10_000000_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-bg_flat_10_000000_40x100.png
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-bg_glass_100_f6f6f6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-bg_glass_100_f6f6f6_1x400.png
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-bg_glass_100_fdf5ce_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-bg_glass_100_fdf5ce_1x400.png
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-bg_gloss-wave_35_f6a828_500x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-bg_gloss-wave_35_f6a828_500x100.png
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-bg_highlight-soft_75_ffe45c_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-bg_diagonals-thick_18_b81900_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-bg_diagonals-thick_18_b81900_40x40.png
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-bg_diagonals-thick_20_666666_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-bg_diagonals-thick_20_666666_40x40.png
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/images/ui-bg_highlight-soft_100_eeeeee_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VoltDB/voltdb-client-nodejs/HEAD/examples/voter/voter/public/stylesheets/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
--------------------------------------------------------------------------------
/examples/voter/voter/views/layout.jade:
--------------------------------------------------------------------------------
1 | doctype
2 | html
3 | head
4 | title= title
5 | link(rel='stylesheet', href='/stylesheets/style.css')
6 | link(rel='stylesheet', href='/stylesheets/jquery-ui-1.8.17.custom.css')
7 | script(src='/javascripts/jquery-1.7.1.min.js')
8 | script(src='/javascripts/jquery-ui-1.8.17.custom.min.js')
9 | body!= body
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "es6": true,
4 | "node": true
5 | },
6 | "extends": "eslint:recommended",
7 | "parserOptions": {
8 | "sourceType": "module"
9 | },
10 | "rules": {
11 | "indent": [
12 | "warn",
13 | 2
14 | ],
15 | "linebreak-style": [
16 | "warn",
17 | "unix"
18 | ],
19 | "quotes": [
20 | "warn",
21 | "double"
22 | ],
23 | "semi": [
24 | "error",
25 | "always"
26 | ]
27 | }
28 | }
--------------------------------------------------------------------------------
/tools/testdb/ddl.sql:
--------------------------------------------------------------------------------
1 | -- test types
2 | CREATE TABLE typetest
3 | (
4 | test_id integer NOT NULL,
5 | test_tiny tinyint NOT NULL,
6 | test_small smallint NOT NULL,
7 | test_integer integer NOT NULL,
8 | test_big bigint NOT NULL,
9 | test_float float NOT NULL,
10 | test_decimal decimal NOT NULL,
11 | test_varchar varchar(100) NOT NULL,
12 | test_varbinary varbinary(4) NOT NULL,
13 | test_timestamp timestamp NOT NULL,
14 | CONSTRAINT PK_tests PRIMARY KEY
15 | (
16 | test_id
17 | )
18 | );
19 |
20 | PARTITION TABLE typetest ON COLUMN test_id;
21 |
22 | CREATE PROCEDURE FROM CLASS com.voltdb.test.typetest.proc.Insert;
23 |
24 | CREATE PROCEDURE FROM CLASS com.voltdb.test.typetest.proc.InitTestType;
25 |
--------------------------------------------------------------------------------
/tools/testdb/project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Nodejs client test
5 | 1
6 | Various test cases
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/examples/voter/voter/views/index.jade:
--------------------------------------------------------------------------------
1 | img(src = '/images/logo.png')
2 |
3 | h1= title
4 | p Welcome to the #{title}
5 |
6 | h2 Description
7 | p This application demonstrates a VoltDB generating data asynchronously,
8 | | reading it and rendering to a live table.
9 |
10 |
11 | table#VOTES
12 | thead
13 | tr: th Candidate
14 | th Votes
15 | tbody
16 | tr: td
17 | td
18 |
19 | script.
20 | $(function() {
21 | setInterval(getVotes, 400);
22 | });
23 |
24 | function getVotes() {
25 | $.getJSON('results', function(data) {
26 | $.each($('#VOTES tbody tr'), function (index, row) {
27 | $(row).remove();
28 | });
29 |
30 | tbody = $('#VOTES');
31 |
32 | rows = data.rows;
33 | $.each(rows, function( index, row) {
34 | tbody.append('
| ' + row.CONTESTANT_NAME + ' | ' + row.TOTAL_VOTES + ' |
');
35 | });
36 | });
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2008-2018 VoltDB Inc.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 | OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "voltjs",
3 | "version": "2.0.0",
4 | "description": "VoltDB binary driver",
5 | "keywords": [
6 | "voltdb",
7 | "client",
8 | "driver",
9 | "binary driver"
10 | ],
11 | "bugs": {
12 | "url": "https://github.com/VoltDB/voltdb-client-nodejs/issues",
13 | "email": "support@voltdb.com"
14 | },
15 | "license": "MIT",
16 | "author": "VoltDB",
17 | "engines": {
18 | "node": ">= 6.11.0"
19 | },
20 | "repository": {
21 | "type": "git",
22 | "url": "https://github.com/VoltDB/voltdb-client-nodejs.git"
23 | },
24 | "scripts": {
25 | "lint": "eslint test/util",
26 | "test": "node test/testrunner.js -i local"
27 | },
28 | "dependencies": {
29 | "bignumber": "^1.1.0",
30 | "ctype": "^0.5.0",
31 | "cli": "^1.0.0",
32 | "debug": "^3.0.1",
33 | "supports-color": "^4.4.0"
34 | },
35 | "devDependencies": {
36 | "eslint": "^4.7.1",
37 | "eslint-config-standard": "^10.2.1",
38 | "eslint-plugin-import": "^2.7.0",
39 | "eslint-plugin-node": "^5.1.1",
40 | "eslint-plugin-promise": "^3.5.0",
41 | "eslint-plugin-standard": "^3.0.1",
42 | "nodeunit": "^0.11.0",
43 | "yargs": "^10.0.3"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/examples/voter/voter/routes/index.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining
5 | * a copy of this software and associated documentation files (the
6 | * "Software"), to deal in the Software without restriction, including
7 | * without limitation the rights to use, copy, modify, merge, publish,
8 | * distribute, sublicense, and/or sell copies of the Software, and to
9 | * permit persons to whom the Software is furnished to do so, subject to
10 | * the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be
13 | * included in all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 | * OTHER DEALINGS IN THE SOFTWARE.
22 | */
23 | exports.index = function(req, res) {
24 |
25 | res.render('index', {
26 | title : 'VoltDB Voter Example'
27 | })
28 | };
29 |
--------------------------------------------------------------------------------
/lib/configuration.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining
5 | * a copy of this software and associated documentation files (the
6 | * "Software"), to deal in the Software without restriction, including
7 | * without limitation the rights to use, copy, modify, merge, publish,
8 | * distribute, sublicense, and/or sell copies of the Software, and to
9 | * permit persons to whom the Software is furnished to do so, subject to
10 | * the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be
13 | * included in all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 | * OTHER DEALINGS IN THE SOFTWARE.
22 | */
23 | VoltConfiguration = function() {
24 | }
25 | VoltConfiguration.prototype = Object.create({
26 | host : 'localhost',
27 | port : 21212,
28 | username : 'user',
29 | password : 'password',
30 | service : 'database',
31 | queryTimeout : 600000,
32 | queryTimeoutInterval: 60000,
33 | flushInterval: 1000,
34 | messageQueueSize : 10,
35 | maxConsecutiveWrites: 5000
36 | });
37 |
38 | module.exports = VoltConfiguration;
39 |
--------------------------------------------------------------------------------
/examples/voter/voter/jsons/votes.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining
5 | * a copy of this software and associated documentation files (the
6 | * "Software"), to deal in the Software without restriction, including
7 | * without limitation the rights to use, copy, modify, merge, publish,
8 | * distribute, sublicense, and/or sell copies of the Software, and to
9 | * permit persons to whom the Software is furnished to do so, subject to
10 | * the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be
13 | * included in all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 | * OTHER DEALINGS IN THE SOFTWARE.
22 | */
23 |
24 | var volt = require("../models/volt"),
25 | VoltConstants = require(__dirname + '/../../../../lib/voltconstants');
26 |
27 | exports.votes = function(req, res) {
28 | return volt.getVoteResults(function displayResults(code, event, results) {
29 | if(code == VoltConstants.STATUS_CODES.SUCCESS) {
30 | res.json({
31 | 'rows' : results.table[0]
32 | });
33 | } else {
34 | res.json({
35 | 'critical fault, database down': 500
36 | });
37 | }
38 | });
39 | }
--------------------------------------------------------------------------------
/tools/testdb/src/com/voltdb/test/typetest/proc/InitTestType.java:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining
5 | * a copy of this software and associated documentation files (the
6 | * "Software"), to deal in the Software without restriction, including
7 | * without limitation the rights to use, copy, modify, merge, publish,
8 | * distribute, sublicense, and/or sell copies of the Software, and to
9 | * permit persons to whom the Software is furnished to do so, subject to
10 | * the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be
13 | * included in all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 | * OTHER DEALINGS IN THE SOFTWARE.
22 | */
23 |
24 | package com.voltdb.test.typetest.proc;
25 |
26 | import java.math.BigDecimal;
27 | import java.math.MathContext;
28 |
29 | import org.voltdb.ProcInfo;
30 |
31 | @ProcInfo (partitionInfo = "typetest.test_id:0", singlePartition = true)
32 | public class InitTestType extends Insert {
33 |
34 | public long run(int blah) {
35 | return super.run(0, (byte)1, (short)2, 3, 4l, 5.1d, new BigDecimal(6.000342d,MathContext.DECIMAL32),
36 | "seven",
37 | new byte[] { (byte)8, (byte)8, (byte)8, (byte)8},
38 | 1331310436605000l);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Thank you for your interest in contributing. VoltDB uses GitHub to manage reviews of pull requests. We welcome your contributions to VoltDB or to any of the related libraries and tools.
4 |
5 | VoltDB uses the standard github workflow, meaning we make use of forking and pull requests.
6 |
7 | * If you have a trivial fix or improvement, go ahead and create a pull request.
8 |
9 | * If you are interested in contributing something more involved, feel free to discuss your ideas in [VoltDB Public](http://chat.voltdb.com/) on Slack.
10 |
11 | ## Contributor License Agreement
12 |
13 | In order to contribute code to VoltDB, you must first sign the [VoltDB Contributor License Agreement (CLA)](https://www.voltdb.com/contributor-license-agreement/) and email an image or PDF of the document including your hand-written signature to [support@voltdb.com](mailto:support@voltdb.com). VoltDB will sign and return the final copy of the agreement for your records.
14 |
15 | ## How to submit code
16 |
17 | The workflow is essentially the following:
18 |
19 | 1. Fork the VoltDB project
20 | 2. Make a branch. Commit your changes to this branch. (See note below)
21 | 3. Issue a pull request on the VoltDB repository.
22 |
23 | Once you have signed the CLA, a VoltDB engineer will review your pull request.
24 |
25 | Note:
26 |
27 | It will be easier to keep your work merge-able (conflict-free) if you don't work directly on your master branch in your VoltDB fork. Rather, keep your master branch in sync with the VoltDB repository and apply your changes on a branch of your fork.
28 |
29 | For further reading:
30 |
31 | * [How to fork a GitHub repository](https://help.github.com/articles/fork-a-repo)
32 | * [Using pull requests](https://help.github.com/articles/using-pull-requests/)
33 |
34 | ## Additional Resources
35 |
36 | * [VoltDB Wiki](https://github.com/VoltDB/voltdb/wiki) on Github
37 | * [VoltDB Public](http://chat.voltdb.com/) on Slack
38 | * [VoltDB Community Forum](https://forum.voltdb.com/)
39 |
--------------------------------------------------------------------------------
/test/util/test-context.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Manages the "context" of a test run, which basically means how the tests interact with the outside world. This
3 | * includes things like whether the Volt instance being tested against is a local instance or running in a Docker
4 | * container etc.
5 | *
6 | */
7 | !(function(global) { // eslint-disable-line no-unused-vars
8 |
9 | "use strict";
10 |
11 | const yargs = require("yargs");
12 | const dockerUtil = require("../util/docker-util");
13 |
14 | const VOLT_CONTAINER_NAME = "node1";
15 |
16 | // TODO: Should eventually go in VoltConstants.
17 | const VOLT_CLIENT_PORT = 21212;
18 |
19 | const config = {
20 | instance: null
21 | };
22 |
23 | /**
24 | * Configures the context for a test run. Currently loads this from cli options but could be
25 | * set with a file, env variables, etc.
26 | */
27 | function _setup(){
28 |
29 | var argv = yargs
30 | .alias("i", "instance")
31 | .demandOption(["i"])
32 | .describe("i", "Specify the type of VoltDB instance the tests will be run against. " +
33 | "Can be a local instance [local] or a local instance running in a Docker container [docker]")
34 | .choices("i", ["local", "docker"])
35 | .argv;
36 |
37 | config.instance = argv.instance;
38 | }
39 |
40 |
41 | /**
42 | * Based on config passed, figures out whether to use the default Volt port or
43 | * look for a Docker container running Volt to run the tests against.
44 | */
45 | function _port(){
46 |
47 | var voltPort = -1;
48 |
49 | if(config.instance === "local"){
50 | voltPort = VOLT_CLIENT_PORT;
51 | }
52 | else if(config.instance === "docker"){
53 | voltPort = dockerUtil.getExposedVoltPort(VOLT_CONTAINER_NAME);
54 | }
55 | else{
56 | // This should be caught by arg parser, but we throw here to be cautious
57 | throw new Error(`Unrecognised instance mode ${config.instance}`);
58 | }
59 |
60 | return voltPort;
61 | }
62 |
63 | //Exports
64 | module.exports = {
65 | setup : _setup,
66 | port: _port
67 | };
68 |
69 | }(this));
--------------------------------------------------------------------------------
/test/testrunner.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining
5 | * a copy of this software and associated documentation files (the
6 | * "Software"), to deal in the Software without restriction, including
7 | * without limitation the rights to use, copy, modify, merge, publish,
8 | * distribute, sublicense, and/or sell copies of the Software, and to
9 | * permit persons to whom the Software is furnished to do so, subject to
10 | * the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be
13 | * included in all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 | * OTHER DEALINGS IN THE SOFTWARE.
22 | */
23 |
24 | var nodeunit = require('nodeunit');
25 | var fs = require('fs');
26 | var child_process = require('child_process');
27 | const path = require('path');
28 |
29 | const testCasesDirectory = path.resolve(__dirname, "cases");
30 |
31 | var TestRunner = function() {
32 | this.testDirectories = [testCasesDirectory];
33 | this.fileList = [];
34 | }
35 | tr = TestRunner.prototype;
36 |
37 | tr.loadTests = function() {
38 | console.log(this.testDirectories.length);
39 | for(var index = 0; index < this.testDirectories.length; index++) {
40 | var cases = fs.readdirSync(this.testDirectories[index]) || [];
41 |
42 | for(var inner = 0; inner < cases.length; inner++) {
43 | this.fileList = this.fileList.concat(this.testDirectories[index] + '/' + cases[inner]);
44 | }
45 | }
46 | }
47 |
48 | tr.run = function() {
49 | var reporter = nodeunit.reporters.default;
50 | reporter.run(this.fileList, null, function something() {
51 | process.exit(0);
52 | });
53 | }
54 | function main() {
55 | var runner = new TestRunner();
56 | runner.loadTests();
57 | runner.run();
58 | };
59 |
60 | main();
61 |
--------------------------------------------------------------------------------
/tools/testdb/src/com/voltdb/test/typetest/proc/Insert.java:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining
5 | * a copy of this software and associated documentation files (the
6 | * "Software"), to deal in the Software without restriction, including
7 | * without limitation the rights to use, copy, modify, merge, publish,
8 | * distribute, sublicense, and/or sell copies of the Software, and to
9 | * permit persons to whom the Software is furnished to do so, subject to
10 | * the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be
13 | * included in all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 | * OTHER DEALINGS IN THE SOFTWARE.
22 | */
23 | package com.voltdb.test.typetest.proc;
24 |
25 | import java.math.BigDecimal;
26 |
27 | import org.voltdb.*;
28 | import org.voltdb.types.TimestampType;
29 |
30 | @ProcInfo (
31 | partitionInfo = "typetest.test_id:0",
32 | singlePartition = true)
33 | public class Insert extends VoltProcedure {
34 |
35 | public static final long SUCCESS = 0;
36 |
37 | public final SQLStmt insertStmt = new SQLStmt(
38 | "insert into typetest "
39 | /*+ " ( test_id"
40 | + ",test_tiny"
41 | + ",test_small"
42 | + ",test_integer"
43 | + ",test_big"
44 | + ",test_float"
45 | + ",test_decimal"
46 | + ",test_varchar"
47 | + ",test_varbinary"
48 | + ",test_timestamp )" */
49 | + " values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? );");
50 |
51 | public long run( int id, byte tiny, short small,
52 | int integer, long big, double dbl, BigDecimal decimal,
53 | String str, byte[] ba, long timestamp ) throws VoltAbortException {
54 |
55 | voltQueueSQL( insertStmt, id, tiny, small, integer, big, dbl, decimal,
56 | str, ba, timestamp );
57 |
58 | voltExecuteSQL();
59 | return Insert.SUCCESS;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/tools/testdb/run.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | function help() {
4 | echo "Usage: ./run.sh {clean|catalog|server}"
5 | }
6 |
7 | if [ -z "$VOLTDB_HOME" ]
8 | then
9 | echo "VOLTDB_HOME must be set";
10 | help
11 | exit 1
12 | else
13 | APPNAME="typetest"
14 | CLASSPATH="`ls -x $VOLTDB_HOME/voltdb/voltdb-*.jar | tr '[:space:]' ':'``ls -x $VOLTDB_HOME/lib/*.jar | tr '[:space:]' ':'`"
15 | VOLTDB="$VOLTDB_HOME/bin/voltdb"
16 | VOLTCOMPILER="$VOLTDB_HOME/bin/voltcompiler"
17 | LICENSE="$VOLTDB_HOME/voltdb/license.xml"
18 | LEADER="localhost"
19 | fi
20 |
21 | # remove build artifacts
22 | function clean() {
23 | rm -rf obj debugoutput $APPNAME.jar voltdbroot plannerlog.txt voltdbroot
24 | }
25 |
26 | # compile the source code for procedures and the client
27 | function srccompile() {
28 | mkdir -p obj
29 | javac -classpath $CLASSPATH -d obj \
30 | -sourcepath ./src \
31 | ./src/com/voltdb/test/typetest/proc/*.java
32 | jar cvf $APPNAME.jar -C obj .
33 | # stop if compilation fails
34 | if [ $? != 0 ]; then exit; fi
35 | }
36 |
37 | # build an application catalog
38 | function catalog() {
39 | srccompile
40 |
41 | # stop if compilation fails
42 | if [ $? != 0 ]; then exit; fi
43 | }
44 |
45 | # run the voltdb server locally
46 | function server() {
47 | # if a catalog doesn't exist, build one
48 | if [ ! -f $APPNAME.jar ]; then catalog; fi
49 |
50 | DOCKER_QUERY=`docker port node1 21212`
51 | if [ $? -eq 0 ]; then
52 | PORT=`echo ${DOCKER_QUERY} | cut -d: -f2`
53 | # Found a Docker container running Volt, load the procs into the db
54 | echo "Found local Docker container running Volt, loading schema"
55 | echo "load classes typetest.jar;" | sqlcmd --port=$PORT
56 | echo "file ddl-drop.sql;" | sqlcmd --port=$PORT
57 | echo "file ddl.sql;" | sqlcmd --port=$PORT
58 | else
59 | # No Docker container running Volt, start a local instance if we can
60 | echo "Could not find local Docker container running Volt, starting local instance with schema"
61 | # run the server
62 | $VOLTDB init -C deployment.xml -f -j $APPNAME.jar -s ddl.sql
63 | $VOLTDB start
64 | fi
65 | }
66 |
67 | # Run the target passed as the first arg on the command line
68 | # If no first arg, run server
69 | if [ $# -gt 1 ]; then help; exit; fi
70 | if [ $# = 1 ]; then $1; else server; fi
--------------------------------------------------------------------------------
/lib/query.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * This file contains original code and/or modifications of original code.
5 | * Any modifications made by VoltDB Inc. are licensed under the following
6 | * terms and conditions:
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining
9 | * a copy of this software and associated documentation files (the
10 | * "Software"), to deal in the Software without restriction, including
11 | * without limitation the rights to use, copy, modify, merge, publish,
12 | * distribute, sublicense, and/or sell copies of the Software, and to
13 | * permit persons to whom the Software is furnished to do so, subject to
14 | * the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be
17 | * included in all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | * OTHER DEALINGS IN THE SOFTWARE.
26 | */
27 |
28 | var EventEmitter = require('events').EventEmitter;
29 | var Message = require('./message').Message;
30 | VoltQuery = function(procName, types) {
31 | this.procName = procName;
32 | this.types = types || [];
33 | this.parameters = [];
34 | this.uid = null;
35 | }
36 |
37 | VoltQuery.prototype.setParameters = function(params) {
38 | this.parameters = params;
39 | }
40 |
41 | VoltQuery.prototype.setUID = function(uid) {
42 | this.uid = uid;
43 | }
44 |
45 | VoltQuery.prototype.getMessage = function() {
46 | var message = new Message();
47 | message.writeString(this.procName);
48 | message.writeBinary(new Buffer(this.uid));
49 | message.writeParameterSet(this.types, this.parameters);
50 | return message;
51 | }
52 | VoltProcedure = function(name, types) {
53 | this.name = name;
54 | this.types = types;
55 | }
56 |
57 | VoltProcedure.prototype.getQuery = function() {
58 | return new VoltQuery(this.name, this.types);
59 | }
60 |
61 | module.exports = VoltQuery;
62 | //remove
63 | module.exports = VoltProcedure;
64 |
--------------------------------------------------------------------------------
/test/util/docker-util.js:
--------------------------------------------------------------------------------
1 | !(function(global) { // eslint-disable-line no-unused-vars
2 |
3 | "use strict";
4 |
5 | const childProcess = require("child_process");
6 | const debug = require("debug")("voltdb-client-nodejs:DockerUtil");
7 | const os = require('os');
8 |
9 | /*
10 | * TODO: Should eventually go in VoltConstants.
11 | */
12 | const VOLT_CLIENT_PORT = 21212;
13 |
14 | /*
15 | * Looks for a docker container with the given name on the local machine and finds
16 | * which port the container's 21212 port has been exposed on. Intended to be used
17 | * with the localhostcluster docker containers defined in the main volt repository.
18 | *
19 | * NOTE: This won't fail if no exposed port can be found, either because of a command
20 | * failure or if there is no docker container running Volt, it will just print a warning
21 | * and return the default Volt client port.
22 | */
23 | function _getExposedVoltPort(containerName) {
24 |
25 | var clientPort = VOLT_CLIENT_PORT;
26 |
27 | /*
28 | * "docker port node1 21212" will return something like this "0.0.0.0:33164". Just parse out the port at the end.
29 | */
30 | const command = "docker";
31 | const args = ["port", containerName, VOLT_CLIENT_PORT];
32 | const dockerPortResponse = childProcess.spawnSync(command, args);
33 | if(dockerPortResponse.status !== 0){
34 | // Failure, log a warning and just fall through, returning the default port
35 | console.warn(`Docker port query failure | Will return default port '${VOLT_CLIENT_PORT}'. \
36 | Docker port query for container '${containerName}' and port '${VOLT_CLIENT_PORT}' failed, error was:${os.EOL} \
37 | ${dockerPortResponse.stderr.toString()}`);
38 | }
39 | else{
40 | // Success
41 | const dockerPortResponseString = dockerPortResponse.stdout.toString();
42 | const dockerPortResponseArray = dockerPortResponseString.replace("\n", "").replace("\r", "").split(":");
43 | if(dockerPortResponseArray.length === 2){
44 | debug("Container Found | Name: %o, Client Port: %o, Exposed Client Port: %o ", containerName, VOLT_CLIENT_PORT, clientPort);
45 | clientPort = parseInt(dockerPortResponseArray[1]);
46 | }
47 | else{
48 | // Failure, log a warning and just fall through, returning the default port
49 | console.warn(`Docker port query failure | Will return default port '${VOLT_CLIENT_PORT}'. \
50 | Docker port query for container '${containerName}' and port '${VOLT_CLIENT_PORT}' returned unrecognised response, response was:${os.EOL} \
51 | ${dockerPortResponseString}`);
52 | }
53 | }
54 |
55 | return clientPort;
56 | }
57 |
58 | // Exports
59 | module.exports = {
60 | getExposedVoltPort : _getExposedVoltPort
61 | };
62 |
63 | }(this));
64 |
--------------------------------------------------------------------------------
/test/cases/connections.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining
5 | * a copy of this software and associated documentation files (the
6 | * "Software"), to deal in the Software without restriction, including
7 | * without limitation the rights to use, copy, modify, merge, publish,
8 | * distribute, sublicense, and/or sell copies of the Software, and to
9 | * permit persons to whom the Software is furnished to do so, subject to
10 | * the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be
13 | * included in all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 | * OTHER DEALINGS IN THE SOFTWARE.
22 | */
23 |
24 | var VoltClient = require('../../lib/client');
25 | var VoltConfiguration = require('../../lib/configuration');
26 | var util = require('util');
27 | var testCase = require('nodeunit');
28 | const testContext = require("../util/test-context");
29 | const debug = require("debug")("voltdb-client-nodejs:ConnectionsTest");
30 |
31 | // Setup context
32 | testContext.setup();
33 |
34 | function goodConfig() {
35 | return config('localhost');
36 | }
37 |
38 | function badConfig() {
39 | return config('idontexist');
40 | }
41 |
42 | function config(host) {
43 | debug('this config got called');
44 | var config = new VoltConfiguration();
45 | config.host = host;
46 | config.port = testContext.port();
47 | var configs = [];
48 | configs.push(config);
49 | return configs;
50 | }
51 |
52 | exports.connections = {
53 |
54 | setUp : function(callback) {
55 | debug('connections setup called');
56 | callback();
57 | },
58 | tearDown : function(callback) {
59 | debug('connections teardown called');
60 | callback();
61 | },
62 | 'Bad connection results' : function(test) {
63 | debug('running bad connection test');
64 | var client = new VoltClient(badConfig())
65 | client.connect(function startup(code, event, results) {
66 | debug('bad connection test');
67 | test.expect(1);
68 | test.notEqual(code, null, 'There should not be a host named idontexists');
69 | client.exit();
70 | test.done();
71 | });
72 | },
73 | 'Good connection results' : function(test) {
74 | debug('running good connection test');
75 | var client = new VoltClient(goodConfig())
76 | client.connect(function startup(code, event, results) {
77 | test.expect(1);
78 | test.equal(code, null, 'Should have been able to connect, is Volt running on localhost?');
79 | client.exit();
80 | test.done();
81 | });
82 | }
83 | };
84 |
--------------------------------------------------------------------------------
/examples/voter/voter/app.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining
5 | * a copy of this software and associated documentation files (the
6 | * "Software"), to deal in the Software without restriction, including
7 | * without limitation the rights to use, copy, modify, merge, publish,
8 | * distribute, sublicense, and/or sell copies of the Software, and to
9 | * permit persons to whom the Software is furnished to do so, subject to
10 | * the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be
13 | * included in all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 | * OTHER DEALINGS IN THE SOFTWARE.
22 | */
23 |
24 | /*
25 | * This version of the sample requires that you have the VoltDB server installed
26 | * and running the voter example database.
27 | *
28 | * This sample will spawn a number( equal to the number of cores divided by 2)
29 | * of cluster nodes that will add votes to a collection of candidates.
30 | * The main cluster node will act as the web server.
31 | *
32 | * Please see the ./modules/volt.js file for a detailed explanation of the
33 | * client code.
34 | */
35 |
36 | var express = require('express'),
37 | routes = require('./routes'), volt = require('./models/volt'),
38 | votes = require('./jsons/votes'), util = require('util'),
39 | cluster = require('cluster'), numCPUs = require('os').cpus().length;
40 |
41 | function webserverProcess() {
42 | var app = module.exports = express.createServer();
43 |
44 | // Configuration
45 |
46 | app.configure(function() {
47 | app.set('views', __dirname + '/views');
48 | app.set('view engine', 'jade');
49 | app.use(express.bodyParser());
50 | app.use(express.methodOverride());
51 | app.use(app.router);
52 | app.use(express.static(__dirname + '/public'));
53 | });
54 |
55 | app.configure('production', function() {
56 | app.use(express.errorHandler({
57 | dumpExceptions : true,
58 | showStack : true
59 | }));
60 | });
61 |
62 | app.configure('production', function() {
63 | app.use(express.errorHandler());
64 | });
65 | // Routes
66 | app.get('/', routes.index);
67 | app.get('/results', votes.votes);
68 |
69 | app.listen(3000);
70 |
71 | util.log(util.format("Express server listening on port %d in %s mode",
72 | app.address().port, app.settings.env));
73 | }
74 |
75 | function startup() {
76 | if(cluster.isMaster) {
77 | numCPUs /=2;
78 | // TODO: Add command line to override whatever numCPUs is set to so we don't
79 | // use all the cores.
80 | util.log("Using CPUs: " + numCPUs);
81 | for(var i = 0; i < (numCPUs); i++) {
82 | cluster.fork();
83 | }
84 | volt.initClient(false);
85 | webserverProcess();
86 | } else {
87 | volt.initClient(true);
88 | }
89 | }
90 |
91 | startup();
92 |
--------------------------------------------------------------------------------
/test/cases/typestest.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining
5 | * a copy of this software and associated documentation files (the
6 | * "Software"), to deal in the Software without restriction, including
7 | * without limitation the rights to use, copy, modify, merge, publish,
8 | * distribute, sublicense, and/or sell copies of the Software, and to
9 | * permit persons to whom the Software is furnished to do so, subject to
10 | * the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be
13 | * included in all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 | * OTHER DEALINGS IN THE SOFTWARE.
22 | */
23 |
24 | // TODO: Remove a lot of the console/util logging statements being used for
25 | // debugging purposes.
26 |
27 | var VoltClient = require('../../lib/client');
28 | var VoltConfiguration = require('../../lib/configuration');
29 | var VoltProcedure = require('../../lib/query');
30 | var VoltQuery = require('../../lib/query');
31 | const debug = require("debug")("voltdb-client-nodejs:TypeTest");
32 |
33 | var util = require('util');
34 | const testContext = require("../util/test-context");
35 | var testCase = require('nodeunit');
36 |
37 | //Setup context
38 | testContext.setup();
39 |
40 | var client = null;
41 | var initProc = new VoltProcedure('InitTestType', ['int']);
42 |
43 | function config() {
44 | var config = new VoltConfiguration();
45 | config.host = 'localhost';
46 | const voltPort = testContext.port();
47 | config.port = voltPort;
48 | var configs = [];
49 | configs.push(config);
50 | return configs;
51 | }
52 |
53 | exports.typetest = {
54 |
55 | setUp : function(callback) {
56 | debug('typetest setup called');
57 | client = new VoltClient(config());
58 | client.connect(function startup(code, event, results) {
59 | debug('dasda connected');
60 | callback();
61 | });
62 | },
63 | tearDown : function(callback) {
64 | debug('typetest teardown called');
65 | client.exit();
66 | callback();
67 | },
68 | 'Init test' : function(test) {
69 | debug('init test');
70 | test.expect(2);
71 |
72 | var initProc = new VoltProcedure('InitTestType', ['int']);
73 | var query = initProc.getQuery();
74 | query.setParameters([0]);
75 |
76 | client.callProcedure(query, function read(code, event, results) {
77 | debug('results %o', results);
78 | test.equals(code, null , 'did I get called');
79 | test.done();
80 | }, function write(code, event, results) {
81 | test.equals(code, null, 'Write didn\'t had an error');
82 | debug('write ok');
83 | });
84 | },
85 | 'select test' : function(test) {
86 | debug('select test');
87 | test.expect(11);
88 |
89 | var initProc = new VoltProcedure('TYPETEST.select', ['int']);
90 | var query = initProc.getQuery();
91 | query.setParameters([0]);
92 |
93 | client.callProcedure(query, function read(code, event, results) {
94 |
95 | var testBuffer = new Buffer(4);
96 | debug('results inspection: %o', results.table[0][0].TEST_TIMESTAMP);
97 | debug('inspect %s', util.inspect(results.table[0][0]));
98 |
99 | test.equals(code, null, 'Invalid status: ' + results.status + 'should be 1');
100 |
101 | test.equals(results.table[0][0].TEST_ID, 0, 'Wrong row ID, should be 0');
102 | test.equals(results.table[0][0].TEST_TINY, 1, 'Wrong tiny, should be 1');
103 | test.equals(results.table[0][0].TEST_SMALL, 2, 'Wrong small, should be 2');
104 | test.equals(results.table[0][0].TEST_INTEGER, 3, 'Wrong integer, should be 3');
105 | test.equals(results.table[0][0].TEST_BIG, 4, 'Wrong integer, should be 4');
106 | test.equals(results.table[0][0].TEST_FLOAT, 5.1, 'Wrong float, should be 5.1');
107 | test.equals(results.table[0][0].TEST_DECIMAL, 6.000342, 'Wrong decimal, should be 6.000342');
108 | test.equals(results.table[0][0].TEST_VARCHAR, 'seven', 'Wrong varchar, should be seven');
109 | // TODO: Add varbinary buffer comparison code.
110 | //test.equals(results.table[0][0].TEST_VARBINARY, 6.00034231,
111 | // results.table[0][0].TEST_VARBINARY);
112 | test.equals(results.table[0][0].TEST_TIMESTAMP.getTime(), (new Date(1331310436605)).getTime(), (new Date(1331310436605)).toString() + ": " + results.table[0][0].TEST_TIMESTAMP);
113 |
114 | test.done();
115 | }, function write(code, event, results) {
116 | debug('write ok');
117 | test.ok(true, 'Write didn\'t get called');
118 | });
119 | }
120 | };
121 |
--------------------------------------------------------------------------------
/lib/voltconstants.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * This file contains original code and/or modifications of original code.
5 | * Any modifications made by VoltDB Inc. are licensed under the following
6 | * terms and conditions:
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining
9 | * a copy of this software and associated documentation files (the
10 | * "Software"), to deal in the Software without restriction, including
11 | * without limitation the rights to use, copy, modify, merge, publish,
12 | * distribute, sublicense, and/or sell copies of the Software, and to
13 | * permit persons to whom the Software is furnished to do so, subject to
14 | * the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be
17 | * included in all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | * OTHER DEALINGS IN THE SOFTWARE.
26 | */
27 |
28 | /**
29 | * Message object constants used only when encoding/decoding a message
30 | * between the client and server.
31 | *
32 | */
33 | var MESSAGE_TYPE = {
34 | UNDEFINED : -1,
35 | LOGIN : 1,
36 | QUERY : 2
37 | };
38 |
39 | var PRESENT = {
40 | STATUS : 0x20,
41 | EXCEPTION : 0x40,
42 | APP_STATUS : 0x80
43 | };
44 |
45 |
46 | /**
47 | * Top level event types for all operations. All events have at least the
48 | * SESSION_EVENT type and STATUS_CODE.
49 | * CONNECT: A successful connection to the volt server
50 | * CONNECTION_ERROR: Could not connect, see both the status code and
51 | * the event handler's message parameter.
52 | * QUERY_RESPONSE: Query executed and returned
53 | * QUERY_ALLOWED: Indicates that the application may execute another query.
54 | * Note that this prevents your application from flooding the database and
55 | * the application's code from blocking.
56 | * QUERY_RESPONSE_ERROR: The query was successfully dispatched but the
57 | * VoltDB server either had a critical fault or lost the connection.
58 | * QUERY_DISPATCH_ERROR: The client could not dispatch the query.
59 | * FATAL_ERROR: A critical error occurred that was above and beyond all
60 | * other error conditions.
61 | */
62 | var SESSION_EVENT = {
63 | CONNECTION : 'CONNECT',
64 | CONNECTION_ERROR: 'CONNECT_ERROR',
65 | QUERY_RESPONSE: 'QUERY_RESPONSE',
66 | QUERY_ALLOWED: 'QUERY_ALLOWED',
67 | QUERY_RESPONSE_ERROR: 'QUERY_RESPONSE_ERROR',
68 | QUERY_DISPATCH_ERROR: 'QUERY_DISPATCH_ERROR',
69 | FATAL_ERROR: 'FATAL_ERROR'
70 | }
71 |
72 | /**
73 | * Each SESSION_EVENT has a STATUS_CODE giving some indication why the
74 | * operation failed.
75 | *
76 | * SUCCESS: Operation succeeded.
77 | * USER_ABORT: The user's stored procedure intentionally threw an exception
78 | * of type UserAbortException
79 | * GRACEFUL_FAILURE: Query had an error that rolled back the transaction.
80 | * UNEXPECTED_FAILURE: Query had an error, rolled back the transaction
81 | * and caused additional errors.
82 | * CONNECTION_LOST: The connection to VoltDB was lost before
83 | * the query returned. This is not issued by the server, but is issued
84 | * by the client.'
85 | * SERVER_UNAVAILABLE: Attempted to use an invalid connection.
86 | * CONNECTION_TIMEOUT: The server stopped replying.
87 | * QUERY_TIMEOUT: The server issues a message saying that the query took
88 | * too long to execute.
89 | * QUERY_TOOK_TOO_LONG: Driver issued message indicating that the server
90 | * has taken too long to respond.
91 | */
92 | var STATUS_CODES = {
93 | SUCCESS : null,
94 | USER_ABORT : -1,
95 | GRACEFUL_FAILURE : -2,
96 | UNEXPECTED_FAILURE : -3,
97 | CONNECTION_LOST : -4,
98 | SERVER_UNAVAILABLE : -5,
99 | CONNECTION_TIMEOUT : -6,
100 | QUERY_TIMEOUT : -7,
101 | QUERY_TOOK_TOO_LONG : -8
102 | };
103 |
104 | var STATUS_CODE_STRINGS = {
105 | 1 : 'SUCCESS',
106 | '-1' : 'USER_ABORT',
107 | '-2' : 'GRACEFUL_FAILURE',
108 | '-3' : 'UNEXPECTED_FAILURE',
109 | '-4' : 'CONNECTION_LOST',
110 | '-5' : 'SERVER_UNAVAILABLE',
111 | '-6' : 'CONNECTION_LOST',
112 | '-7' : 'QUERY_TIMEOUT',
113 | '-8' : 'QUERY_TOOK_TOO_LONG'
114 | };
115 |
116 | var LOGIN_ERRORS = {
117 | 1 : 'Too many connections',
118 | 2 : 'Authentication failed, client took too long to transmit credentials',
119 | 3 : 'Corrupt or invalid login message'
120 | };
121 |
122 | exports.PRESENT = PRESENT;
123 | exports.LOGIN_ERRORS = LOGIN_ERRORS;
124 | exports.SESSION_EVENT = SESSION_EVENT;
125 | exports.STATUS_CODE_STRINGS = STATUS_CODE_STRINGS;
126 | exports.STATUS_CODES = STATUS_CODES;
127 | exports.MESSAGE_TYPE = MESSAGE_TYPE;
--------------------------------------------------------------------------------
/lib/message.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * This file contains original code and/or modifications of original code.
5 | * Any modifications made by VoltDB Inc. are licensed under the following
6 | * terms and conditions:
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining
9 | * a copy of this software and associated documentation files (the
10 | * "Software"), to deal in the Software without restriction, including
11 | * without limitation the rights to use, copy, modify, merge, publish,
12 | * distribute, sublicense, and/or sell copies of the Software, and to
13 | * permit persons to whom the Software is furnished to do so, subject to
14 | * the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be
17 | * included in all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | * OTHER DEALINGS IN THE SOFTWARE.
26 | */
27 | var Parser = require('./parser').Parser,
28 | util = require('util'),
29 | PRESENT = require('./voltconstants').PRESENT,
30 | MESSAGE_TYPE = require('./voltconstants').MESSAGE_TYPE,
31 | STATUS_CODE_STRINGS = require('./voltconstants').STATUS_CODE_STRINGS,
32 | STATUS_CODES = require('./voltconstants').STATUS_CODES;
33 |
34 | function Message(buffer) {
35 | this.type = MESSAGE_TYPE.UNDEFINED;
36 | this.error = false;
37 | Parser.call(this, buffer);
38 | if(!buffer) {
39 | this.writeInt(0);
40 | this.writeByte(0);
41 | } else {
42 | this.readHeader();
43 | }
44 | }
45 |
46 | Message.prototype = Object.create(Parser.prototype);
47 |
48 | Message.prototype.readHeader = function() {
49 | this.length = this.readInt();
50 | this.protocol = this.readByte();
51 | };
52 |
53 | Message.prototype.writeHeader = function() {
54 | var pos = this.position;
55 | this.position = 0;
56 | this.writeInt(this.buffer.length - 4);
57 | this.writeByte(0);
58 | this.position = pos;
59 | };
60 |
61 | Message.prototype.toBuffer = function() {
62 | this.writeHeader();
63 | return new Buffer(this.buffer);
64 | };
65 | // for getting lengths from incoming data
66 | Message.readInt = function(buffer, offset) {
67 | return Parser.readInt(buffer, offset);
68 | };
69 | LoginMessage = function(buffer) {
70 | Message.call(this, buffer);
71 | this.type = MESSAGE_TYPE.LOGIN;
72 | this.status = this.readByte();
73 | this.error = (this.status === 0 ? false : true );
74 | if(this.error === false) {
75 | this.serverId = this.readInt();
76 | this.connectionId = this.readLong();
77 | this.clusterStartTimestamp = new Date(parseInt(this.readLong().toString()));
78 | // not microseonds, milliseconds
79 | this.leaderIP = this.readByte() + '.' + this.readByte() + '.' + this.readByte() + '.' + this.readByte();
80 | this.build = this.readString();
81 | }
82 | }
83 |
84 | util.inherits(LoginMessage, Message);
85 |
86 | var lm = LoginMessage.prototype;
87 | lm.toString = function() {
88 | return {
89 | length : this.length,
90 | protocol : this.protocol,
91 | status : this.status,
92 | error : this.error,
93 | serverId : this.serverId,
94 | connectionId : this.connectionId,
95 | clusterStartTimestamp : this.clusterStartTimestamp,
96 | leaderIP : this.leaderIP,
97 | build : this.build
98 | };
99 | }
100 | QueryMessage = function(buffer) {
101 | Message.call(this, buffer);
102 | this.type = MESSAGE_TYPE.QUERY;
103 |
104 | this.uid = this.readBinary(8).toString();
105 | this.fieldsPresent = this.readByte();
106 | // bitfield, use PRESENT values to check
107 | this.status = this.readByte();
108 | this.statusString = STATUS_CODE_STRINGS[this.status];
109 | if(this.fieldsPresent & PRESENT.STATUS) {
110 | this.statusString = this.readString();
111 | }
112 | this.appStatus = this.readByte();
113 | this.appStatusString = '';
114 | if(this.fieldsPresent & PRESENT.APP_STATUS) {
115 | this.appStatusString = this.readString();
116 | }
117 | this.exception
118 | this.exceptionLength = this.readInt();
119 | if(this.fieldsPresent & PRESENT.EXCEPTION) {
120 | this.exception = this.readException(1);
121 | // seems size doesn't matter, always 1
122 | } else {
123 | // don't parse the rest if there was an exception. Bad material there.
124 | var resultCount = this.readShort();
125 | // there can be more than one table with rows
126 | this.table = new Array(resultCount);
127 | for(var i = 0; i < resultCount; i++) {
128 | this.table[i] = this.readVoltTable();
129 | }
130 |
131 | }
132 | }
133 |
134 | util.inherits(QueryMessage, Message);
135 |
136 | var qm = QueryMessage.prototype;
137 |
138 | qm.toString = function() {
139 | return {
140 | length : this.length,
141 | protocol : this.protocol,
142 | status : this.status,
143 | error : this.error,
144 | uid : this.uid,
145 | fieldsPresent : this.fieldsPresent,
146 | status : this.status,
147 | statusString : this.statusString,
148 | appStatus : this.appStatus,
149 | appStatusString : this.appStatusString,
150 | exception : this.exception,
151 | exceptionLength : this.exceptionLength,
152 | results : this.results
153 | };
154 | }
155 | exports.Message = Message;
156 | exports.LoginMessage = LoginMessage;
157 | exports.QueryMessage = QueryMessage;
158 |
--------------------------------------------------------------------------------
/writer.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * This file contains original code and/or modifications of original code.
5 | * Any modifications made by VoltDB Inc. are licensed under the following
6 | * terms and conditions:
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining
9 | * a copy of this software and associated documentation files (the
10 | * "Software"), to deal in the Software without restriction, including
11 | * without limitation the rights to use, copy, modify, merge, publish,
12 | * distribute, sublicense, and/or sell copies of the Software, and to
13 | * permit persons to whom the Software is furnished to do so, subject to
14 | * the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be
17 | * included in all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | * OTHER DEALINGS IN THE SOFTWARE.
26 | */
27 |
28 | /*
29 | * Authors:
30 | * Andy Wilson [www.voltdb.com]
31 | * Henning Diedrich [www.eonblast.com]
32 | *
33 | */
34 |
35 | var os = require('os')
36 | var cli = require('cli');
37 | var util = require('util');
38 | var cluster = require('cluster');
39 | var VoltClient = require('./lib/client');
40 | var VoltProcedure = require('./lib/query');
41 | var VoltQuery = require('./lib/query');
42 |
43 | var numCPUs = os.cpus().length
44 | var logTag = "master "
45 |
46 | var client = null;
47 | var resultsProc = new VoltProcedure('Results');
48 | var initProc = new VoltProcedure('Initialize', ['int', 'string']);
49 | var writeProc = new VoltProcedure('Vote', ['long', 'int', 'long']);
50 | var throughput = 0;
51 |
52 | var options = cli.parse({
53 | loops : ['c', 'Number of loops to run', 'number', 10000],
54 | voltGate : ['h', 'VoltDB host (any if multi-node)', 'string', 'localhost'],
55 | workers : ['f', 'client worker forks', 'number', numCPUs],
56 | verbose : ['v', 'verbose output'],
57 | debug : ['d', 'debug output']
58 | });
59 |
60 | var workers = options.workers;
61 | var vlog = options.verbose || options.debug ? log : function() {
62 | }
63 | var vvlog = options.debug ? log : function() {
64 | }
65 | var cargos = 'a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z';
66 |
67 | if(cluster.isMaster)
68 | master_main();
69 | else
70 | worker_main();
71 |
72 | function master_main() {
73 |
74 | log("-- Crude Forking Write Benchmark Client --")
75 |
76 | log("VoltDB host: " + options.voltGate);
77 | log("worker forks: " + workers);
78 |
79 | // fork workers
80 | for(var i = 0; i < workers; i++) {
81 | vvlog('forking worker #' + i)
82 | var worker = cluster.fork()
83 |
84 | // result counter
85 | worker.on('message', function(msg) {
86 | if(msg.cmd && msg.cmd == 'result') {
87 | throughput += msg.throughput
88 | }
89 | });
90 | }
91 |
92 | // track exits, print total
93 | var exited = 0;
94 | cluster.on('death', function(worker) {
95 | vlog('worker (pid ' + worker.pid + ') exits.')
96 | exited++;
97 | if(exited == workers) {
98 | log("Total: " + Math.round(throughput) + " TPS")
99 | }
100 | })
101 | }
102 |
103 | function worker_main() {
104 | logTag = 'worker ' + process.env.NODE_WORKER_ID
105 | vvlog('worker main')
106 |
107 | // define and start a Volt client
108 | client = new VoltClient([{
109 | host : options.voltGate,
110 | port : 21212,
111 | username : 'user',
112 | password : 'password',
113 | service : 'database',
114 | queryTimeout : 50000
115 |
116 | }]);
117 | client.connect(function startup(results) {
118 | vvlog('Node up');
119 | voltInit();
120 | }, function loginError(results) {
121 | vvlog('Node up (on Error)');
122 | voltInit();
123 | });
124 | vvlog('connected')
125 | }
126 |
127 | function voltInit() {
128 | vvlog('voltInit');
129 | var query = initProc.getQuery();
130 | query.setParameters([cargos.length, cargos]);
131 | client.call(query, function initWriter(results) {
132 | var job = {
133 | loops : options.loops,
134 | steps : getSteps()
135 | };
136 | step(job);
137 | });
138 | }
139 |
140 | function getSteps() {
141 | var steps = [];
142 | steps.push(writeResults);
143 | steps.push(writeInsertLoop);
144 | steps.push(writeResults);
145 | steps.push(writeEnd);
146 | return steps;
147 | }
148 |
149 | function writeResults(job) {
150 | vvlog('writeResults');
151 | var query = resultsProc.getQuery();
152 | client.call(query, function displayResults(results) {
153 | var mytotalwrites = 0;
154 | var msg = '';
155 | var longestString = 0;
156 | var rows = results.table[0];
157 | for(var i = 0; i < rows.length; i++) {
158 | mytotalwrites += rows[i].TOTAL_VOTES;
159 | msg += util.format("%s\t%d", rows[i].CONTESTANT_NUMBER, rows[i].TOTAL_VOTES);
160 | }
161 | // msg += util.format("%d writes", mytotalwrites);
162 | // log(msg);
163 | step(job);
164 | });
165 | }
166 |
167 | function connectionStats() {
168 | client.connectionStats();
169 | }
170 |
171 | function writeEnd(job) {
172 | client.connectionStats();
173 | vvlog('writeEnd');
174 | process.exit();
175 | }
176 |
177 | function getCandidate() {
178 | return Math.floor(Math.random() * cargos.length) + 1;
179 | }
180 |
181 | function writeInsertLoop(job) {
182 |
183 | var index = 0;
184 | var reads = job.loops;
185 | var startTime = new Date().getTime();
186 | var chunkTime = new Date().getTime();
187 | var doneWith = 0;
188 |
189 | var innerLoop = function() {
190 | var query = writeProc.getQuery();
191 | if(index < job.loops) {
192 |
193 | query.setParameters([getRand(1E6), getCandidate(), 200000]);
194 | client.call(query, function displayResults(results) {
195 | vvlog("reads ", reads);
196 | reads--;
197 | if(reads == 0) {
198 | logTime(startTime, job.loops, "Results");
199 | step(job);
200 | } else {
201 | vvlog("reads ", reads);
202 | }
203 | }, function readyToWrite() {
204 |
205 | if(index < job.loops) {
206 | if(index && index % 5000 == 0) {
207 | vlog('Executed ' + index + ' writes in ' + ((new Date().getTime()) - chunkTime) + 'ms ' + util.inspect(process.memoryUsage()));
208 | chunkTime = new Date().getTime();
209 | }
210 | index++;
211 | process.nextTick(innerLoop);
212 | } else {
213 | log(doneWith++, 'Time to stop voting: ', index);
214 | }
215 | });
216 | } else {
217 | vvlog('Index is: ' + index + ' and ' + job.loops);
218 | }
219 | };
220 | // void stack, yield
221 | process.nextTick(innerLoop);
222 |
223 | }
224 |
225 | function logTime(startTime, writes, typeString) {
226 |
227 | var endTimeMS = Math.max(1, new Date().getTime() - startTime);
228 | var throughput = writes * 1000 / endTimeMS;
229 |
230 | log(util.format('%d transactions in %d milliseconds.\n' + '%d transactions per second', writes, endTimeMS, throughput));
231 |
232 | process.send({
233 | cmd : 'result',
234 | throughput : throughput
235 | });
236 | }
237 |
238 | function step(job) {
239 |
240 | if(job.steps.length > 0) {
241 | var method = job.steps.shift();
242 | method(job);
243 | }
244 | }
245 |
246 | function log(tx) {
247 | tx = tx.replace(/\n/g, "\n" + logTag + ": ");
248 | console.log(logTag + ": " + tx);
249 | }
250 |
251 | function getRand(max) {
252 | return Math.floor(Math.random() * max);
253 | }
--------------------------------------------------------------------------------
/lib/client.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining
5 | * a copy of this software and associated documentation files (the
6 | * "Software"), to deal in the Software without restriction, including
7 | * without limitation the rights to use, copy, modify, merge, publish,
8 | * distribute, sublicense, and/or sell copies of the Software, and to
9 | * permit persons to whom the Software is furnished to do so, subject to
10 | * the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be
13 | * included in all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 | * OTHER DEALINGS IN THE SOFTWARE.
22 | */
23 |
24 | var EventEmitter = require('events').EventEmitter,
25 | util = require('util'),
26 | VoltConnection = require('./connection'),
27 | VoltConstants = require('./voltconstants');
28 | const debug = require("debug")("voltdb-client-nodejs:VoltClient");
29 |
30 | VoltClient = function(configuration) {
31 | EventEmitter.call(this);
32 |
33 | this.config = configuration;
34 |
35 | this.connect = this.connect.bind(this);
36 | this._getConnections = this.connect.bind(this);
37 | this.call = this.call.bind(this);
38 | this.callProcedure = this.callProcedure.bind(this);
39 | this.exit = this.exit.bind(this);
40 | this.connectionStats = this.connectionStats.bind(this);
41 |
42 | this._connectListener = this._connectListener.bind(this);
43 | this._connectErrorListener=this._connectErrorListener.bind(this);
44 | this._queryResponseListener=this._queryResponseListener.bind(this);
45 | this._queryResponseErrorListener=this._queryResponseErrorListener.bind(this);
46 | this._queryDispatchErrorListener=this._queryDispatchErrorListener.bind(this);
47 | this._fatalErrorListener=this._fatalErrorListener.bind(this);
48 |
49 | this._connections = [];
50 | this._badConnections = [];
51 | this._connectionCounter = 0;
52 | }
53 |
54 | util.inherits(VoltClient, EventEmitter);
55 |
56 | VoltClient.prototype.connect = function(callback) {
57 | var self = this;
58 |
59 | var connectionCount = this.config.length;
60 | var connectionResults = [];
61 | for(var index = 0; index < this.config.length; index++) {
62 | var con = new VoltConnection(this.config[index]);
63 |
64 | con.on(VoltConstants.SESSION_EVENT.CONNECTION,this._connectListener);
65 | con.on(VoltConstants.SESSION_EVENT.CONNECTION, callback);
66 | con.on(VoltConstants.SESSION_EVENT.CONNECTION_ERROR, callback);
67 | con.on(VoltConstants.SESSION_EVENT.QUERY_RESPONSE,this._queryResponseListener);
68 | con.on(VoltConstants.SESSION_EVENT.QUERY_RESPONSE_ERROR,this._queryResponseErrorListener);
69 | con.on(VoltConstants.SESSION_EVENT.QUERY_DISPATCH_ERROR,this._queryDispatchErrorListener);
70 | con.on(VoltConstants.SESSION_EVENT.FATAL_ERROR,this._fatalErrorListener);
71 |
72 | /**
73 | * Need to register the connection even before the socket connects otherwise
74 | * it can't be torn down in the event of a socket failure.
75 | */
76 | this._connections.push(con);
77 |
78 | con.connect();
79 | }
80 | }
81 |
82 | VoltClient.prototype._getConnection = function(callback) {
83 | var length = this._connections.length;
84 | var connection = null;
85 | for(var index = 0; index < length; index++) {
86 |
87 | // creates round robin
88 | this._connectionCounter++;
89 | if(this._connectionCounter >= length) {
90 | this._connectionCounter = 0;
91 | }
92 | connection = this._connections[this._connectionCounter];
93 | // validates that the connection is good and not blocked on reads
94 | if(connection == null || connection.isValidConnection() == false) {
95 | this._badConnections.push(connection);
96 | this._connections[this._connectionCounter] = null;
97 | } else if(connection.isBlocked() == false) {
98 | break;
99 | }
100 | }
101 | return connection;
102 | }
103 |
104 | VoltClient.prototype.callProcedure = function(query, readCallback, writeCallback) {
105 | var con = this._getConnection();
106 | if(con) {
107 | if(con.callProcedure(query, readCallback, writeCallback) == false) {
108 | this.emit(VoltConstants.SESSION_EVENT.CONNECTION_ERROR,
109 | VoltConstants.STATUS_CODES.CONNECTION_TIMEOUT,
110 | VoltConstants.SESSION_EVENT.CONNECTION_ERROR,
111 | 'Invalid connection in connection pool');
112 | }
113 |
114 | } else {
115 | this.emit(VoltConstants.SESSION_EVENT.CONNECTION_ERROR,
116 | VoltConstants.STATUS_CODES.CONNECTION_TIMEOUT,
117 | VoltConstants.SESSION_EVENT.CONNECTION_ERROR,
118 | 'No valid VoltDB connections, verify that the database is online');
119 | }
120 | }
121 |
122 | VoltClient.prototype.call = function(query, readCallback, writeCallback) {
123 | this.callProcedure(query, readCallback, writeCallback);
124 | }
125 |
126 | VoltClient.prototype.exit = function(callback) {
127 |
128 | debug("Exiting | Connections Length: %o", this._connections.length);
129 |
130 | while(this._connections.length > 0){
131 | var c = this._connections[0];
132 | c.close();
133 | this._connections.splice(0, 1);
134 | }
135 |
136 | if(callback) callback();
137 | }
138 |
139 | VoltClient.prototype.connectionStats = function() {
140 | util.log('Good connections:');
141 | this._displayConnectionArrayStats(this._connections);
142 |
143 | util.log('Bad connections:');
144 | this._displayConnectionArrayStats(this._badConnections);
145 | }
146 |
147 | VoltClient.prototype._displayConnectionArrayStats = function(array) {
148 | for(var index = 0; index < array.length; index++) {
149 | var connection = array[index];
150 | if(connection != null) {
151 | util.log('Connection: ',
152 | connection.config.host, ': ',
153 | connection.invocations, ' Alive: ',
154 | connection.isValidConnection());
155 | }
156 | }
157 | }
158 |
159 | /**
160 | * TODO: Not sure why SUCCESS can be both null and 1. Will leave it as is until
161 | * I know why and just brute force map the null to 1 to get it as a String.
162 | */
163 | function statusCodeToString(code){
164 | return code === null ? VoltConstants.STATUS_CODE_STRINGS[1] : VoltConstants.STATUS_CODE_STRINGS[code];
165 | }
166 |
167 | VoltClient.prototype._connectListener = function(code, event, connection) {
168 |
169 | debug("Connected | Code: %o, Event: %o", statusCodeToString(code), event);
170 |
171 | this.emit(VoltConstants.SESSION_EVENT.CONNECTION,
172 | code,
173 | event,
174 | connection.config.host);
175 | }
176 |
177 | VoltClient.prototype._connectErrorListener = function(code, event, message) {
178 | this.emit(VoltConstants.SESSION_EVENT.CONNECTION_ERROR,
179 | code,
180 | event,
181 | message);
182 | }
183 |
184 | VoltClient.prototype._queryResponseListener = function(code,event, message) {
185 | this.emit(VoltConstants.SESSION_EVENT.QUERY_RESPONSE,
186 | code,
187 | event,
188 | message);
189 | }
190 |
191 | VoltClient.prototype._queryResponseErrorListener = function(code, event, message) {
192 | this.emit(VoltConstants.SESSION_EVENT.QUERY_RESPONSE_ERROR,
193 | code,
194 | event,
195 | message);
196 | }
197 |
198 | VoltClient.prototype._queryDispatchErrorListener = function(code, event, message) {
199 | this.emit(VoltConstants.SESSION_EVENT.QUERY_DISPATCH_ERROR,
200 | code,
201 | event,
202 | message);
203 | }
204 |
205 | VoltClient.prototype._fatalErrorListener = function(code, event, message) {
206 | this.emit(VoltConstants.SESSION_EVENT.FATAL_ERROR,
207 | code,
208 | event,
209 | message);
210 | }
211 |
212 | module.exports = VoltClient;
213 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | VoltDB NodeJS Wire Protocol Driver 2.0
2 | ======================================
3 |
4 | Requirements
5 | ============
6 |
7 | Node.js 6.11.0 or later
8 | VoltDB 7.5 or later
9 |
10 |
11 | Installation
12 | ============
13 | Run NPM to install all the dependencies for the driver itself. The example application does not automatically install its dependencies, so do `npm install` in both the directory where the node.js driver is installed and the example/voter/voter folder as well.
14 |
15 | npm install
16 |
17 | Introduction
18 | ============
19 | The VoltDB is a high throughput, ACID compliant database that works best when using an asynchronous client. This wire driver runs in asynchronous mode only.
20 |
21 | Please see the documentation for administering and using VoltDB on the [VoltDB community page][1]
22 |
23 |
24 | Example Application
25 | ===================
26 |
27 | The example uses the voter example server included in the VoltDB distribution. It is found in `VOLTDB_HOME/examples/voter`.
28 |
29 | 1\. Start the server
30 |
31 | ```
32 | ./run.sh server
33 | ```
34 |
35 | 2\. In a second terminal, run the sample
36 |
37 | ```
38 | cd ./examples/voter/voter
39 | node ./app.js
40 | ```
41 |
42 | 3\. Open a browser and connect to localhost:3000 and watch the voting results.
43 |
44 | The example include detailed comments about how the application runs in the app.js and volt.js files.
45 |
46 | You may want to set the number of VoltDB *sites per host* to something interesting in `VOLTDB_HOME/examples/voter/deployment.xml`. The
47 | *sites per host* value is equivalent to the number of cores that VoltDB will use for the server when you are running a single instance on localhost.
48 |
49 |
50 | Driver Modules
51 | ==============
52 | ----------
53 |
54 |
55 | VoltClient
56 | ==========
57 | This provides the interface for connecting to the VoltDB server, managing event processing and executing stored procedures.
58 |
59 | Methods
60 | -----------
61 | VoltClient(configurationArray)
62 | -------------------------
63 |
64 | - configurationArray: A collection of configurations for connecting to and managing all of the nodes within the VoltDB cluster.
65 |
66 | Creates an instance of the client and sets internal properties, but does not perform the actual connection operation.
67 |
68 | VoltClient.connect(callback)
69 | ----------------------------
70 |
71 | - callback: A handler that gets the success and failure statuses for each of the servers specified in the `configurationArray` in the `VoltClient`
72 |
73 | Attempts to connect to each of the VoltDB server configurations passed into the constructor. The callback will be invoked for each connection. Connections may fail and the callback will receive error information. See the **Callbacks** section for callback parameter information.
74 |
75 | VoltClient.callProcedure(query, readCallback, writeCallback)
76 | ------------------------------------------------------------
77 | - query: An instance of a `VoltQuery` object.
78 | - readCallback: callback that receives the results of a query.
79 | - writeCallback: callback that is invoked when the client driver is able to write again to the driver.
80 |
81 | This function manages all queries to the VoltDB server. This includes whether it is safe to allow for more writes, encoding of query parameters and management of the outgoing query queue.
82 |
83 | Calling this function in a loop is generally discouraged since it can lead to blocking socket reads. The VoltDB server will drop a connection if data lingers on the socket for too long. The `writeCallback` handler is mechanism for avoiding that particular problem is it will get invoked each time the driver is able to issue another query.
84 |
85 | See the **Callbacks** section for callback parameter information.
86 |
87 | VoltConfiguration
88 | =================
89 | Create a VoltConfiguration object for each server within a VoltDB cluster. Pass this configuration into the `VoltClient(configurationArray)` constructor.
90 |
91 |
92 | - VoltConfiguration.host: The server name
93 | - VoltConfiguration.port: The server port (optional)
94 | - VoltConfiguration.username: Username if not using the default. (optional)
95 | - VoltConfiguration.password: Password if not using the default. (optional)
96 | - VoltConfiguration.service: Service if not using the default. (optional)
97 | - VoltConfiguration.queryTimeout: How long a query should be allowed to be pending before the driver issues an error message. (optional)
98 | - VoltConfiguration.queryTimeoutInterval: The interval for checking for queries that have timed out. Also cleans out the queue of processed queries. (optional)
99 | - VoltConfiguration.flushInterval: How long to wait before flushing the query queue. (optional)
100 | - VoltConfiguration.messageQueueSize: Maximum number of messages to place in the driver's internal message queue before writing them to the outgoing socket. The default value is set to 10 and it is not recommended to create queue much larger as the gains become less significant as the queue grows. (optional)
101 | - VoltConfiguration.maxConsecutiveWrites: The driver will only allow this number of writes to the outgoing queue and socket before requiring a read operation. This is necessary to ensure that read operations are not blocked. The default value is 5000 queries. If you find that connections between the client and server are being dropped by the server, then lower this value to ensure more frequent reads. (optional)
102 |
103 | VoltProcedure
104 | =============
105 | Defines a template for a query, which includes the name of the procedure and the parameter types that can be passed to the query.
106 |
107 | Methods
108 | -------
109 | VoltProcedure(name, types)
110 | --------------------------
111 |
112 | - name: The name of the stored procedure.
113 | - types: An array of types specified as a set of strings.
114 |
115 | **Example**
116 | ```
117 | var resultsProc = new VoltProcedure('Results');
118 | var initProc = new VoltProcedure('Initialize', ['int', 'string']);
119 | var voteProc = new VoltProcedure('Vote', ['long', 'int', 'long']);
120 | ```
121 |
122 | A complete list of types is specified in the **Data Types** section
123 |
124 |
125 | VoltProcedure.getQuery()
126 | --------------------------------
127 | Returns an instance of a VoltQuery.
128 |
129 | VoltQuery
130 | =========
131 | VoltQuery is necessary for query invocation, but the application developer does very little with it. A VoltQuery is produced by the `VoltProcedure.getQuery()` function. That object is then passed to the `VoltClient.callProcedure`function.
132 |
133 | VoltQuery(procName, types)
134 | --------------------------
135 | Called only by the VoltProcedure object.
136 |
137 |
138 | Callbacks
139 | =========
140 | ---------
141 | All callbacks take follow the same structure:
142 | (errorCode, eventCode, result)
143 | - errorCode: Will be set to null if successful or a numeric value if an error occurred. See **Error Codes** for details on each error code.
144 |
145 | **Example 1: Using status codes**
146 | ```
147 | client.callProcedure(query, displayResults(errorCode, eventCode, results) {
148 | if(errorCode == VoltConstants.STATUS_CODES.SUCCESS) {
149 | // Success!
150 | } else {
151 | // Error handling
152 | }
153 | });
154 | ```
155 |
156 |
157 | **Example 2: No status codes**
158 | ```
159 | client.callProcedure(query, displayResults(errorCode, eventCode, results) {
160 | if(errorCode) {
161 | // Error Handling
162 | } else {
163 | // Success!
164 | }
165 | });
166 | ```
167 |
168 |
169 | Events
170 | ======
171 | ----------
172 |
173 | SESSION\_EVENT
174 | --------------
175 | - SESSION\_EVENT.CONNECTION: A successful connection to the volt server
176 | - SESSION\_EVENT.CONNECTION\_ERROR: Could not connect, see both the status code and the event handler's message parameter.
177 | - SESSION\_EVENT.QUERY\_RESPONSE: Query executed and returned.
178 | - SESSION\_EVENT.QUERY\_ALLOWED: Indicates that the application may execute another query Note that this prevents your application from flooding the database and the application's code from blocking.
179 | - SESSION\_EVENT.QUERY\_RESPONSE\_ERROR:The query was successfully dispatched but theVoltDB server either had a critical fault or dropped the connection.
180 | - SESSION\_EVENT.QUERY\_DISPATCH\_ERROR: The client could not dispatch the query.
181 | - SESSION\_EVENT.FATAL\_ERROR: A critical error occurred that was above and beyond all other error conditions.
182 |
183 | Error Codes
184 | ===========
185 | ----------
186 |
187 | STATUS\_CODES
188 | ============
189 | - STATUS\_CODES.SUCCESS: Operation succeeded. Note that the value of this constant is null.
190 | - STATUS\_CODES.USER\_ABORT: The user's stored procedure intentionally threw an exception of type `UserAbortException`.
191 | - STATUS\_CODES.GRACEFUL\_FAILURE: Query had an error that rolled back the transaction.
192 | - STATUS\_CODES.UNEXPECTED\_FAILURE: Query had an error, rolled back the transaction and caused additional errors.
193 | - STATUS\_CODES.CONNECTION\_LOST: The connection to VoltDB was lost before the query returned. This is not issued by the server, but is issued by the client.
194 | - STATUS\_CODES.SERVER\_UNAVAILABLE: Attempted to use an invalid connection.
195 | - STATUS\_CODES.CONNECTION\_TIMEOUT: The server stopped replying.
196 | - STATUS\_CODES.QUERY\_TIMEOUT: The server issues a message saying that the query took too long to execute.
197 | - STATUS\_CODES.QUERY\_TOOK\_TOO\_LONG: Driver issued message indicating that the server has taken too long to respond.
198 |
199 | Data Types
200 | ===========
201 | ----------
202 | These data types are not JavaScript data types. The driver uses these type specifiers to encode a JavaScript type into a VoltDB type.
203 | - null: Use `null`
204 | - byte: Use a number, not a string
205 | - tinyint: Use a number, not a string
206 | - short: Use a number, not a string
207 | - smallint: Use a number, not a string
208 | - int: Use a number, not a string
209 | - integer: Use a number, not a string
210 | - long: Use a number, not a string
211 | - bigint: Use a number, not a string
212 | - double: Use a number, not a string
213 | - float: Use a number, not a string
214 | - string: Use a string
215 | - date: Use a number, not a string
216 | - timestamp: Use a number, not a string
217 | - decimal: Use a number, not a string
218 | - varbinary: Use a `Buffer`
219 |
220 |
221 |
222 | [1]: http://community.voltdb.com/
223 |
--------------------------------------------------------------------------------
/test/cases/bufferTest.js:
--------------------------------------------------------------------------------
1 | !(function (global) { // eslint-disable-line no-unused-vars
2 |
3 | "use strict";
4 |
5 | const VoltClient = require("../../lib/client");
6 | const VoltConfiguration = require("../../lib/configuration");
7 | const VoltConstants = require("../../lib/voltconstants");
8 | const VoltProcedure = require("../../lib/query");
9 |
10 |
11 | require("nodeunit");
12 | const testContext = require("../util/test-context");
13 | const debug = require("debug")("voltdb-client-nodejs:BufferTest");
14 |
15 | //Setup context
16 | testContext.setup();
17 |
18 | /**
19 | * A "good" client config that points to a volt instance on localhost
20 | */
21 | function configs() {
22 |
23 | const configs = [];
24 |
25 | const config = new VoltConfiguration();
26 | config.host = "localhost";
27 | config.port = testContext.port();
28 |
29 | configs.push(config);
30 |
31 | return configs;
32 | }
33 |
34 | /**
35 | * Promise style function for connecting to a Volt instance
36 | */
37 | function connect(client){
38 |
39 | const p = new Promise(function(resolve, reject) {
40 | client.connect(function(code, event, results) {
41 | if(code === VoltConstants.STATUS_CODES.SUCCESS){
42 | resolve({errorCode: code, eventCode: event, results: results});
43 | }
44 | else{
45 | debug("Connect Failure | Code: %o, Event: %o", code, event);
46 | reject({errorCode: code, eventCode: event, results: results});
47 | }
48 | });
49 | });
50 |
51 | return p;
52 | }
53 |
54 | /**
55 | * Promise style function for calling a procedure. An alternative to the old
56 | * callback style functions that returns both a write and a read promise.
57 | */
58 | function query(query, client){
59 |
60 | var writeResolve = null;
61 | var writeReject = null;
62 |
63 | const writePromise = new Promise(function(resolve, reject){
64 | writeResolve = resolve;
65 | writeReject = reject;
66 | });
67 |
68 | const readPromise = new Promise(function(resolve, reject){
69 |
70 | client.callProcedure(query, function read(code, event, results) {
71 | // debug("AdHocQuery Complete | errorCode: %o, eventCode: %o, results:
72 | // %O", code, event, results);
73 | if(code === VoltConstants.STATUS_CODES.SUCCESS){
74 | // The results code is 1 for SUCCESS so can't use voltconstants
75 | if(results.status === PROC_STATUS_CODE_SUCCESS){
76 | resolve({errorCode: code, eventCode: event, results: results});
77 | }
78 | else{
79 | debug("AdHocQuery Failure | Read Error. errorCode: %o, eventCode: %o, results: %O", statusCodeToString(code), event, results);
80 | reject({errorCode: code, eventCode: event, results: results});
81 | }
82 | }
83 | else{
84 | debug("AdHocQuery Failure | Read Error. errorCode: %o, eventCode: %o, results: %O", statusCodeToString(code), event, results);
85 | reject({errorCode: code, eventCode: event, results: results});
86 | }
87 |
88 | }, function write(code, event, results) {
89 | if(code === VoltConstants.STATUS_CODES.SUCCESS){
90 | writeResolve({errorCode: code, eventCode: event, results: results});
91 | }
92 | else{
93 | debug("AdHocQuery Failure | Write Error. errorCode: %o, eventCode: %o, results: %O", statusCodeToString(code), event, results);
94 | writeReject({errorCode: code, eventCode: event, results: results});
95 | }
96 | });
97 | });
98 |
99 | return { writePromise: writePromise, readPromise: readPromise };
100 | }
101 |
102 | /**
103 | * Sugar for running an adhoc query
104 | */
105 | function adHocQuery(queryString, client){
106 |
107 | debug("Query | query: %o", queryString);
108 |
109 | const p = new VoltProcedure("@AdHoc", [ "string" ]);
110 |
111 | const q = p.getQuery();
112 | q.setParameters([queryString]);
113 |
114 | return query(q, client);
115 | }
116 |
117 | /**
118 | *
119 | */
120 | function statusCodeToString(code){
121 | return code === null ? VoltConstants.STATUS_CODE_STRINGS[PROC_STATUS_CODE_SUCCESS] : VoltConstants.STATUS_CODE_STRINGS[code];
122 | }
123 |
124 | /**
125 | * Utility method for volt queries that return a write and a read promise.
126 | * Useful for when you want to fire off a bunch of writes and then wait on the
127 | * read at the end. Executes the query and collects the read promises in the
128 | * given array. Returns both the write and read promise.
129 | */
130 | function queryCollect(queryString, readPromises, client){
131 | const p = adHocQuery(queryString, client);
132 | readPromises.push(p.readPromise);
133 | return p;
134 | }
135 |
136 | /**
137 | *
138 | */
139 | const PROC_STATUS_CODE_SUCCESS = 1;
140 |
141 | // Exports
142 | module.exports = {
143 | setUp : function(callback){
144 | callback();
145 | },
146 | tearDown : function(callback){
147 | callback();
148 | },
149 | readTest : function(test){
150 |
151 | debug("readTest");
152 |
153 | const client = new VoltClient(configs());
154 |
155 | debug("Connecting");
156 |
157 | connect(client)
158 | .then(function(value){
159 | test.ok(value.errorCode === VoltConstants.STATUS_CODES.SUCCESS);
160 | return Promise.resolve(null);
161 | })
162 | .then(function(){
163 | return adHocQuery("DROP TABLE PLAYERS IF EXISTS;", client).readPromise;
164 | })
165 | .then(function(){
166 | return adHocQuery("CREATE TABLE PLAYERS (" +
167 | "playerID integer NOT NULL, " +
168 | "teamid varchar(100) NOT NULL " +
169 | ");", client).readPromise;
170 | })
171 | .then(function(){
172 | return adHocQuery("DROP TABLE TEAM_PLAYERS IF EXISTS;", client).readPromise;
173 | })
174 | .then(function(){
175 | return adHocQuery("CREATE TABLE TEAM_PLAYERS (" +
176 | "id integer NOT NULL, " +
177 | "uid varchar(100) NOT NULL, " +
178 | "name varchar(100) NOT NULL, " +
179 | "avatar varbinary(12000) NOT NULL" +
180 | ");", client).readPromise;
181 | })
182 | .then(function(){
183 |
184 | const readPromises = [];
185 |
186 | return Promise.resolve()
187 | .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (0, 'TeamA');", readPromises, client).writePromise; })
188 | .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (1, 'TeamA');", readPromises, client).writePromise; })
189 | .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (2, 'TeamA');", readPromises, client).writePromise; })
190 | .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (3, 'TeamA');", readPromises, client).writePromise; })
191 | .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (4, 'TeamA');", readPromises, client).writePromise; })
192 | .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (5, 'TeamB');", readPromises, client).writePromise; })
193 | .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (6, 'TeamB');", readPromises, client).writePromise; })
194 | .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (7, 'TeamB');", readPromises, client).writePromise; })
195 | .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (8, 'TeamB');", readPromises, client).writePromise; })
196 | .then(function() { return queryCollect("INSERT INTO PLAYERS VALUES (9, 'TeamB');", readPromises, client).writePromise; })
197 | .then(function() { return Promise.all(readPromises); });
198 |
199 | })
200 | .then(function(){
201 |
202 | const readPromises = [];
203 |
204 | return Promise.resolve()
205 | .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (0, 'GameA', 'TeamA', 'ABCDEF');", readPromises, client).writePromise; })
206 | .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (1, 'GameB', 'TeamA', 'ABCDEF');", readPromises, client).writePromise; })
207 | .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (2, 'GameC', 'TeamA', 'ABCDEF');", readPromises, client).writePromise; })
208 | .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (3, 'GameD', 'TeamA', 'ABCDEF');", readPromises, client).writePromise; })
209 | .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (4, 'GameE', 'TeamA', 'ABCDEF');", readPromises, client).writePromise; })
210 | .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (5, 'GameA', 'TeamB', 'ABCDEF');", readPromises, client).writePromise; })
211 | .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (6, 'GameB', 'TeamB', 'ABCDEF');", readPromises, client).writePromise; })
212 | .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (7, 'GameC', 'TeamB', 'ABCDEF');", readPromises, client).writePromise; })
213 | .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (8, 'GameD', 'TeamB', 'ABCDEF');", readPromises, client).writePromise; })
214 | .then(function() { return queryCollect("INSERT INTO TEAM_PLAYERS VALUES (9, 'GameE', 'TeamB', 'ABCDEF');", readPromises, client).writePromise; })
215 | .then(function() { return Promise.all(readPromises); });
216 |
217 | })
218 | .then(function(){
219 | return adHocQuery("select A.*, " +
220 | "B.name as name, " +
221 | "B.avatar as avatar " +
222 | "from PLAYERS as A left join TEAM_PLAYERS as B on A.playerID=B.id " +
223 | "where uID='GameA' and A.teamID='TeamA';", client).readPromise;
224 | })
225 | .then(function(value){
226 | debug("Result Count: %O", value.results.table.length);
227 | debug("Results: %O", value.results.table[0][0]);
228 | client.exit();
229 | test.done();
230 | return Promise.resolve(null);
231 | })
232 | .catch(function(value){
233 | debug("Test Failed | Results: %O", value);
234 | client.exit();
235 | test.ok(false, "Test failed, see previous messages");
236 | test.done();
237 | });
238 | }
239 | };
240 |
241 | }(this));
242 |
--------------------------------------------------------------------------------
/examples/voter/voter/models/volt.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining
5 | * a copy of this software and associated documentation files (the
6 | * "Software"), to deal in the Software without restriction, including
7 | * without limitation the rights to use, copy, modify, merge, publish,
8 | * distribute, sublicense, and/or sell copies of the Software, and to
9 | * permit persons to whom the Software is furnished to do so, subject to
10 | * the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be
13 | * included in all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 | * OTHER DEALINGS IN THE SOFTWARE.
22 | */
23 |
24 | /*
25 | * This following is just a simple integration of VoltDB and a Node application.
26 | *
27 | * The code does the following:
28 | * 1. Exposes the VOLTDB stored procedures
29 | * 2. Creates a connection
30 | * 3. Invokes stored procedures and processes the results.
31 | */
32 |
33 | var util = require('util');
34 | var cluster = require('cluster');
35 |
36 | // VoltClient manages all communication with VoltDB
37 | var VoltClient = require(__dirname + '/../../../../lib/client');
38 |
39 | // VoltConstants has all the event types, codes and other constants
40 | // that the client and your code will rely upon
41 | var VoltConstants = require(__dirname + '/../../../../lib/voltconstants');
42 |
43 | // VoltConfiguration sets up the configuration for each VoltDB server
44 | // in your cluster. If you have ten Volt nodes in the cluster, then you should
45 | // create ten configurations. These configurations are used in the construction
46 | // of the client.
47 | var VoltConfiguration = require(__dirname + '/../../../../lib/configuration');
48 |
49 | // VoltProcedure is a static representation of the stored procedure and
50 | // specifies the procedure's name and the parameter types. The parameter types
51 | // are especially important since they define how the client will marshal the
52 | // the parameters.
53 | var VoltProcedure = require(__dirname + '/../../../../lib/query');
54 |
55 | // VoltQuery is a specific instance of a VoltProcedure. Your code will
56 | // always call stored procedures using a VoltQuery object.
57 | var VoltQuery = require(__dirname + '/../../../../lib/query');
58 |
59 | // These are a set of stored procedure definitions.
60 | // See VoltConstants to see the data types supported by the driver.
61 | var resultsProc = new VoltProcedure('Results');
62 | var initProc = new VoltProcedure('Initialize', ['int', 'string']);
63 | var voteProc = new VoltProcedure('Vote', ['long', 'int', 'long']);
64 |
65 | // The following is just application specific data
66 | var client = null;
67 |
68 | var transactionCounter = 0;
69 | var statsLoggingInterval = 10000;
70 |
71 | var area_codes = [907, 205, 256, 334, 251, 870, 501, 479, 480, 602, 623, 928,
72 | 520, 341, 764, 628, 831, 925, 909, 562, 661, 510, 650, 949, 760, 415, 951, 209,
73 | 669, 408, 559, 626, 442, 530, 916, 627, 714, 707, 310, 323, 213, 424, 747, 818,
74 | 858, 935, 619, 805, 369, 720, 303, 970, 719, 860, 203, 959, 475, 202, 302, 689,
75 | 407, 239, 850, 727, 321, 754, 954, 927, 352, 863, 386, 904, 561, 772, 786, 305,
76 | 941, 813, 478, 770, 470, 404, 762, 706, 678, 912, 229, 808, 515, 319, 563, 641,
77 | 712, 208, 217, 872, 312, 773, 464, 708, 224, 847, 779, 815, 618, 309, 331, 630,
78 | 317, 765, 574, 260, 219, 812, 913, 785, 316, 620, 606, 859, 502, 270, 504, 985,
79 | 225, 318, 337, 774, 508, 339, 781, 857, 617, 978, 351, 413, 443, 410, 301, 240,
80 | 207, 517, 810, 278, 679, 313, 586, 947, 248, 734, 269, 989, 906, 616, 231, 612,
81 | 320, 651, 763, 952, 218, 507, 636, 660, 975, 816, 573, 314, 557, 417, 769, 601,
82 | 662, 228, 406, 336, 252, 984, 919, 980, 910, 828, 704, 701, 402, 308, 603, 908,
83 | 848, 732, 551, 201, 862, 973, 609, 856, 575, 957, 505, 775, 702, 315, 518, 646,
84 | 347, 212, 718, 516, 917, 845, 631, 716, 585, 607, 914, 216, 330, 234, 567, 419,
85 | 440, 380, 740, 614, 283, 513, 937, 918, 580, 405, 503, 541, 971, 814, 717, 570,
86 | 878, 835, 484, 610, 267, 215, 724, 412, 401, 843, 864, 803, 605, 423, 865, 931,
87 | 615, 901, 731, 254, 325, 713, 940, 817, 430, 903, 806, 737, 512, 361, 210, 979,
88 | 936, 409, 972, 469, 214, 682, 832, 281, 830, 956, 432, 915, 435, 801, 385, 434,
89 | 804, 757, 703, 571, 276, 236, 540, 802, 509, 360, 564, 206, 425, 253, 715, 920,
90 | 262, 414, 608, 304, 307];
91 |
92 | var voteCandidates = 'Edwina Burnam,Tabatha Gehling,Kelly Clauss,' +
93 | 'Jessie Alloway,Alana Bregman,Jessie Eichman,Allie Rogalski,Nita Coster,' +
94 | 'Kurt Walser,Ericka Dieter,Loraine NygrenTania Mattioli';
95 |
96 | function getCandidate() {
97 | return Math.floor(Math.random() * 6) + 1;
98 | }
99 |
100 | function getAreaCode() {
101 | var tmpNumber = Math.floor((area_codes[Math.floor(Math.random() * 1000) % area_codes.length] * 10000000) +
102 | (Math.random() * 10000000));
103 | return tmpNumber;
104 | }
105 |
106 | // This will initialize the Voter database by invoking a stored procedure.
107 | function voltInit() {
108 | util.log('voltInit');
109 | // Start by creating a query instance from the VoltProcedure
110 | var query = initProc.getQuery();
111 |
112 | // Set the parameter values.
113 | query.setParameters([6, voteCandidates]);
114 |
115 | // Call the stored procedure with the query instance and a callback
116 | // handler to receive the results.
117 | // The callback handler uses the code to indicate whether there is an error
118 | // and the severity. See the VoltConstant source to see all the possible codes
119 | // and their definitions.
120 | // The event indicates what kind of event occurred. Again, check the
121 | // VoltConstant source to see the possible values.
122 | // The result object depends on the operation. Queries will always return a
123 | // VoltTable array
124 | client.callProcedure(query, function initVoter(code, event, results) {
125 | var val = results.table[0][0];
126 | util.log('Initialized app for ' + val[''] + ' candidates.');
127 | });
128 | }
129 |
130 |
131 | // This is a generic event handler. An application can register a common
132 | // event handler for all events emitted by the client. This is very useful
133 | // for trapping all the various error conditions, like connections being
134 | // dropped.
135 | function eventListener(code, event, message) {
136 | util.log(util.format( 'Event %s\tcode: %d\tMessage: %s', event, code,
137 | message));
138 | }
139 |
140 | // This is a generic configuration object factory.
141 | function getConfiguration(host) {
142 | var cfg = new VoltConfiguration();
143 | cfg.host = host;
144 | // The messageQueueSize sets how many messages to buffer before dispatching
145 | // them to the server. The messages are dispatched when either a timeout is
146 | // reached or the queue fills up. It is best to keep this number
147 | // relatively small. High volume applications will see a benefit by having a
148 | // queue while low volume applications would be better served with the queue
149 | // size set to 0. Increasing the queue size beyond 20 will only give you
150 | // marginal performance improvements.
151 | cfg.messageQueueSize = 20;
152 | return cfg;
153 | }
154 |
155 | // Connect to the server
156 | exports.initClient = function(startLoop) {
157 | if(client == null) {
158 | var configs = []
159 |
160 | configs.push(getConfiguration('localhost'));
161 | // The client is only configured at this point. The connection
162 | // is not made until the call to client.connect().
163 | client = new VoltClient(configs);
164 |
165 | // You can register for a long list of event types, including the results
166 | // of queries. Some developers will prefer a common message loop
167 | // while others will prefer to consume each event in a separate handler.
168 | // Queries can also be processed in a common handler at the client level,
169 | // but would be better handled by using a query callback instead.
170 | client.on(VoltConstants.SESSION_EVENT.CONNECTION,eventListener);
171 | client.on(VoltConstants.SESSION_EVENT.CONNECTION_ERROR,eventListener);
172 | client.on(VoltConstants.SESSION_EVENT.QUERY_RESPONSE_ERROR,eventListener);
173 | client.on(VoltConstants.SESSION_EVENT.QUERY_DISPATCH_ERROR,eventListener);
174 | client.on(VoltConstants.SESSION_EVENT.FATAL_ERROR,eventListener);
175 |
176 | // The actual connection.
177 | // Note, there are two handlers. The first handler will generally indicate
178 | // a success, though it is possible for one of the connections to the
179 | // volt cluster to fail.
180 | // The second handler is more for catastrophic failures.
181 | client.connect(function startup(code, event,results) {
182 | if(code == VoltConstants.STATUS_CODES.SUCCESS) {
183 | util.log('Node connected to VoltDB');
184 | if(startLoop) {
185 | setInterval(logResults, statsLoggingInterval);
186 | voteInsertLoop();
187 | } else {
188 | voltInit();
189 | }
190 | } else {
191 | util.log(`Unexpected status while initClient: ${VoltConstants.STATUS_CODE_STRINGS[code]}`);
192 | process.exit(1);
193 | }
194 | }, function loginError(code, event, results) {
195 | util.log('Node did not connect to VoltDB');
196 | });
197 | }
198 | }
199 |
200 | // This method will vote several times and will run in the background.
201 | function voteInsertLoop() {
202 |
203 | // Get the query object.
204 | var query = voteProc.getQuery();
205 | var innerLoop = function() {
206 | // hard coded limited loop.
207 | // Note, increasing the size of the loop will "blast" the server with a
208 | // large backlog of queries and degrade performance when you are running
209 | // this application against a two node VoltDB cluster.
210 | for(var i = 0; i < 30; i++) {
211 | // Note that you can reuse the query object
212 | query.setParameters([ getAreaCode(), getCandidate(), 20000]);
213 |
214 | // There are two callbacks. The first indicates that the query returned.
215 | // The second indicates that it is safe to query the server again. The
216 | // second handler prevents blocking. You must allow the driver to read
217 | // from the VoltConnection's socket or VoltDB will close your socket. The
218 | // readyToWrite() callback gives you a way to interrupt looping type
219 | // operations so that the socket.read events can be processed by the
220 | // connection.
221 | client.callProcedure(query,
222 | function displayResults(code, event, results) {
223 | transactionCounter++;
224 | }, function readyToWrite(code, event, results) {
225 |
226 | });
227 | }
228 | setImmediate(innerLoop);
229 | }
230 | process.nextTick(innerLoop);
231 |
232 | }
233 |
234 | // This just displays how many votes we issued every 10 seconds, per node
235 | // instance
236 | function logResults() {
237 | logTime("Voted", statsLoggingInterval, transactionCounter);
238 | transactionCounter = 0;
239 | }
240 |
241 | function logTime(operation, totalTime, count) {
242 | util.log(util.format('%d: %s %d times in %d milliseconds. %d TPS',
243 | process.pid, operation, count, totalTime,
244 | Math.floor((count / totalTime) * 1000)));
245 | }
246 |
247 | // Call the stored proc to collect all votes.
248 | exports.getVoteResults = function(callback) {
249 | var query = resultsProc.getQuery();
250 | client.callProcedure(query, callback);
251 | }
252 |
--------------------------------------------------------------------------------
/voternoui.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * This file contains original code and/or modifications of original code.
5 | * Any modifications made by VoltDB Inc. are licensed under the following
6 | * terms and conditions:
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining
9 | * a copy of this software and associated documentation files (the
10 | * "Software"), to deal in the Software without restriction, including
11 | * without limitation the rights to use, copy, modify, merge, publish,
12 | * distribute, sublicense, and/or sell copies of the Software, and to
13 | * permit persons to whom the Software is furnished to do so, subject to
14 | * the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be
17 | * included in all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | * OTHER DEALINGS IN THE SOFTWARE.
26 | */
27 |
28 | var cli = require('cli');
29 | var cluster = require ('cluster');
30 | var VoltClient = require('./lib/client');
31 | var VoltConfiguration = require('./lib/configuration');
32 | var VoltProcedure = require('./lib/query');
33 | var VoltQuery = require('./lib/query');
34 |
35 | var util = require('util');
36 |
37 | var client = null;
38 | var resultsProc = new VoltProcedure('Results');
39 | var initProc = new VoltProcedure('Initialize', ['int', 'string']);
40 | var voteProc = new VoltProcedure('Vote', ['long', 'int', 'long']);
41 |
42 | var options = cli.parse({
43 | voteCount : ['c', 'Number of votes to run', 'number', 10000],
44 | clusterNode0 : ['h', 'VoltDB host (one of the cluster)', 'string', 'localhost']
45 | });
46 |
47 | var area_codes = [907, 205, 256, 334, 251, 870, 501, 479, 480, 602, 623, 928,
48 | 520, 341, 764, 628, 831, 925, 909, 562, 661, 510, 650, 949, 760, 415, 951, 209,
49 | 669, 408, 559, 626, 442, 530, 916, 627, 714, 707, 310, 323, 213, 424, 747,
50 | 818, 858, 935, 619, 805, 369, 720, 303, 970, 719, 860, 203, 959, 475, 202,
51 | 302, 689, 407, 239, 850, 727, 321, 754, 954, 927, 352, 863, 386, 904, 561,
52 | 772, 786, 305, 941, 813, 478, 770, 470, 404, 762, 706, 678, 912, 229, 808,
53 | 515, 319, 563, 641, 712, 208, 217, 872, 312, 773, 464, 708, 224, 847, 779,
54 | 815, 618, 309, 331, 630, 317, 765, 574, 260, 219, 812, 913, 785, 316, 620,
55 | 606, 859, 502, 270, 504, 985, 225, 318, 337, 774, 508, 339, 781, 857, 617,
56 | 978, 351, 413, 443, 410, 301, 240, 207, 517, 810, 278, 679, 313, 586, 947,
57 | 248, 734, 269, 989, 906, 616, 231, 612, 320, 651, 763, 952, 218, 507, 636,
58 | 660, 975, 816, 573, 314, 557, 417, 769, 601, 662, 228, 406, 336, 252, 984,
59 | 919, 980, 910, 828, 704, 701, 402, 308, 603, 908, 848, 732, 551, 201, 862,
60 | 973, 609, 856, 575, 957, 505, 775, 702, 315, 518, 646, 347, 212, 718, 516,
61 | 917, 845, 631, 716, 585, 607, 914, 216, 330, 234, 567, 419, 440, 380, 740,
62 | 614, 283, 513, 937, 918, 580, 405, 503, 541, 971, 814, 717, 570, 878, 835,
63 | 484, 610, 267, 215, 724, 412, 401, 843, 864, 803, 605, 423, 865, 931, 615,
64 | 901, 731, 254, 325, 713, 940, 817, 430, 903, 806, 737, 512, 361, 210, 979,
65 | 936, 409, 972, 469, 214, 682, 832, 281, 830, 956, 432, 915, 435, 801, 385,
66 | 434, 804, 757, 703, 571, 276, 236, 540, 802, 509, 360, 564, 206, 425, 253,
67 | 715, 920, 262, 414, 608, 304, 307];
68 | var voteCandidates = 'Edwina Burnam,Tabatha Gehling,Kelly Clauss,' +
69 | 'Jessie Alloway,Alana Bregman,Jessie Eichman,Allie Rogalski,Nita Coster,' +
70 | 'Kurt Walser,Ericka Dieter,Loraine NygrenTania Mattioli';
71 |
72 |
73 | function main() {
74 |
75 | var clusterNodes = [options.clusterNode0];
76 | var configs = [];
77 | for ( var index = 0; index < clusterNodes.length; index++ ) {
78 | console.log("Host: " + clusterNodes[index]);
79 | var vc = new VoltConfiguration();
80 | vc.host = clusterNodes[index];
81 | configs.push(vc);
82 | }
83 | var counter = 0;
84 |
85 | client = new VoltClient(configs);
86 | client.connect(function startup(results) {
87 | console.log('Node up');
88 | voltInit();
89 | }, function loginError(results) {
90 | console.log("Error logging in: " + results);
91 | });
92 | }
93 |
94 | function voltInit() {
95 | console.log('voltInit');
96 | var query = initProc.getQuery();
97 | query.setParameters([6, voteCandidates]);
98 | client.callProcedure(query, function initVoter(event, code, results) {
99 | if ( results.error == false ) {
100 | var val = results.table[0][0];
101 | console.log( 'Initialized app for ' + val[''] + ' candidates.\n\n');
102 |
103 | var voteJob = {};
104 | voteJob.voteCount = options.voteCount;
105 | voteJob.steps = getSteps();
106 |
107 | runNextLink(voteJob);
108 | }
109 | });
110 | }
111 |
112 | function voteOften(voteJob) {
113 | console.log('voteOften');
114 | voteInsertLoop(voteJob);
115 | }
116 |
117 | function voteResultsOften(voteJob) {
118 | console.log('voteResultsOften');
119 | voteResultsLoop(voteJob);
120 | }
121 |
122 | function voteResults(voteJob) {
123 | console.log('voteResults');
124 | var query = resultsProc.getQuery();
125 | client.callProcedure(query, function displayResults(event, code, results) {
126 | var mytotalVotes = 0;
127 |
128 | var msg = '';
129 | var longestString = 0;
130 | var rows = results.table[0];
131 | for(var i = 0; i < rows.length; i++) {
132 | mytotalVotes += rows[i].TOTAL_VOTES;
133 | msg += util.format("%s\t%s\t%d\n", rows[i].CONTESTANT_NAME,
134 | rows[i].CONTESTANT_NUMBER, rows[i].TOTAL_VOTES);
135 | }
136 | msg += util.format("%d votes\n\n", mytotalVotes);
137 | console.log(msg);
138 | runNextLink(voteJob);
139 | });
140 | }
141 |
142 | function connectionStats() {
143 | client.connectionStats();
144 | }
145 |
146 | function voteEnd(voteJob) {
147 | client.connectionStats();
148 | console.log('voteEnd');
149 | process.exit();
150 | }
151 |
152 | function getCandidate() {
153 | return Math.floor(Math.random() * 6) + 1;
154 | }
155 |
156 | function getAreaCode() {
157 | return area_codes[Math.floor(Math.random() * area_codes.length)] * 10000000
158 | + Math.random() * 10000000;
159 | }
160 |
161 | function getSteps() {
162 | var voltTestChain = [];
163 | voltTestChain.push(voteResults);
164 | // Not called because the query does a table scan and is not
165 | // representative of VoltDB's performance
166 | //voltTestChain.push(voteResultsOften);
167 | voltTestChain.push(voteOften);
168 | voltTestChain.push(voteResults);
169 | voltTestChain.push(voteEnd);
170 |
171 | return voltTestChain;
172 | }
173 |
174 | function voteResultsLoop(voteJob) {
175 |
176 | var index = 0;
177 | var reads = voteJob.voteCount;
178 | var startTime = new Date().getTime();
179 | var chunkTime = new Date().getTime();
180 | var readyToWriteCounter = 0;
181 |
182 | var innerResultsLoop = function() {
183 | var query = resultsProc.getQuery();
184 | if(index < voteJob.voteCount) {
185 | client.callProcedure(query, function displayVoteResults(event, code, results) {
186 | reads--;
187 | // results object is not always real
188 | if ( results.status != 1) {
189 | console.log(results);
190 | }
191 |
192 | //console.log('reads left: ', reads);
193 | if(reads == 0) {
194 | logVoteResultsTime(startTime, voteJob.voteCount, "Results");
195 | runNextLink(voteJob);
196 | } else {
197 | // console.log("reads ", reads);
198 | }
199 | //console.log('read done');
200 | }, function readyToWrite() {
201 | //console.log('writes left: ', voteJob.voteCount-index);
202 | if(index < voteJob.voteCount) {
203 | if ( index % 5000 == 0 ) {
204 | console.log('Executed ', index, ' queries in ',
205 | (new Date().getTime()) - chunkTime, 'ms ',
206 | util.inspect(process.memoryUsage()));
207 | chunkTime = new Date().getTime();
208 | }
209 | index++;
210 | if ( index % 20 == 0) {
211 | process.nextTick(innerResultsLoop);
212 | }
213 | } else {
214 | console.log('Time to stop querying: ', index);
215 | }
216 | //console.log('write done');
217 | });
218 | } else {
219 | console.log(readyToWriteCounter++, 'Index is: ', index, ' and ',
220 | voteJob.voteCount);
221 | }
222 | };
223 | process.nextTick(innerResultsLoop);
224 | }
225 |
226 |
227 |
228 | function voteInsertLoop(voteJob) {
229 |
230 | var index = 0;
231 | var reads = voteJob.voteCount;
232 | var startTime = new Date().getTime();
233 | var chunkTime = new Date().getTime();
234 | var readyToWriteCounter = 0;
235 |
236 | var innerLoop = function() {
237 | var query = voteProc.getQuery();
238 | if(index < voteJob.voteCount) {
239 | query.setParameters([getAreaCode(), getCandidate(), 200000]);
240 | client.callProcedure(query, function displayResults(event, code, results) {
241 | //console.log("reads ", reads);
242 | reads--;
243 | if(reads == 0) {
244 | logVoteInsertTime(startTime, voteJob.voteCount, "Results");
245 | runNextLink(voteJob);
246 | } else {
247 | //console.log("reads ", reads);
248 | }
249 | }, function readyToWrite() {
250 | if( index < voteJob.voteCount ) {
251 | if ( index % 5000 == 0 ) {
252 | console.log('Executed ', index, ' votes in ',
253 | (new Date().getTime()) - chunkTime, 'ms '/*,
254 | util.inspect(process.memoryUsage())*/);
255 | chunkTime = new Date().getTime();
256 | }
257 | index++;
258 | }
259 | });
260 | }
261 | setImmediate(innerLoop);
262 | };
263 | process.nextTick(innerLoop);
264 |
265 | }
266 |
267 | function logVoteInsertTime(startTime, votes, typeString) {
268 | logTime('Voted', startTime, votes, typeString);
269 | }
270 |
271 | function logVoteResultsTime(startTime, votes, typeString) {
272 | logTime('Queried for results', startTime, votes, typeString);
273 | }
274 |
275 | function logTime(operation, startTime, votes, typeString) {
276 | var endTimeMS = new Date().getTime() - startTime;
277 | var endTimeSeconds = Math.floor(endTimeMS / 1000);
278 | endTimeMS = (endTimeMS > 0 ? endTimeMS : 1 );
279 | endTimeSeconds = (endTimeSeconds > 0 ? endTimeSeconds : 1 );
280 |
281 | console.log(util.format('%s %d times in %d milliseconds.\n'
282 | + '%s %d times in %d seconds.\n%d milliseconds per transaction\n'
283 | + '%d transactions per millisecond\n%d transactions per second\n\n',
284 | operation,
285 | votes, endTimeMS,
286 | operation, votes,
287 | endTimeSeconds, (endTimeMS / votes),
288 | (votes / endTimeMS), (votes / endTimeSeconds)));
289 | }
290 |
291 | function isValidObject(object) {
292 | return typeof object != 'undefined' && object != null;
293 | }
294 |
295 | function runNextLink(voteJob) {
296 |
297 | if(0 < voteJob.steps.length) {
298 | var method = voteJob.steps.shift();
299 | if(isValidObject(method) == true) {
300 | method(voteJob);
301 | }
302 | }
303 | }
304 |
305 | main();
306 |
--------------------------------------------------------------------------------
/lib/connection.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * This file contains original code and/or modifications of original code.
5 | * Any modifications made by VoltDB Inc. are licensed under the following
6 | * terms and conditions:
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining
9 | * a copy of this software and associated documentation files (the
10 | * "Software"), to deal in the Software without restriction, including
11 | * without limitation the rights to use, copy, modify, merge, publish,
12 | * distribute, sublicense, and/or sell copies of the Software, and to
13 | * permit persons to whom the Software is furnished to do so, subject to
14 | * the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be
17 | * included in all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | * OTHER DEALINGS IN THE SOFTWARE.
26 | */
27 |
28 | var EventEmitter = require('events').EventEmitter,
29 | Socket = require('net').Socket,
30 | crypto = require('crypto'),
31 | util = require('util'),
32 | Message = require('./message').Message,
33 | VoltConstants = require('./voltconstants');
34 | const debug = require("debug")("voltdb-client-nodejs:VoltConnection");
35 |
36 | function VoltMessageManager(configuration) {
37 | EventEmitter.call(this);
38 | this.uid = configuration.uid || null;
39 | this.message = configuration.message || null;
40 | this.error = false;
41 | this.time = null;
42 | index = -1;
43 | }
44 |
45 | util.inherits(VoltMessageManager, EventEmitter);
46 |
47 |
48 | function VoltConnection(configuration) {
49 | EventEmitter.call(this);
50 | this.config = configuration;
51 |
52 | this.onConnect = this.onConnect.bind(this);
53 | this.onError = this.onError.bind(this);
54 | this.onRead = this.onRead.bind(this);
55 | this._send = this._send.bind(this);
56 | this._flush = this._flush.bind(this);
57 | this.isValidConnection = this.isValidConnection.bind(this);
58 | this.isBlocked = this.isBlocked.bind(this);
59 | this._checkQueryTimeout = this._checkQueryTimeout.bind(this);
60 | this._manageOustandingQueries = this._manageOustandingQueries.bind(this);
61 |
62 | this.isWritable = true;
63 | this.isLoggedIn = false;
64 | this._sendQueue = [];
65 | this._calls = {};
66 | this._callIndex = [];
67 | this._id = 0;
68 | this._overflow = new Buffer(0);
69 | this.sendCounter = 0;
70 | this.timeout = 0;
71 | this.invocations = 0;
72 | this.validConnection = true;
73 | this.blocked = false;
74 |
75 | this.outstandingQueryManager = null;
76 | this.flusher = null;
77 |
78 | }
79 |
80 | util.inherits(VoltConnection, EventEmitter);
81 |
82 | VoltConnection.prototype.initSocket = function(socket) {
83 | this.socket = socket;
84 | this.socket.on('error', this.onError);
85 | this.socket.on('data', this.onRead);
86 | this.socket.on('connect', this.onConnect);
87 | }
88 |
89 |
90 | VoltConnection.prototype.connect = function() {
91 | this.initSocket(new Socket())
92 | this.socket.connect(this.config.port, this.config.host);
93 | this.outstandingQueryManager = setInterval(this._manageOustandingQueries, this.config.queryTimeoutInterval);
94 | this.flusher = setInterval(this._flush, this.config.flushInterval);
95 | }
96 |
97 | VoltConnection.prototype.isValidConnection = function() {
98 | return this.validConnection;
99 | }
100 |
101 | VoltConnection.prototype.isBlocked = function() {
102 | return this.blocked;
103 | }
104 |
105 |
106 | // Deprecating call in favor of callProcedure
107 | VoltConnection.prototype.call = function(query, readCallback, writeCallback) {
108 | return this.callProcedure(query, readCallback, writeCallback);
109 | }
110 |
111 | VoltConnection.prototype.callProcedure = function(query, readCallback, writeCallback) {
112 | this.invocations++;
113 |
114 | var uid = this._getUID();
115 | query.setUID(uid);
116 |
117 | var vmm = new VoltMessageManager({
118 | message: query.getMessage(),
119 | uid: uid});
120 |
121 | if (readCallback) {
122 | vmm.on(VoltConstants.SESSION_EVENT.QUERY_RESPONSE, readCallback);
123 | vmm.on(VoltConstants.SESSION_EVENT.QUERY_RESPONSE_ERROR, readCallback);
124 | }
125 |
126 | if ( writeCallback ) {
127 | vmm.on(VoltConstants.SESSION_EVENT.QUERY_ALLOWED, writeCallback);
128 | }
129 | return this._send(vmm, true);
130 | }
131 |
132 |
133 |
134 | VoltConnection.prototype._getUID = function() {
135 | var id = String(this._id < 99999999 ? this._id++ : this._id = 0);
136 | var uid = this._zeros(8 - id.length).join('') + id;
137 | return uid;
138 | }
139 |
140 | VoltConnection.prototype._zeros = function(num) {
141 | var arr = new Array(num);
142 | for(var i = 0; i < num; i++) {
143 | arr[i] = 0;
144 | }
145 | return arr;
146 | }
147 |
148 | VoltConnection.prototype.close = function(callback) {
149 |
150 | debug("Closing");
151 |
152 | if(this.outstandingQueryManager) clearInterval(this.outstandingQueryManager);
153 | if(this.flusher) clearInterval(this.flusher);
154 |
155 | if(this.socket) this.socket.end();
156 |
157 | if(callback) callback();
158 | }
159 |
160 | VoltConnection.prototype.onConnect = function(results) {
161 | var service = this.config.service;
162 | var sha1 = crypto.createHash('sha1');
163 | sha1.update(this.config.password);
164 | var password = new Buffer(sha1.digest('base64'), 'base64');
165 |
166 | var message = this._getLoginMessage(password);
167 |
168 | // you must connect and send login credentials immediately.
169 | var vmm = new VoltMessageManager({
170 | message: message,
171 | uid: this._getUID()
172 | });
173 |
174 | this._send(vmm, false);
175 | }
176 |
177 | VoltConnection.prototype.onError = function(results) {
178 | this.emit(
179 | VoltConstants.SESSION_EVENT.CONNECTION,
180 | VoltConstants.STATUS_CODES.UNEXPECTED_FAILURE,
181 | VoltConstants.SESSION_EVENT.CONNECTION,
182 | this);
183 | }
184 |
185 | VoltConnection.prototype.onRead = function(buffer) {
186 | var results = null;
187 |
188 | if(this.isLoggedIn == false) {
189 | results = this._decodeLoginResult(buffer);
190 | this.isLoggedIn = true;
191 | this.validConnection = true;
192 | this.emit(VoltConstants.SESSION_EVENT.CONNECTION,
193 | VoltConstants.STATUS_CODES.SUCCESS,
194 | VoltConstants.SESSION_EVENT.CONNECTION,
195 | this);
196 | } else {
197 |
198 | var overflow = this._overflow;
199 | var data = new Buffer(overflow.length + buffer.length);
200 | var length;
201 |
202 | overflow.copy(data, 0);
203 | buffer.copy(data, overflow.length, 0);
204 | while(data.length > 4 && data.length >= ( length = Message.readInt(data) + 4)) {
205 |
206 | var msg = data.slice(0, length);
207 | data = data.slice(length);
208 | results = this._decodeQueryResult(msg);
209 |
210 | var vmm = this._calls[results.uid];
211 | if(vmm) {
212 | delete this._calls[results.uid];
213 | this.sendCounter--;
214 | vmm.emit(VoltConstants.SESSION_EVENT.QUERY_RESPONSE,
215 | VoltConstants.STATUS_CODES.SUCCESS,
216 | VoltConstants.SESSION_EVENT.QUERY_RESPONSE,
217 | results);
218 |
219 | if(this.blocked == true) {
220 | this.blocked = false;
221 | this._invokeWriteEventHandler(vmm);
222 | }
223 |
224 | } else {
225 | this.emit(
226 | VoltConstants.SESSION_EVENT.QUERY_RESPONSE_ERROR,
227 | VoltConstants.STATUS_CODES.QUERY_TOOK_TOO_LONG,
228 | VoltConstants.SESSION_EVENT.QUERY_RESPONSE_ERROR,
229 | "Query completed after an extended period but query manager was deleted" );
230 | }
231 | }
232 | this._overflow = data;
233 | }
234 | }
235 |
236 | VoltConnection.prototype._send = function(vmm, track) {
237 | var results = true;
238 | try {
239 | if(track == true) {
240 | this._calls[vmm.uid] = vmm;
241 | this._callIndex.push(vmm.uid);
242 | vmm.time = Date.now();
243 | }
244 |
245 | this._queue(vmm.message.toBuffer(), track);
246 |
247 | this.sendCounter++;
248 |
249 | if(this.blocked == false) {
250 | this._invokeWriteEventHandler(vmm);
251 | }
252 | } catch (err) {
253 | this.emit(VoltConstants.SESSION_EVENT.QUERY_DISPATCH_ERROR,
254 | VoltConstants.STATUS_CODES.UNEXPECTED_FAILURE,
255 | VoltConstants.SESSION_EVENT.QUERY_DISPATCH_ERROR,
256 | err.message);
257 | this.validConnection = false;
258 | results = false;
259 | }
260 | return results;
261 | }
262 |
263 | VoltConnection.prototype._queue = function(buffer, track) {
264 | this._sendQueue.push(buffer);
265 |
266 | if(!track || this._sendQueue.length > this.config.messageQueueSize) {
267 | this._flush();
268 | }
269 | };
270 |
271 | VoltConnection.prototype._flush = function() {
272 | debug("Flushing | Send Queue Length: %o", this._sendQueue.length);
273 | var bytes = this._sendQueue.reduce(function(bytes, buffer) {
274 | return bytes + buffer.length;
275 | }, 0);
276 | var combined = new Buffer(bytes);
277 |
278 | this._sendQueue.reduce(function(offset, buffer) {
279 | buffer.copy(combined, offset);
280 | return offset + buffer.length;
281 | }, 0);
282 |
283 | try {
284 | this.socket.write(combined);
285 | } catch (err) {
286 | this.emit(VoltConstants.SESSION_EVENT.QUERY_DISPATCH_ERROR,
287 | VoltConstants.STATUS_CODES.UNEXPECTED_FAILURE,
288 | VoltConstants.SESSION_EVENT.QUERY_DISPATCH_ERROR,
289 | err.message
290 | + ": Connection dropped to server while dispatching query. Is VoltDB Server up?");
291 | throw err;
292 | }
293 |
294 | this._sendQueue = [];
295 | };
296 |
297 | VoltConnection.prototype._invokeWriteEventHandler = function(vmm) {
298 | // only allow more writes if the queue has not breached a limit
299 | if(this.sendCounter < this.config.maxConsecutiveWrites ) {
300 | this.blocked = false;
301 | vmm.emit(VoltConstants.SESSION_EVENT.QUERY_ALLOWED,
302 | VoltConstants.STATUS_CODES.SUCCESS,
303 | VoltConstants.SESSION_EVENT.QUERY_ALLOWED,
304 | null);
305 | } else {
306 | this.blocked = true;
307 | }
308 | }
309 |
310 | VoltConnection.prototype._getLoginMessage = function(password) {
311 |
312 | var message = new Message();
313 | message.writeString(this.config.service);
314 | message.writeString(this.config.username);
315 | message.writeBinary(password);
316 | message.type = VoltConstants.MESSAGE_TYPE.LOGIN;
317 | return message;
318 | }
319 |
320 | VoltConnection.prototype._decodeLoginResult = function(buffer) {
321 | return new LoginMessage(buffer);
322 | }
323 |
324 | VoltConnection.prototype._decodeQueryResult = function(buffer) {
325 | return new QueryMessage(buffer);
326 | }
327 |
328 | VoltConnection.prototype._manageOustandingQueries = function() {
329 | var tmpCallIndex = [];
330 | var time = Date.now();
331 | var uid = null;
332 | while( uid = this._callIndex.pop()) {
333 | vmm = this._calls[uid];
334 | if(vmm && this._checkQueryTimeout(vmm, time) == false) {
335 | tmpCallIndex.push(vmm.uid);
336 | }
337 | }
338 | this._callIndex = tmpCallIndex;
339 | }
340 |
341 | VoltConnection.prototype._checkQueryTimeout = function(vmm, time) {
342 | var queryInvalidated = false;
343 | if(vmm) {
344 | if(time - vmm.time > this.config.queryTimeout) {
345 | queryInvalidated = true;
346 | this.sendCounter--;
347 | vmm.emit(VoltConstants.SESSION_EVENT.QUERY_RESPONSE_ERROR,
348 | VoltConstants.STATUS_CODES.QUERY_TOOK_TOO_LONG,
349 | VoltConstants.SESSION_EVENT.QUERY_RESPONSE_ERROR,
350 | {error : true,
351 | status : VoltConstants.STATUS_CODES.CONNECTION_TIMEOUT,
352 | statusString : 'Query timed out before server responded'
353 | });
354 |
355 | vmm.emit(VoltConstants.SESSION_EVENT.QUERY_ALLOWED,
356 | VoltConstants.STATUS_CODES.SUCCESS,
357 | VoltConstants.SESSION_EVENT.QUERY_ALLOWED,
358 | null);
359 | delete this._calls[vmm.uid];
360 | }
361 | }
362 |
363 | return queryInvalidated;
364 | }
365 |
366 | module.exports = VoltConnection;
367 |
--------------------------------------------------------------------------------
/lib/parser.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * This file contains original code and/or modifications of original code.
5 | * Any modifications made by VoltDB Inc. are licensed under the following
6 | * terms and conditions:
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining
9 | * a copy of this software and associated documentation files (the
10 | * "Software"), to deal in the Software without restriction, including
11 | * without limitation the rights to use, copy, modify, merge, publish,
12 | * distribute, sublicense, and/or sell copies of the Software, and to
13 | * permit persons to whom the Software is furnished to do so, subject to
14 | * the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be
17 | * included in all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | * OTHER DEALINGS IN THE SOFTWARE.
26 | */
27 | var BigInteger = require('bignumber').BigInteger,
28 | ctype = require('./ctype'),
29 | endian = 'big';
30 |
31 | var NullValueOf = {
32 | byte: -128,
33 | short: -32768,
34 | int: -2147483648,
35 | long: new BigInteger('-9223372036854775808'),
36 | double: -1.7E+308,
37 | decimal: '-170141183460469231731687303715884105728'
38 | };
39 |
40 | function Parser(buffer) {
41 | this.buffer = buffer || [];
42 | this.position = 0;
43 | }
44 |
45 | Parser.prototype.readBinary = function(length) {
46 | return this.buffer.slice(this.position, this.position += length);
47 | };
48 | Parser.prototype.writeBinary = function(buffer) {
49 | for(var i = 0, l = buffer.length, pos = this.position; i < l; i++) {
50 | this.buffer[pos + i] = buffer[i];
51 | }
52 | this.position += l;
53 | };
54 |
55 | Parser.prototype.readByte = function() {
56 | var res = ctype.rsint8(this.buffer, endian, this.position++);
57 | if (res === NullValueOf['byte']) {
58 | return null;
59 | } else {
60 | return res;
61 | }
62 | };
63 | Parser.prototype.writeByte = function(value) {
64 | if (value == null) {
65 | value = NullValueOf['byte'];
66 | }
67 | ctype.wsint8(value, endian, this.buffer, this.position++);
68 | };
69 |
70 | Parser.prototype.readShort = function() {
71 | var res = ctype.rsint16(this.buffer, endian, (this.position += 2) - 2);
72 | if (res === NullValueOf['short']) {
73 | return null;
74 | } else {
75 | return res;
76 | }
77 | };
78 | Parser.prototype.writeShort = function(value) {
79 | if (value == null) {
80 | value = NullValueOf['short'];
81 | }
82 | ctype.wsint16(value, endian, this.buffer, (this.position += 2) - 2);
83 | };
84 |
85 | Parser.prototype.readInt = function() {
86 | var res = ctype.rsint32(this.buffer, endian, (this.position += 4) - 4);
87 | if (res === NullValueOf['int']) {
88 | return null;
89 | } else {
90 | return res;
91 | }
92 | };
93 | Parser.prototype.writeInt = function(value) {
94 | if (value == null) {
95 | value = NullValueOf['int'];
96 | }
97 | ctype.wsint32(value, endian, this.buffer, (this.position += 4) - 4);
98 | };
99 |
100 | Parser.prototype.readDouble = function() {
101 | var res = ctype.rdouble(this.buffer, endian, (this.position += 8) - 8);
102 | if (res === NullValueOf['double']) {
103 | return null;
104 | } else {
105 | return res;
106 | }
107 | };
108 | Parser.prototype.writeDouble = function(value) {
109 | if (value == null) {
110 | value = NullValueOf['double'];
111 | }
112 | ctype.wdouble(value, endian, this.buffer, (this.position += 8) - 8);
113 | };
114 |
115 | Parser.prototype.readLongBytes = function() {
116 | var bytes = [], numBytes = 8;
117 | for(var i = 0; i < numBytes; i++) {
118 | bytes.push(ctype.ruint8(this.buffer, endian, this.position + i));
119 | }
120 | this.position += numBytes;
121 | return (new BigInteger(bytes));
122 | };
123 |
124 | Parser.prototype.readLong = function() {
125 | var res = this.readLongBytes();
126 | if (res.equals(NullValueOf['long'])) {
127 | return null;
128 | } else {
129 | return res;
130 | }
131 | };
132 | Parser.prototype.writeLong = function(value) {
133 | if (value == null) {
134 | value = NullValueOf['long'];
135 | }
136 | var bytes, numBytes = 8;
137 | if( typeof value === 'number')
138 | value = new BigInteger(value.toString());
139 | if(!( value instanceof BigInteger))
140 | throw new Error('Long type must be a BigInteger or Number');
141 | bytes = value.toByteArray();
142 | if (bytes[0] >= 0) {
143 | while (bytes.length < numBytes) {
144 | bytes.unshift(0);
145 | }
146 | } else {
147 | while (bytes.length < numBytes) {
148 | bytes.unshift(-1);
149 | }
150 | }
151 |
152 | for(var i = 0; i < numBytes; i++)
153 | ctype.wsint8(bytes[i], endian, this.buffer, this.position + i);
154 | this.position += numBytes;
155 | };
156 |
157 | Parser.prototype.readString = function() {
158 | var length = this.readInt();
159 | if (length < 0) return null;
160 | return this.buffer.toString('utf8', this.position, this.position += length);
161 | };
162 | Parser.prototype.writeString = function(value) {
163 | var length;
164 | if (value == null) {
165 | length = -1;
166 | } else {
167 | var strBuf = new Buffer(value, 'utf8');
168 | length = strBuf.length;
169 | }
170 | this.writeInt(length);
171 |
172 | for(var i = 0, pos = this.position; i < length; i++) {
173 | this.buffer[pos + i] = strBuf[i];
174 | }
175 | this.position += Math.max(0, length);
176 | };
177 |
178 | Parser.prototype.readDate = function() {
179 | var bigInt = this.readLongBytes();
180 | if (bigInt.toString() === NullValueOf['long']) {
181 | return null;
182 | } else {
183 | var intStr = bigInt.divide(thousand).toString();
184 | return new Date(parseInt(intStr));
185 | }
186 | };
187 |
188 | Parser.prototype.writeDate = function(value) {
189 | if (value == null) {
190 | this.writeLong(null);
191 | } else {
192 | var bigInt;
193 | if (value instanceof Date)
194 | value = Date.getTime();
195 | else if (typeof value !== 'number')
196 | throw new Error('Date type must be a Date or number');
197 | bigInt = new BigInteger(value.toString());
198 |
199 | this.writeLong(bigInt.multiply(thousand));
200 | }
201 | };
202 |
203 | Parser.prototype.readDecimal = function() {
204 | var bytes = [], bigInt, numBytes = 16, decimalPlaces = 12;
205 | for(var i = 0; i < numBytes; i++)
206 | bytes.push(ctype.ruint8(this.buffer, endian, this.position + i));
207 | this.position += numBytes;
208 | bigInt = new BigInteger(bytes);
209 | var val = bigInt.toString();
210 |
211 | // handle the null value case
212 | if(val === NullValueOf['decimal']) {
213 | val = null;
214 | } else if(val.length <= 12) {
215 | // add leading zeros (e.g. 123 to 0.000000000123)
216 | val = zeros(decimalPlaces - val.length).join('') + val;
217 | val = '0.' + val;
218 | } else {
219 | // put the decimal in the right place
220 | val = val.slice(0, -decimalPlaces) + '.' + val.slice(-decimalPlaces);
221 | }
222 | return val;
223 | };
224 | Parser.prototype.writeDecimal = function(value) {
225 | var bytes, bigInt, numBytes = 16;
226 | if(value == null) {
227 | bigInt = new BigInteger(NullValueOf['decimal']);
228 | } else {
229 | if (typeof value === 'number')
230 | value = value.toString();
231 | if (typeof value != 'string' || !(/^-?\d*\.?\d*$/).test(value))
232 | throw new Error('Decimal type must be a numerical string or Number:' + value);
233 |
234 | // add decimal and missing zeros
235 | if (value.startsWith('.')) {
236 | value = '0' + value;
237 | }
238 | bigInt = new BigInteger(sanitizeDecimal(value));
239 | }
240 | bytes = bigInt.toByteArray();
241 | if (bytes[0] >= 0) {
242 | while (bytes.length < numBytes) {
243 | bytes.unshift(0);
244 | }
245 | } else {
246 | while (bytes.length < numBytes) {
247 | bytes.unshift(-1);
248 | }
249 | }
250 |
251 | for(var i = 0; i < numBytes; i++)
252 | ctype.wsint8(bytes[i], endian, this.buffer, this.position + i);
253 | this.position += numBytes;
254 | };
255 |
256 | Parser.prototype.readVarbinary = function() {
257 | var length = this.readInt();
258 | if (length == -1) {
259 | return null;
260 | } else {
261 | var binary = this.buffer.slice(this.position, this.position + length);
262 | this.position += length;
263 | return binary;
264 | }
265 | }
266 |
267 | Parser.prototype.writeVarbinary = function(value) {
268 | if (value == null) {
269 | this.writeInt(-1);
270 | } else {
271 | this.writeInt(value.length);
272 | this.writeBinary(value);
273 | }
274 | }
275 |
276 | Parser.prototype.readNull = function() {
277 | // a no-op, no reading
278 | return null;
279 | };
280 | Parser.prototype.writeNull = function(value) {
281 | // a no-op, no writing
282 | };
283 |
284 | Parser.prototype.readArray = function(type, value) {
285 | type = TYPES_STRINGS[this.readByte()];
286 | if(type == undefined)
287 | throw new Error('Unsupported type, update driver');
288 |
289 | var length = (type == 'byte' ? this.readInt() : this.readShort());
290 | var method = TYPES_READ[type];
291 | value = new Array(length);
292 | for(var i = 0; i < length; i++) {
293 | value[i] = this[method]();
294 | }
295 | return value;
296 | };
297 |
298 | Parser.prototype.writeArray = function(type, value) {
299 | if(type.slice(0, 5) != 'array' && !TYPES_NUMBERS.hasOwnProperty(type))
300 | throw new Error('Type must be one of: array, null tinyint, smallint,' + ' integer, bigint, float, string, timestamp, decimal');
301 |
302 | if(!( value instanceof Array))
303 | throw new Error(('Array value must be an Array'));
304 |
305 | var length = value.length, i, match;
306 |
307 | // if it's a subarray (e.g. type = array[string])
308 | if( match = type.match(arrExp)) {
309 | this.writeByte(TYPES_NUMBERS.array);
310 | // write type 'array' -99
311 | this.writeShort(length);
312 | var arrType = match[1];
313 |
314 | // write sub-array values
315 | for( i = 0; i < length; i++) {
316 | this.writeArray(arrType, value[i])
317 | }
318 | } else {
319 | this.writeByte(TYPES_NUMBERS[type]);
320 | // write type
321 | // write length
322 | type == 'byte' ? this.writeInt(length) : this.writeShort(length);
323 | var method = TYPES_WRITE[type];
324 |
325 | // write values
326 | for( i = 0; i < length; i++) {
327 | this[method](value[i]);
328 | }
329 | }
330 | };
331 |
332 | Parser.prototype.readVoltTable = function() {
333 | // header
334 | var tableLength = this.readInt();
335 | var metaLength = this.readInt();
336 | var status = this.readByte();
337 | var columnCount = this.readShort();
338 | var columnTypes = new Array(columnCount);
339 | var columnMethods = new Array(columnCount);
340 | for(var i = 0; i < columnCount; i++) {
341 | var typeByte = this.readByte();
342 | var type = TYPES_STRINGS[typeByte];
343 | columnTypes[i] = type;
344 | columnMethods[i] = TYPES_READ[type];
345 |
346 | }
347 | var columnNames = new Array(columnCount);
348 | for( i = 0; i < columnCount; i++) {
349 | columnNames[i] = this.readString();
350 | }
351 | var rowCount = this.readInt();
352 |
353 | // data
354 | var rows = new Array(rowCount);
355 | for( i = 0; i < rowCount; i++) {
356 | var rowLength = this.readInt();
357 | var row = {};
358 | for(var j = 0; j < columnCount; j++) {
359 | row[columnNames[j]] = this[columnMethods[j]]();
360 | }
361 | rows[i] = row;
362 | }
363 |
364 | rows.status = status;
365 | rows.columnNames = columnNames;
366 | rows.columnTypes = columnTypes;
367 | return rows;
368 | };
369 |
370 | Parser.prototype.readException = function(length) {
371 | if(length == 0)
372 | new Error('An exception has occurred');
373 | var ordinal = this.readByte();
374 | // they don't have a spec for exceptions at this time, just skip it.
375 | var theRest = this.readBinary(length - 1);
376 | if(ordinal == 1)
377 | return new Error('EEException');
378 | else if(ordinal == 2)
379 | return new Error('SQLException');
380 | else if(ordinal == 3)
381 | return new Error('ConstraintFailureException');
382 | return new Error('An exception has occurred');
383 | };
384 |
385 | Parser.prototype.writeParameterSet = function(types, values) {
386 | if(types.length != values.length)
387 | throw new Error('The number of parameters do not match the number of ' + 'types defined in the definition.');
388 |
389 | var length = values.length, match;
390 | this.writeShort(length);
391 |
392 | for(var i = 0; i < length; i++) {
393 | var type = types[i];
394 | var value = values[i];
395 | checkType(type, value);
396 |
397 | // handle the array type
398 | if( match = type.match(arrExp)) {
399 | var arrType = match[1];
400 | this.writeByte(TYPES_NUMBERS.array);
401 | this.writeArray(arrType, value);
402 | } else {
403 | this.writeByte(TYPES_NUMBERS[type]);
404 | var method = TYPES_WRITE[type];
405 | this[method](value);
406 | }
407 | }
408 | };
409 | // for getting lengths from incoming data
410 | Parser.readInt = function(buffer, offset) {
411 | if(offset == undefined)
412 | offset = 0;
413 | return ctype.rsint32(buffer, endian, offset);
414 | };
415 |
416 | exports.Parser = Parser;
417 |
418 | var arrExp = /array\[(.*)\]/;
419 |
420 | var TYPES_STRINGS = {
421 | '-99' : 'array',
422 | '1' : 'null',
423 | '3' : 'byte',
424 | '4' : 'short',
425 | '5' : 'int',
426 | '6' : 'long',
427 | '8' : 'double',
428 | '9' : 'string',
429 | '11' : 'date',
430 | '22' : 'decimal',
431 | '25' : 'varbinary'
432 | };
433 |
434 | var TYPES_NUMBERS = {
435 | 'array' : -99,
436 | 'null' : 1,
437 | 'byte' : 3,
438 | 'tinyint' : 3,
439 | 'short' : 4,
440 | 'smallint' : 4,
441 | 'int' : 5,
442 | 'integer' : 5,
443 | 'long' : 6,
444 | 'bigint' : 6,
445 | 'double' : 8,
446 | 'float' : 8,
447 | 'string' : 9,
448 | 'date' : 11,
449 | 'timestamp' : 11,
450 | 'decimal' : 22,
451 | 'varbinary' : 25
452 | };
453 |
454 | var TYPES_READ = {
455 | 'array' : 'readArray',
456 | 'null' : 'readNull',
457 | 'byte' : 'readByte',
458 | 'tinyint' : 'readByte',
459 | 'short' : 'readShort',
460 | 'smallint' : 'readShort',
461 | 'int' : 'readInt',
462 | 'integer' : 'readInt',
463 | 'long' : 'readLong',
464 | 'bigint' : 'readLong',
465 | 'double' : 'readDouble',
466 | 'float' : 'readDouble',
467 | 'string' : 'readString',
468 | 'date' : 'readDate',
469 | 'timestamp' : 'readDate',
470 | 'decimal' : 'readDecimal',
471 | 'varbinary' : 'readVarbinary'
472 | };
473 | var TYPES_WRITE = {
474 | 'array' : 'writeArray',
475 | 'null' : 'writeNull',
476 | 'byte' : 'writeByte',
477 | 'tinyint' : 'writeByte',
478 | 'short' : 'writeShort',
479 | 'smallint' : 'writeShort',
480 | 'int' : 'writeInt',
481 | 'integer' : 'writeInt',
482 | 'long' : 'writeLong',
483 | 'bigint' : 'writeLong',
484 | 'double' : 'writeDouble',
485 | 'float' : 'writeDouble',
486 | 'string' : 'writeString',
487 | 'date' : 'writeDate',
488 | 'timestamp' : 'writeDate',
489 | 'decimal' : 'writeDecimal',
490 | 'varbinary' : 'writeVarbinary'
491 | };
492 |
493 | var NUMERIC_TYPES = {
494 | 'byte' : true,
495 | 'tinyint' : true,
496 | 'short' : true,
497 | 'smallint' : true,
498 | 'int' : true,
499 | 'integer' : true,
500 | 'long' : true,
501 | 'bigint' : true,
502 | 'double' : true,
503 | 'float' : true,
504 | 'date' : true,
505 | 'timestamp' : true,
506 | 'decimal' : true,
507 | 'varbinary' : true
508 | };
509 | var STRING_TYPES = {
510 | 'string' : true,
511 | 'decimal' : true
512 | };
513 | var BIGINT_TYPES = {
514 | 'long' : true,
515 | 'bigint' : true
516 | };
517 |
518 | var thousand = new BigInteger('1000');
519 |
520 | function zeros(num) {
521 | var arr = new Array(num);
522 | for(var i = 0; i < num; i++)
523 | arr[i] = 0;
524 | return arr;
525 | }
526 |
527 | function ones(num) {
528 | var arr = new Array(num);
529 | for(var i = 0; i < num; i++)
530 | arr[i] = 1;
531 | return arr;
532 | }
533 |
534 | function checkType(type, value) {
535 | if(type == 'array')
536 | throw new Error('Type array must have a subtype. E.g. array[string]');
537 |
538 | if(type.slice(0, 5) != 'array' && !TYPES_NUMBERS.hasOwnProperty(type))
539 | throw new Error('Type must be one of: array, null tinyint, smallint, ' + 'integer, bigint, float, string, timestamp, decimal');
540 |
541 | if( typeof value === 'numeric' && !NUMERIC_TYPES[type])
542 | throw new Error('Providing a numeric type for a non-numeric field. ' + value + ' can not be a ' + type);
543 |
544 | if( typeof value === 'string' && !STRING_TYPES[type])
545 | throw new Error('Providing a string type for a non-string field. ' + value + ' can not be a ' + type);
546 |
547 | if( typeof value === 'object' && !( value instanceof Array) && !( value instanceof Uint8Array) && (value != null))
548 | throw new Error('Cannot provide custom objects as procedure parameters');
549 |
550 | if( value instanceof Array && type.slice(0, 5) != 'array')
551 | throw new Error('Providing an array type for a non-array field. ' + value + ' can not be a ' + type);
552 |
553 | if(type.slice(0, 5) == 'array' && !( value instanceof Array))
554 | throw new Error('Providing a non-array value for an array field. ' + value + ' can not be a ' + type);
555 |
556 | if( value instanceof BigInteger && !BIGINT_TYPES[type])
557 | throw new Error('Providing a BigInteger type for a non-bigint field. ' + value + ' can not be a ' + type);
558 | }
559 |
560 | function sanitizeDecimal(value) {
561 | var MAX_INT_DIGIT = 26, MAX_FRAC_DIGIT = 12;
562 |
563 | var sign = '';
564 | if (value.startsWith('-')) {
565 | sign = '-';
566 | value = value.slice(1);
567 | }
568 | var parts = value.split('.');
569 | // first check if the given value is legal
570 | if (parts[0].length > MAX_INT_DIGIT) {
571 | throw new Error('The integer part should not have more than' + MAX_INT_DIGIT + 'digits.');
572 | }
573 | if (parts.length == 2 && parts[1].length > MAX_FRAC_DIGIT) {
574 | throw new Error('The fractional part should not have more than' + MAX_FRAC_DIGIT + 'digits.');
575 | }
576 |
577 | // add trailing zeros
578 | if (parts.length == 1) {
579 | return sign + parts[0] + zeros(MAX_FRAC_DIGIT).join('');
580 | } else {
581 | return sign + parts[0] + parts[1] + zeros(MAX_FRAC_DIGIT - parts[1].length).join('');
582 | }
583 | }
--------------------------------------------------------------------------------
/lib/ctype.js:
--------------------------------------------------------------------------------
1 | /* This file is part of VoltDB.
2 | * Copyright (C) 2008-2018 VoltDB Inc.
3 | *
4 | * This file contains original code and/or modifications of original code.
5 | * Any modifications made by VoltDB Inc. are licensed under the following
6 | * terms and conditions:
7 | *
8 | * Permission is hereby granted, free of charge, to any person obtaining
9 | * a copy of this software and associated documentation files (the
10 | * "Software"), to deal in the Software without restriction, including
11 | * without limitation the rights to use, copy, modify, merge, publish,
12 | * distribute, sublicense, and/or sell copies of the Software, and to
13 | * permit persons to whom the Software is furnished to do so, subject to
14 | * the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be
17 | * included in all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | * OTHER DEALINGS IN THE SOFTWARE.
26 | */
27 |
28 | /*
29 | * The following license applies to all files unless the file is specified below.
30 | * Each file specified below has its license information embedded in it:
31 | * tools/jsstyle
32 | *
33 | * Copyright 2011, Robert Mustacchi. All rights reserved.
34 | * Copyright 2011, Joyent, Inc. All rights reserved.
35 | * Permission is hereby granted, free of charge, to any person obtaining a copy
36 | * of this software and associated documentation files (the "Software"), to
37 | * deal in the Software without restriction, including without limitation the
38 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
39 | * sell copies of the Software, and to permit persons to whom the Software is
40 | * furnished to do so, subject to the following conditions:
41 | *
42 | * The above copyright notice and this permission notice shall be included in
43 | * all copies or substantial portions of the Software.
44 | *
45 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
49 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
50 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
51 | * IN THE SOFTWARE.
52 | */
53 |
54 | /*
55 | * rm - Feb 2011
56 | * ctype.js
57 | *
58 | * This module provides a simple abstraction towards reading and writing
59 | * different types of binary data. It is designed to use ctio.js and provide a
60 | * richer and more expressive API on top of it.
61 | *
62 | * By default we support the following as built in basic types:
63 | * int8_t
64 | * int16_t
65 | * int32_t
66 | * uint8_t
67 | * uint16_t
68 | * uint32_t
69 | * float
70 | * double
71 | * char
72 | * char[]
73 | *
74 | * Each type is returned as a Number, with the exception of char and char[]
75 | * which are returned as Node Buffers. A char is considered a uint8_t.
76 | *
77 | * Requests to read and write data are specified as an array of JSON objects.
78 | * This is also the same way that one declares structs. Even if just a single
79 | * value is requested, it must be done as a struct. The array order determines
80 | * the order that we try and read values. Each entry has the following format
81 | * with values marked with a * being optional.
82 | *
83 | * { key: { type: /type/, value*: /value/, offset*: /offset/ }
84 | *
85 | * If offset is defined, we lseek(offset, SEEK_SET) before reading the next
86 | * value. Value is defined when we're writing out data, otherwise it's ignored.
87 | *
88 | */
89 |
90 | var mod_ctio = require('./ctio.js');
91 | var ASSERT = require('assert');
92 |
93 | /*
94 | * This is the set of basic types that we support.
95 | *
96 | * read The function to call to read in a value from a buffer
97 | *
98 | * write The function to call to write a value to a buffer
99 | *
100 | */
101 | var deftypes = {
102 | 'uint8_t' : {
103 | read : ctReadUint8,
104 | write : ctWriteUint8
105 | },
106 | 'uint16_t' : {
107 | read : ctReadUint16,
108 | write : ctWriteUint16
109 | },
110 | 'uint32_t' : {
111 | read : ctReadUint32,
112 | write : ctWriteUint32
113 | },
114 | 'int8_t' : {
115 | read : ctReadSint8,
116 | write : ctWriteSint8
117 | },
118 | 'int16_t' : {
119 | read : ctReadSint16,
120 | write : ctWriteSint16
121 | },
122 | 'int32_t' : {
123 | read : ctReadSint32,
124 | write : ctWriteSint32
125 | },
126 | 'float' : {
127 | read : ctReadFloat,
128 | write : ctWriteFloat
129 | },
130 | 'double' : {
131 | read : ctReadDouble,
132 | write : ctWriteDouble
133 | },
134 | 'char' : {
135 | read : ctReadChar,
136 | write : ctWriteChar
137 | },
138 | 'char[]' : {
139 | read : ctReadCharArray,
140 | write : ctWriteCharArray
141 | }
142 | };
143 |
144 | /*
145 | * The following are wrappers around the CType IO low level API. They encode
146 | * knowledge about the size and return something in the expected format.
147 | */
148 | function ctReadUint8(endian, buffer, offset) {
149 | var val = mod_ctio.ruint8(buffer, endian, offset);
150 | return ( {
151 | value : val,
152 | size : 1
153 | });
154 | }
155 |
156 | function ctReadUint16(endian, buffer, offset) {
157 | var val = mod_ctio.ruint16(buffer, endian, offset);
158 | return ( {
159 | value : val,
160 | size : 2
161 | });
162 | }
163 |
164 | function ctReadUint32(endian, buffer, offset) {
165 | var val = mod_ctio.ruint32(buffer, endian, offset);
166 | return ( {
167 | value : val,
168 | size : 4
169 | });
170 | }
171 |
172 | function ctReadSint8(endian, buffer, offset) {
173 | var val = mod_ctio.rsint8(buffer, endian, offset);
174 | return ( {
175 | value : val,
176 | size : 1
177 | });
178 | }
179 |
180 | function ctReadSint16(endian, buffer, offset) {
181 | var val = mod_ctio.rsint16(buffer, endian, offset);
182 | return ( {
183 | value : val,
184 | size : 2
185 | });
186 | }
187 |
188 | function ctReadSint32(endian, buffer, offset) {
189 | var val = mod_ctio.rsint32(buffer, endian, offset);
190 | return ( {
191 | value : val,
192 | size : 4
193 | });
194 | }
195 |
196 | function ctReadFloat(endian, buffer, offset) {
197 | var val = mod_ctio.rfloat(buffer, endian, offset);
198 | return ( {
199 | value : val,
200 | size : 4
201 | });
202 | }
203 |
204 | function ctReadDouble(endian, buffer, offset) {
205 | var val = mod_ctio.rdouble(buffer, endian, offset);
206 | return ( {
207 | value : val,
208 | size : 8
209 | });
210 | }
211 |
212 | /*
213 | * Reads a single character into a node buffer
214 | */
215 | function ctReadChar(endian, buffer, offset) {
216 | var res = new Buffer(1);
217 | res[0] = mod_ctio.ruint8(buffer, endian, offset);
218 | return ( {
219 | value : res,
220 | size : 1
221 | });
222 | }
223 |
224 | function ctReadCharArray(length, endian, buffer, offset) {
225 | var ii;
226 | var res = new Buffer(length);
227 |
228 | for( ii = 0; ii < length; ii++)
229 | res[ii] = mod_ctio.ruint8(buffer, endian, offset + ii);
230 |
231 | return ( {
232 | value : res,
233 | size : length
234 | });
235 | }
236 |
237 | function ctWriteUint8(value, endian, buffer, offset) {
238 | mod_ctio.wuint8(value, endian, buffer, offset);
239 | return (1);
240 | }
241 |
242 | function ctWriteUint16(value, endian, buffer, offset) {
243 | mod_ctio.wuint16(value, endian, buffer, offset);
244 | return (2);
245 | }
246 |
247 | function ctWriteUint32(value, endian, buffer, offset) {
248 | mod_ctio.wuint32(value, endian, buffer, offset);
249 | return (4);
250 | }
251 |
252 | function ctWriteSint8(value, endian, buffer, offset) {
253 | mod_ctio.wsint8(value, endian, buffer, offset);
254 | return (1);
255 | }
256 |
257 | function ctWriteSint16(value, endian, buffer, offset) {
258 | mod_ctio.wsint16(value, endian, buffer, offset);
259 | return (2);
260 | }
261 |
262 | function ctWriteSint32(value, endian, buffer, offset) {
263 | mod_ctio.wsint32(value, endian, buffer, offset);
264 | return (4);
265 | }
266 |
267 | function ctWriteFloat(value, endian, buffer, offset) {
268 | mod_ctio.wfloat(value, endian, buffer, offset);
269 | return (4);
270 | }
271 |
272 | function ctWriteDouble(value, endian, buffer, offset) {
273 | mod_ctio.wdouble(value, endian, buffer, offset);
274 | return (8);
275 | }
276 |
277 | /*
278 | * Writes a single character into a node buffer
279 | */
280 | function ctWriteChar(value, endian, buffer, offset) {
281 | if(!( value instanceof Buffer))
282 | throw (new Error('Input must be a buffer'));
283 |
284 | mod_ctio.ruint8(value[0], endian, buffer, offset);
285 | return (1);
286 | }
287 |
288 | /*
289 | * We're going to write 0s into the buffer if the string is shorter than the
290 | * length of the array.
291 | */
292 | function ctWriteCharArray(value, length, endian, buffer, offset) {
293 | var ii;
294 |
295 | if(!( value instanceof Buffer))
296 | throw (new Error('Input must be a buffer'));
297 |
298 | if(value.length > length)
299 | throw (new Error('value length greater than array length'));
300 |
301 | for( ii = 0; ii < value.length && ii < length; ii++)
302 | mod_ctio.wuint8(value[ii], endian, buffer, offset + ii);
303 |
304 | for(; ii < length; ii++)
305 | mod_ctio.wuint8(0, endian, offset + ii);
306 |
307 | return (length);
308 | }
309 |
310 | /*
311 | * Construct a per parser specific set of the basic types. That way if this is
312 | * modified, it's okay. The values themselves should never be modified; however,
313 | * the set of keys may change over time.
314 | */
315 | function ctGetBasicTypes() {
316 | var ret = {};
317 | var key;
318 | for(key in deftypes)
319 | ret[key] = deftypes[key];
320 |
321 | return (ret);
322 | }
323 |
324 | /*
325 | * Given a string in the form of type[length] we want to split this into an
326 | * object that extracts that information. We want to note that we could possibly
327 | * have nested arrays so this should only check the furthest one. It may also be
328 | * the case that we have no [] pieces, in which case we just return the current
329 | * type.
330 | */
331 | function ctParseType(str) {
332 | var begInd, endInd;
333 | var type, len;
334 | if( typeof (str) != 'string')
335 | throw (new Error('type must be a Javascript string'));
336 | endInd = str.lastIndexOf(']');
337 | if(endInd == -1) {
338 | if(str.lastIndexOf('[') != -1)
339 | throw (new Error('found invalid type with \'[\' but ' + 'no corresponding \']\''));
340 |
341 | return ( {
342 | type : str
343 | });
344 | }
345 | begInd = str.lastIndexOf('[');
346 | if(begInd == -1)
347 | throw (new Error('found invalid type with \']\' but ' + 'no corresponding \'[\''));
348 |
349 | if(begInd >= endInd)
350 | throw (new Error('malformed type, \']\' appears before \'[\''));
351 | type = str.substring(0, begInd);
352 | len = str.substring(begInd + 1, endInd);
353 |
354 | return ( {
355 | type : type,
356 | len : len
357 | });
358 | }
359 |
360 | /*
361 | * Given a request validate that all of the fields for it are valid and make
362 | * sense. This includes verifying the following notions:
363 | * - Each type requested is present in types
364 | * - Only allow a name for a field to be specified once
365 | * - If an array is specified, validate that the requested field exists and
366 | * comes before it.
367 | * - If fields is defined, check that each entry has the occurrence of field
368 | */
369 | function ctCheckReq(def, types, fields) {
370 | var ii, jj;
371 | var req, keys, key, exists;
372 | var found = {};
373 |
374 | if(!( def instanceof Array))
375 | throw (new Error('definition is not an array'));
376 |
377 | if(def.length === 0)
378 | throw (new Error('definition must have at least one element'));
379 |
380 | for( ii = 0; ii < def.length; ii++) {
381 | req = def[ii];
382 | if(!( req instanceof Object))
383 | throw (new Error('definition must be an array of' + 'objects'));
384 | keys = Object.keys(req);
385 | if(keys.length != 1)
386 | throw (new Error('definition entry must only have ' + 'one key'));
387 |
388 | if(keys[0] in found)
389 | throw (new Error('Specified name already ' + 'specified: ' + keys[0]));
390 |
391 | if(!('type' in req[keys[0]]))
392 | throw (new Error('missing required type definition'));
393 | key = ctParseType(req[keys[0]]['type']);
394 |
395 | /*
396 | * We may have nested arrays, we need to check the validity of
397 | * the types until the len field is undefined in key. However,
398 | * each time len is defined we need to verify it is either an
399 | * integer or corresponds to an already seen key.
400 | */
401 | while(key['len'] !== undefined) {
402 | if(isNaN(parseInt(key['len'], 10))) {
403 | exists = false;
404 | if(!(key['len'] in found))
405 | throw (new Error('Given an array ' + 'length without a matching type'));
406 |
407 | }
408 | key = ctParseType(key['type']);
409 | }
410 |
411 | /* Now we can validate if the type is valid */
412 | if(!(key['type'] in types))
413 | throw (new Error('type not found or typdefed: ' + key['type']));
414 |
415 | /* Check for any required fields */
416 | if(fields !== undefined) {
417 | for( jj = 0; jj < fields.length; jj++) {
418 | if(!(fields[jj] in req[keys[0]]))
419 | throw (new Error('Missing required ' + 'field: ' + fields[jj]));
420 | }
421 | }
422 |
423 | found[keys[0]] = true;
424 | }
425 | }
426 |
427 | /*
428 | * Create a new instance of the parser. Each parser has its own store of
429 | * typedefs and endianness. Conf is an object with the following values:
430 | *
431 | * endian Either 'big' or 'little' do determine the endianness we
432 | * want to read from or write to.
433 | *
434 | */
435 | function CTypeParser(conf) {
436 | if(!conf)
437 | throw (new Error('missing required argument'));
438 |
439 | if(!('endian' in conf))
440 | throw (new Error('missing required endian value'));
441 |
442 | if(conf['endian'] != 'big' && conf['endian'] != 'little')
443 | throw (new Error('Invalid endian type'));
444 |
445 | this.endian = conf['endian'];
446 | this.types = ctGetBasicTypes();
447 | }
448 |
449 | /*
450 | * Sets the current endian value for the Parser. If the value is not valid,
451 | * throws an Error.
452 | *
453 | * endian Either 'big' or 'little' do determine the endianness we
454 | * want to read from or write to.
455 | *
456 | */
457 | CTypeParser.prototype.setEndian = function(endian) {
458 | if(endian != 'big' || endian != 'little')
459 | throw (new Error('invalid endian type, must be big or ' + ' little'));
460 |
461 | this.endian = endian;
462 | };
463 | /*
464 | * Returns the current value of the endian value for the parser.
465 | */
466 | CTypeParser.prototype.getEndian = function() {
467 | return (this.endian);
468 | };
469 | /*
470 | * A user has requested to add a type, let us honor their request. Yet, if their
471 | * request doth spurn us, send them unto the Hells which Dante describes.
472 | *
473 | * name The string for the type definition we're adding
474 | *
475 | * value Either a string that is a type/array name or an object
476 | * that describes a struct.
477 | */
478 | CTypeParser.prototype.typedef = function(name, value) {
479 | var type;
480 |
481 | if(name === undefined)
482 | throw (new (Error('missing required typedef argument: name')));
483 |
484 | if(value === undefined)
485 | throw (new (Error('missing required typedef argument: value')));
486 |
487 | if( typeof (name) != 'string')
488 | throw (new (Error('the name of a type must be a string')));
489 | type = ctParseType(name);
490 |
491 | if(type['len'] !== undefined)
492 | throw (new Error('Cannot have an array in the typedef name'));
493 |
494 | if( name in this.types)
495 | throw (new Error('typedef name already present: ' + name));
496 |
497 | if( typeof (value) != 'string' && !( value instanceof Array))
498 | throw (new Error('typedef value must either be a string or ' + 'struct'));
499 |
500 | if( typeof (value) == 'string') {
501 | type = ctParseType(value);
502 | if(type['len'] !== undefined) {
503 | if(isNaN(parseInt(type['len'], 10)))
504 | throw (new (Error('typedef value must use ' +
505 | 'fixed size array when outside of a ' +
506 | 'struct')));
507 | }
508 |
509 | this.types[name] = value;
510 | } else {
511 | /* We have a struct, validate it */
512 | ctCheckReq(value, this.types);
513 | this.types[name] = value;
514 | }
515 | };
516 | /*
517 | * Include all of the typedefs, but none of the built in types. This should be
518 | * treated as read-only.
519 | */
520 | CTypeParser.prototype.lstypes = function() {
521 | var key;
522 | var ret = {};
523 |
524 | for(key in this.types) {
525 | if( key in deftypes)
526 | continue;
527 | ret[key] = this.types[key];
528 | }
529 |
530 | return (ret);
531 | };
532 | /*
533 | * Given a type string that may have array types that aren't numbers, try and
534 | * fill them in from the values object. The object should be of the format where
535 | * indexing into it should return a number for that type.
536 | *
537 | * str The type string
538 | *
539 | * values An object that can be used to fulfill type information
540 | */
541 | function ctResolveArray(str, values) {
542 | var ret = '';
543 | var type = ctParseType(str);
544 |
545 | while(type['len'] !== undefined) {
546 | if(isNaN(parseInt(type['len'], 10))) {
547 | if( typeof (values[type['len']]) != 'number')
548 | throw (new Error('cannot sawp in non-number ' + 'for array value'));
549 | ret = '[' + values[type['len']] + ']' + ret;
550 | } else {
551 | ret = '[' + type['len'] + ']' + ret;
552 | }
553 | type = ctParseType(type['type']);
554 | }
555 | ret = type['type'] + ret;
556 |
557 | return (ret);
558 | }
559 |
560 | /*
561 | * [private] Either the typedef resolves to another type string or to a struct.
562 | * If it resolves to a struct, we just pass it off to read struct. If not, we
563 | * can just pass it off to read entry.
564 | */
565 | CTypeParser.prototype.resolveTypedef = function(type, dispatch, buffer, offset, value) {
566 | var pt;
567 | console.log(type);
568 | ASSERT.ok( type in this.types);
569 | console.log(type + ':' + this.types[type]);
570 | if( typeof (this.types[type]) == 'string') {
571 | pt = ctParseType(this.types[type]);
572 | if(dispatch == 'read')
573 | return (this.readEntry(pt, buffer, offset));
574 | else if(dispatch == 'write')
575 | return (this.writeEntry(value, pt, buffer, offset));
576 | else
577 | throw (new Error('invalid dispatch type to ' + 'resolveTypedef'));
578 | } else {
579 | if(dispatch == 'read')
580 | return (this.readStruct(this.types[type], buffer, offset));
581 | else if(dispatch == 'write')
582 | return (this.readStruct(value, this.types[type], buffer, offset));
583 | else
584 | throw (new Error('invalid dispatch type to ' + 'resolveTypedef'));
585 | }
586 |
587 | };
588 | /*
589 | * [private] Try and read in the specific entry.
590 | */
591 | CTypeParser.prototype.readEntry = function(type, buffer, offset) {
592 | var parse, len;
593 |
594 | /*
595 | * Because we want to special case char[]s this is unfortunately
596 | * a bit uglier than it really should be. We want to special
597 | * case char[]s so that we return a node buffer, thus they are a
598 | * first class type where as all other arrays just call into a
599 | * generic array routine which calls their data-specific routine
600 | * the specified number of times.
601 | *
602 | * The valid dispatch options we have are:
603 | * - Array and char => char[] handler
604 | * - Generic array handler
605 | * - Generic typedef handler
606 | * - Basic type handler
607 | */
608 | if(type['len'] !== undefined) {
609 | len = parseInt(type['len'], 10);
610 | if(isNaN(len))
611 | throw (new Error('somehow got a non-numeric length'));
612 |
613 | if(type['type'] == 'char')
614 | parse = deftypes['char[]']['read'](len, this.endian, buffer, offset);
615 | else
616 | parse = this.readArray(type['type'], len, buffer, offset);
617 | } else {
618 | if(type['type'] in deftypes)
619 | parse = deftypes[type['type']]['read'](this.endian, buffer, offset);
620 | else
621 | parse = this.resolveTypedef(type['type'], 'read', buffer, offset);
622 | }
623 |
624 | return (parse);
625 | };
626 | /*
627 | * [private] Read an array of data
628 | */
629 | CTypeParser.prototype.readArray = function(type, length, buffer, offset) {
630 | var ii, ent, pt;
631 | var baseOffset = offset;
632 | var ret = new Array(length);
633 | pt = ctParseType(type);
634 |
635 | for( ii = 0; ii < length; ii++) {
636 | ent = this.readEntry(pt, buffer, offset);
637 | offset += ent['size'];
638 | ret[ii] = ent['value'];
639 | }
640 |
641 | return ( {
642 | value : ret,
643 | size : offset - baseOffset
644 | });
645 | };
646 | /*
647 | * [private] Read a single struct in.
648 | */
649 | CTypeParser.prototype.readStruct = function(def, buffer, offset) {
650 | var parse, ii, type, entry, key;
651 | var baseOffset = offset;
652 | var ret = {};
653 |
654 | /* Walk it and handle doing what's necessary */
655 | for( ii = 0; ii < def.length; ii++) {
656 | key = Object.keys(def[ii])[0];
657 | entry = def[ii][key];
658 |
659 | /* Resolve all array values */
660 | type = ctParseType(ctResolveArray(entry['type'], ret));
661 |
662 | if('offset' in entry)
663 | offset = baseOffset + entry['offset'];
664 | parse = this.readEntry(type, buffer, offset);
665 | offset += parse['size'];
666 | ret[key] = parse['value'];
667 | }
668 |
669 | return ( {
670 | values : ret,
671 | size : (offset - baseOffset)
672 | });
673 | };
674 | /*
675 | * This is what we were born to do. We read the data from a buffer and return it
676 | * in an object whose keys match the values from the object.
677 | *
678 | * def The array definition of the data to read in
679 | *
680 | * buffer The buffer to read data from
681 | *
682 | * offset The offset to start writing to
683 | *
684 | * Returns an object where each key corresponds to an entry in def and the value
685 | * is the read value.
686 | */
687 | CTypeParser.prototype.readData = function(def, buffer, offset) {
688 | /* Sanity check for arguments */
689 | if(def === undefined)
690 | throw (new Error('missing definition for what we should be' + 'parsing'));
691 |
692 | if(buffer === undefined)
693 | throw (new Error('missing buffer for what we should be' + 'parsing'));
694 |
695 | if(offset === undefined)
696 | throw (new Error('missing offset for what we should be' + 'parsing'));
697 |
698 | /* Sanity check the object definition */
699 | ctCheckReq(def, this.types);
700 |
701 | return (this.readStruct(def, buffer, offset)['values']);
702 | };
703 | /*
704 | * [private] Write out an array of data
705 | */
706 | CTypeParser.prototype.writeArray = function(value, type, length, buffer, offset) {
707 | var ii, pt;
708 | var baseOffset = offset;
709 | if(!( value instanceof Array))
710 | throw (new Error('asked to write an array, but value is not ' + 'an array'));
711 |
712 | if(value.length != length)
713 | throw (new Error('asked to write array of length ' + length + ' but that does not match value length: ' + value.length));
714 | pt = ctParseType(type);
715 | for( ii = 0; ii < length; ii++)
716 | offset += this.writeEntry(value[ii], pt, buffer, offset);
717 |
718 | return (offset - baseOffset);
719 | };
720 | /*
721 | * [private] Write the specific entry
722 | */
723 | CTypeParser.prototype.writeEntry = function(value, type, buffer, offset) {
724 | var len, ret;
725 |
726 | if(type['len'] !== undefined) {
727 | len = parseInt(type['len'], 10);
728 | if(isNaN(len))
729 | throw (new Error('somehow got a non-numeric length'));
730 |
731 | if(type['type'] == 'char')
732 | ret = deftypes['char[]']['write'](value, len, this.endian, buffer, offset);
733 | else
734 | ret = this.writeArray(value, type['type'], len, buffer, offset);
735 | } else {
736 | if(type['type'] in deftypes)
737 | ret = deftypes[type['type']]['write'](value, this.endian, buffer, offset);
738 | else
739 | ret = this.resolveTypedef(type['type'], 'write', buffer, offset, value);
740 | }
741 |
742 | return (ret);
743 | };
744 | /*
745 | * [private] Write a single struct out.
746 | */
747 | CTypeParser.prototype.writeStruct = function(def, buffer, offset) {
748 | var ii, entry, type, key;
749 | var baseOffset = offset;
750 | var vals = {};
751 |
752 | for( ii = 0; ii < def.length; ii++) {
753 | key = Object.keys(def[ii])[0];
754 | entry = def[ii][key];
755 | type = ctParseType(ctResolveArray(entry['type'], vals));
756 |
757 | if('offset' in entry)
758 | offset = baseOffset + entry['offset'];
759 | offset += this.writeEntry(entry['value'], type, buffer, offset);
760 |
761 | /* Now that we've written it out, we can use it for arrays */
762 | vals[key] = entry['value'];
763 | }
764 | };
765 | /*
766 | * This is the second half of what we were born to do, write out the data
767 | * itself.
768 | *
769 | * def The array definition of the data to write out with
770 | * values
771 | *
772 | * buffer The buffer to write to
773 | *
774 | * offset The offset in the buffer to write to
775 | */
776 | CTypeParser.prototype.write = function(def, buffer, offset) {
777 | if(def === undefined)
778 | throw (new Error('missing definition for what we should be' + 'parsing'));
779 |
780 | if(buffer === undefined)
781 | throw (new Error('missing buffer for what we should be' + 'parsing'));
782 |
783 | if(offset === undefined)
784 | throw (new Error('missing offset for what we should be' + 'parsing'));
785 |
786 | ctCheckReq(def, this.types, ['value']);
787 |
788 | this.writeStruct(def, buffer, offset);
789 | };
790 | /*
791 | * Functions to go to and from 64 bit numbers in a way that is compatible with
792 | * Javascript limitations. There are two sets. One where the user is okay with
793 | * an approximation and one where they are definitely not okay with an
794 | * approximation.
795 | */
796 |
797 | /*
798 | * Attempts to convert an array of two integers returned from rsint64 / ruint64
799 | * into an absolute 64 bit number. If however the value would exceed 2^52 this
800 | * will instead throw an error. The mantissa in a double is a 52 bit number and
801 | * rather than potentially give you a value that is an approximation this will
802 | * error. If you would rather an approximation, please see toApprox64.
803 | *
804 | * val An array of two 32-bit integers
805 | */
806 | function toAbs64(val) {
807 | if(val === undefined)
808 | throw (new Error('missing required arg: value'));
809 |
810 | if(!( val instanceof Array))
811 | throw (new Error('value must be an array'));
812 |
813 | if(val.length != 2)
814 | throw (new Error('value must be an array of length 2'));
815 |
816 | /* We have 20 bits worth of precision in this range */
817 | if(val[0] >= 0x100000)
818 | throw (new Error('value would become approximated'));
819 |
820 | return (val[0] * Math.pow(2, 32) + val[1]);
821 | }
822 |
823 | /*
824 | * Will return the 64 bit value as returned in an array from rsint64 / ruint64
825 | * to a value as close as it can. Note that Javascript stores all numbers as a
826 | * double and the mantissa only has 52 bits. Thus this version may approximate
827 | * the value.
828 | *
829 | * val An array of two 32-bit integers
830 | */
831 | function toApprox64(val) {
832 | if(val === undefined)
833 | throw (new Error('missing required arg: value'));
834 |
835 | if(!( val instanceof Array))
836 | throw (new Error('value must be an array'));
837 |
838 | if(val.length != 2)
839 | throw (new Error('value must be an array of length 2'));
840 |
841 | return (Math.pow(2, 32) * val[0] + val[1]);
842 | }
843 |
844 | /*
845 | * Export the few things we actually want to. Currently this is just the CType
846 | * Parser and ctio.
847 | */
848 | exports.Parser = CTypeParser;
849 |
850 | exports.ruint8 = mod_ctio.ruint8;
851 | exports.ruint16 = mod_ctio.ruint16;
852 | exports.ruint32 = mod_ctio.ruint32;
853 | exports.ruint64 = mod_ctio.ruint64;
854 | exports.wuint8 = mod_ctio.wuint8;
855 | exports.wuint16 = mod_ctio.wuint16;
856 | exports.wuint32 = mod_ctio.wuint32;
857 | exports.wuint64 = mod_ctio.wuint64;
858 |
859 | exports.rsint8 = mod_ctio.rsint8;
860 | exports.rsint16 = mod_ctio.rsint16;
861 | exports.rsint32 = mod_ctio.rsint32;
862 | exports.rsint64 = mod_ctio.rsint64;
863 | exports.wsint8 = mod_ctio.wsint8;
864 | exports.wsint16 = mod_ctio.wsint16;
865 | exports.wsint32 = mod_ctio.wsint32;
866 | exports.wsint64 = mod_ctio.wsint64;
867 |
868 | exports.rfloat = mod_ctio.rfloat;
869 | exports.rdouble = mod_ctio.rdouble;
870 | exports.wfloat = mod_ctio.wfloat;
871 | exports.wdouble = mod_ctio.wdouble;
872 | exports.deftypes = deftypes
--------------------------------------------------------------------------------
/examples/voter/voter/public/stylesheets/jquery-ui-1.8.17.custom.css:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery UI CSS Framework 1.8.17
3 | *
4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
5 | * Dual licensed under the MIT or GPL Version 2 licenses.
6 | * http://jquery.org/license
7 | *
8 | * http://docs.jquery.com/UI/Theming/API
9 | */
10 |
11 | /* Layout helpers
12 | ----------------------------------*/
13 | .ui-helper-hidden { display: none; }
14 | .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px, 1px, 1px, 1px); clip: rect(1px,1px,1px,1px); }
15 | .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
16 | .ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
17 | .ui-helper-clearfix:after { clear: both; }
18 | .ui-helper-clearfix { zoom: 1; }
19 | .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
20 |
21 |
22 | /* Interaction Cues
23 | ----------------------------------*/
24 | .ui-state-disabled { cursor: default !important; }
25 |
26 |
27 | /* Icons
28 | ----------------------------------*/
29 |
30 | /* states and images */
31 | .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
32 |
33 |
34 | /* Misc visuals
35 | ----------------------------------*/
36 |
37 | /* Overlays */
38 | .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
39 |
40 |
41 | /*
42 | * jQuery UI CSS Framework 1.8.17
43 | *
44 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
45 | * Dual licensed under the MIT or GPL Version 2 licenses.
46 | * http://jquery.org/license
47 | *
48 | * http://docs.jquery.com/UI/Theming/API
49 | *
50 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
51 | */
52 |
53 |
54 | /* Component containers
55 | ----------------------------------*/
56 | .ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; }
57 | .ui-widget .ui-widget { font-size: 1em; }
58 | .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; }
59 | .ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; }
60 | .ui-widget-content a { color: #333333; }
61 | .ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
62 | .ui-widget-header a { color: #ffffff; }
63 |
64 | /* Interaction states
65 | ----------------------------------*/
66 | .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; }
67 | .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; }
68 | .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; }
69 | .ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; }
70 | .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; }
71 | .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; }
72 | .ui-widget :active { outline: none; }
73 |
74 | /* Interaction Cues
75 | ----------------------------------*/
76 | .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; }
77 | .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
78 | .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; }
79 | .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
80 | .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
81 | .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
82 | .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
83 | .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
84 |
85 | /* Icons
86 | ----------------------------------*/
87 |
88 | /* states and images */
89 | .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
90 | .ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
91 | .ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
92 | .ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); }
93 | .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
94 | .ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
95 | .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); }
96 | .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); }
97 |
98 | /* positioning */
99 | .ui-icon-carat-1-n { background-position: 0 0; }
100 | .ui-icon-carat-1-ne { background-position: -16px 0; }
101 | .ui-icon-carat-1-e { background-position: -32px 0; }
102 | .ui-icon-carat-1-se { background-position: -48px 0; }
103 | .ui-icon-carat-1-s { background-position: -64px 0; }
104 | .ui-icon-carat-1-sw { background-position: -80px 0; }
105 | .ui-icon-carat-1-w { background-position: -96px 0; }
106 | .ui-icon-carat-1-nw { background-position: -112px 0; }
107 | .ui-icon-carat-2-n-s { background-position: -128px 0; }
108 | .ui-icon-carat-2-e-w { background-position: -144px 0; }
109 | .ui-icon-triangle-1-n { background-position: 0 -16px; }
110 | .ui-icon-triangle-1-ne { background-position: -16px -16px; }
111 | .ui-icon-triangle-1-e { background-position: -32px -16px; }
112 | .ui-icon-triangle-1-se { background-position: -48px -16px; }
113 | .ui-icon-triangle-1-s { background-position: -64px -16px; }
114 | .ui-icon-triangle-1-sw { background-position: -80px -16px; }
115 | .ui-icon-triangle-1-w { background-position: -96px -16px; }
116 | .ui-icon-triangle-1-nw { background-position: -112px -16px; }
117 | .ui-icon-triangle-2-n-s { background-position: -128px -16px; }
118 | .ui-icon-triangle-2-e-w { background-position: -144px -16px; }
119 | .ui-icon-arrow-1-n { background-position: 0 -32px; }
120 | .ui-icon-arrow-1-ne { background-position: -16px -32px; }
121 | .ui-icon-arrow-1-e { background-position: -32px -32px; }
122 | .ui-icon-arrow-1-se { background-position: -48px -32px; }
123 | .ui-icon-arrow-1-s { background-position: -64px -32px; }
124 | .ui-icon-arrow-1-sw { background-position: -80px -32px; }
125 | .ui-icon-arrow-1-w { background-position: -96px -32px; }
126 | .ui-icon-arrow-1-nw { background-position: -112px -32px; }
127 | .ui-icon-arrow-2-n-s { background-position: -128px -32px; }
128 | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
129 | .ui-icon-arrow-2-e-w { background-position: -160px -32px; }
130 | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
131 | .ui-icon-arrowstop-1-n { background-position: -192px -32px; }
132 | .ui-icon-arrowstop-1-e { background-position: -208px -32px; }
133 | .ui-icon-arrowstop-1-s { background-position: -224px -32px; }
134 | .ui-icon-arrowstop-1-w { background-position: -240px -32px; }
135 | .ui-icon-arrowthick-1-n { background-position: 0 -48px; }
136 | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
137 | .ui-icon-arrowthick-1-e { background-position: -32px -48px; }
138 | .ui-icon-arrowthick-1-se { background-position: -48px -48px; }
139 | .ui-icon-arrowthick-1-s { background-position: -64px -48px; }
140 | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
141 | .ui-icon-arrowthick-1-w { background-position: -96px -48px; }
142 | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
143 | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
144 | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
145 | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
146 | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
147 | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
148 | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
149 | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
150 | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
151 | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
152 | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
153 | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
154 | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
155 | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
156 | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
157 | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
158 | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
159 | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
160 | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
161 | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
162 | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
163 | .ui-icon-arrow-4 { background-position: 0 -80px; }
164 | .ui-icon-arrow-4-diag { background-position: -16px -80px; }
165 | .ui-icon-extlink { background-position: -32px -80px; }
166 | .ui-icon-newwin { background-position: -48px -80px; }
167 | .ui-icon-refresh { background-position: -64px -80px; }
168 | .ui-icon-shuffle { background-position: -80px -80px; }
169 | .ui-icon-transfer-e-w { background-position: -96px -80px; }
170 | .ui-icon-transferthick-e-w { background-position: -112px -80px; }
171 | .ui-icon-folder-collapsed { background-position: 0 -96px; }
172 | .ui-icon-folder-open { background-position: -16px -96px; }
173 | .ui-icon-document { background-position: -32px -96px; }
174 | .ui-icon-document-b { background-position: -48px -96px; }
175 | .ui-icon-note { background-position: -64px -96px; }
176 | .ui-icon-mail-closed { background-position: -80px -96px; }
177 | .ui-icon-mail-open { background-position: -96px -96px; }
178 | .ui-icon-suitcase { background-position: -112px -96px; }
179 | .ui-icon-comment { background-position: -128px -96px; }
180 | .ui-icon-person { background-position: -144px -96px; }
181 | .ui-icon-print { background-position: -160px -96px; }
182 | .ui-icon-trash { background-position: -176px -96px; }
183 | .ui-icon-locked { background-position: -192px -96px; }
184 | .ui-icon-unlocked { background-position: -208px -96px; }
185 | .ui-icon-bookmark { background-position: -224px -96px; }
186 | .ui-icon-tag { background-position: -240px -96px; }
187 | .ui-icon-home { background-position: 0 -112px; }
188 | .ui-icon-flag { background-position: -16px -112px; }
189 | .ui-icon-calendar { background-position: -32px -112px; }
190 | .ui-icon-cart { background-position: -48px -112px; }
191 | .ui-icon-pencil { background-position: -64px -112px; }
192 | .ui-icon-clock { background-position: -80px -112px; }
193 | .ui-icon-disk { background-position: -96px -112px; }
194 | .ui-icon-calculator { background-position: -112px -112px; }
195 | .ui-icon-zoomin { background-position: -128px -112px; }
196 | .ui-icon-zoomout { background-position: -144px -112px; }
197 | .ui-icon-search { background-position: -160px -112px; }
198 | .ui-icon-wrench { background-position: -176px -112px; }
199 | .ui-icon-gear { background-position: -192px -112px; }
200 | .ui-icon-heart { background-position: -208px -112px; }
201 | .ui-icon-star { background-position: -224px -112px; }
202 | .ui-icon-link { background-position: -240px -112px; }
203 | .ui-icon-cancel { background-position: 0 -128px; }
204 | .ui-icon-plus { background-position: -16px -128px; }
205 | .ui-icon-plusthick { background-position: -32px -128px; }
206 | .ui-icon-minus { background-position: -48px -128px; }
207 | .ui-icon-minusthick { background-position: -64px -128px; }
208 | .ui-icon-close { background-position: -80px -128px; }
209 | .ui-icon-closethick { background-position: -96px -128px; }
210 | .ui-icon-key { background-position: -112px -128px; }
211 | .ui-icon-lightbulb { background-position: -128px -128px; }
212 | .ui-icon-scissors { background-position: -144px -128px; }
213 | .ui-icon-clipboard { background-position: -160px -128px; }
214 | .ui-icon-copy { background-position: -176px -128px; }
215 | .ui-icon-contact { background-position: -192px -128px; }
216 | .ui-icon-image { background-position: -208px -128px; }
217 | .ui-icon-video { background-position: -224px -128px; }
218 | .ui-icon-script { background-position: -240px -128px; }
219 | .ui-icon-alert { background-position: 0 -144px; }
220 | .ui-icon-info { background-position: -16px -144px; }
221 | .ui-icon-notice { background-position: -32px -144px; }
222 | .ui-icon-help { background-position: -48px -144px; }
223 | .ui-icon-check { background-position: -64px -144px; }
224 | .ui-icon-bullet { background-position: -80px -144px; }
225 | .ui-icon-radio-off { background-position: -96px -144px; }
226 | .ui-icon-radio-on { background-position: -112px -144px; }
227 | .ui-icon-pin-w { background-position: -128px -144px; }
228 | .ui-icon-pin-s { background-position: -144px -144px; }
229 | .ui-icon-play { background-position: 0 -160px; }
230 | .ui-icon-pause { background-position: -16px -160px; }
231 | .ui-icon-seek-next { background-position: -32px -160px; }
232 | .ui-icon-seek-prev { background-position: -48px -160px; }
233 | .ui-icon-seek-end { background-position: -64px -160px; }
234 | .ui-icon-seek-start { background-position: -80px -160px; }
235 | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
236 | .ui-icon-seek-first { background-position: -80px -160px; }
237 | .ui-icon-stop { background-position: -96px -160px; }
238 | .ui-icon-eject { background-position: -112px -160px; }
239 | .ui-icon-volume-off { background-position: -128px -160px; }
240 | .ui-icon-volume-on { background-position: -144px -160px; }
241 | .ui-icon-power { background-position: 0 -176px; }
242 | .ui-icon-signal-diag { background-position: -16px -176px; }
243 | .ui-icon-signal { background-position: -32px -176px; }
244 | .ui-icon-battery-0 { background-position: -48px -176px; }
245 | .ui-icon-battery-1 { background-position: -64px -176px; }
246 | .ui-icon-battery-2 { background-position: -80px -176px; }
247 | .ui-icon-battery-3 { background-position: -96px -176px; }
248 | .ui-icon-circle-plus { background-position: 0 -192px; }
249 | .ui-icon-circle-minus { background-position: -16px -192px; }
250 | .ui-icon-circle-close { background-position: -32px -192px; }
251 | .ui-icon-circle-triangle-e { background-position: -48px -192px; }
252 | .ui-icon-circle-triangle-s { background-position: -64px -192px; }
253 | .ui-icon-circle-triangle-w { background-position: -80px -192px; }
254 | .ui-icon-circle-triangle-n { background-position: -96px -192px; }
255 | .ui-icon-circle-arrow-e { background-position: -112px -192px; }
256 | .ui-icon-circle-arrow-s { background-position: -128px -192px; }
257 | .ui-icon-circle-arrow-w { background-position: -144px -192px; }
258 | .ui-icon-circle-arrow-n { background-position: -160px -192px; }
259 | .ui-icon-circle-zoomin { background-position: -176px -192px; }
260 | .ui-icon-circle-zoomout { background-position: -192px -192px; }
261 | .ui-icon-circle-check { background-position: -208px -192px; }
262 | .ui-icon-circlesmall-plus { background-position: 0 -208px; }
263 | .ui-icon-circlesmall-minus { background-position: -16px -208px; }
264 | .ui-icon-circlesmall-close { background-position: -32px -208px; }
265 | .ui-icon-squaresmall-plus { background-position: -48px -208px; }
266 | .ui-icon-squaresmall-minus { background-position: -64px -208px; }
267 | .ui-icon-squaresmall-close { background-position: -80px -208px; }
268 | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
269 | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
270 | .ui-icon-grip-solid-vertical { background-position: -32px -224px; }
271 | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
272 | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
273 | .ui-icon-grip-diagonal-se { background-position: -80px -224px; }
274 |
275 |
276 | /* Misc visuals
277 | ----------------------------------*/
278 |
279 | /* Corner radius */
280 | .ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
281 | .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
282 | .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
283 | .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
284 |
285 | /* Overlays */
286 | .ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); }
287 | .ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/*
288 | * jQuery UI Accordion 1.8.17
289 | *
290 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
291 | * Dual licensed under the MIT or GPL Version 2 licenses.
292 | * http://jquery.org/license
293 | *
294 | * http://docs.jquery.com/UI/Accordion#theming
295 | */
296 | /* IE/Win - Fix animation bug - #4615 */
297 | .ui-accordion { width: 100%; }
298 | .ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
299 | .ui-accordion .ui-accordion-li-fix { display: inline; }
300 | .ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
301 | .ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
302 | .ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
303 | .ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
304 | .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
305 | .ui-accordion .ui-accordion-content-active { display: block; }
306 | /*
307 | * jQuery UI Autocomplete 1.8.17
308 | *
309 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
310 | * Dual licensed under the MIT or GPL Version 2 licenses.
311 | * http://jquery.org/license
312 | *
313 | * http://docs.jquery.com/UI/Autocomplete#theming
314 | */
315 | .ui-autocomplete { position: absolute; cursor: default; }
316 |
317 | /* workarounds */
318 | * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
319 |
320 | /*
321 | * jQuery UI Menu 1.8.17
322 | *
323 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
324 | * Dual licensed under the MIT or GPL Version 2 licenses.
325 | * http://jquery.org/license
326 | *
327 | * http://docs.jquery.com/UI/Menu#theming
328 | */
329 | .ui-menu {
330 | list-style:none;
331 | padding: 2px;
332 | margin: 0;
333 | display:block;
334 | float: left;
335 | }
336 | .ui-menu .ui-menu {
337 | margin-top: -3px;
338 | }
339 | .ui-menu .ui-menu-item {
340 | margin:0;
341 | padding: 0;
342 | zoom: 1;
343 | float: left;
344 | clear: left;
345 | width: 100%;
346 | }
347 | .ui-menu .ui-menu-item a {
348 | text-decoration:none;
349 | display:block;
350 | padding:.2em .4em;
351 | line-height:1.5;
352 | zoom:1;
353 | }
354 | .ui-menu .ui-menu-item a.ui-state-hover,
355 | .ui-menu .ui-menu-item a.ui-state-active {
356 | font-weight: normal;
357 | margin: -1px;
358 | }
359 | /*
360 | * jQuery UI Button 1.8.17
361 | *
362 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
363 | * Dual licensed under the MIT or GPL Version 2 licenses.
364 | * http://jquery.org/license
365 | *
366 | * http://docs.jquery.com/UI/Button#theming
367 | */
368 | .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
369 | .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
370 | button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
371 | .ui-button-icons-only { width: 3.4em; }
372 | button.ui-button-icons-only { width: 3.7em; }
373 |
374 | /*button text element */
375 | .ui-button .ui-button-text { display: block; line-height: 1.4; }
376 | .ui-button-text-only .ui-button-text { padding: .4em 1em; }
377 | .ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
378 | .ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
379 | .ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
380 | .ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
381 | /* no icon support for input elements, provide padding by default */
382 | input.ui-button { padding: .4em 1em; }
383 |
384 | /*button icon element(s) */
385 | .ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
386 | .ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
387 | .ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
388 | .ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
389 | .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
390 |
391 | /*button sets*/
392 | .ui-buttonset { margin-right: 7px; }
393 | .ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
394 |
395 | /* workarounds */
396 | button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
397 | /*
398 | * jQuery UI Dialog 1.8.17
399 | *
400 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
401 | * Dual licensed under the MIT or GPL Version 2 licenses.
402 | * http://jquery.org/license
403 | *
404 | * http://docs.jquery.com/UI/Dialog#theming
405 | */
406 | .ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
407 | .ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
408 | .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
409 | .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
410 | .ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
411 | .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
412 | .ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
413 | .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
414 | .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
415 | .ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
416 | .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
417 | .ui-draggable .ui-dialog-titlebar { cursor: move; }
418 | /*
419 | * jQuery UI Slider 1.8.17
420 | *
421 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
422 | * Dual licensed under the MIT or GPL Version 2 licenses.
423 | * http://jquery.org/license
424 | *
425 | * http://docs.jquery.com/UI/Slider#theming
426 | */
427 | .ui-slider { position: relative; text-align: left; }
428 | .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
429 | .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
430 |
431 | .ui-slider-horizontal { height: .8em; }
432 | .ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
433 | .ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
434 | .ui-slider-horizontal .ui-slider-range-min { left: 0; }
435 | .ui-slider-horizontal .ui-slider-range-max { right: 0; }
436 |
437 | .ui-slider-vertical { width: .8em; height: 100px; }
438 | .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
439 | .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
440 | .ui-slider-vertical .ui-slider-range-min { bottom: 0; }
441 | .ui-slider-vertical .ui-slider-range-max { top: 0; }/*
442 | * jQuery UI Tabs 1.8.17
443 | *
444 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
445 | * Dual licensed under the MIT or GPL Version 2 licenses.
446 | * http://jquery.org/license
447 | *
448 | * http://docs.jquery.com/UI/Tabs#theming
449 | */
450 | .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
451 | .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
452 | .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
453 | .ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
454 | .ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
455 | .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
456 | .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
457 | .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
458 | .ui-tabs .ui-tabs-hide { display: none !important; }
459 | /*
460 | * jQuery UI Datepicker 1.8.17
461 | *
462 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
463 | * Dual licensed under the MIT or GPL Version 2 licenses.
464 | * http://jquery.org/license
465 | *
466 | * http://docs.jquery.com/UI/Datepicker#theming
467 | */
468 | .ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
469 | .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
470 | .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
471 | .ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
472 | .ui-datepicker .ui-datepicker-prev { left:2px; }
473 | .ui-datepicker .ui-datepicker-next { right:2px; }
474 | .ui-datepicker .ui-datepicker-prev-hover { left:1px; }
475 | .ui-datepicker .ui-datepicker-next-hover { right:1px; }
476 | .ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
477 | .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
478 | .ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
479 | .ui-datepicker select.ui-datepicker-month-year {width: 100%;}
480 | .ui-datepicker select.ui-datepicker-month,
481 | .ui-datepicker select.ui-datepicker-year { width: 49%;}
482 | .ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
483 | .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
484 | .ui-datepicker td { border: 0; padding: 1px; }
485 | .ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
486 | .ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
487 | .ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
488 | .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
489 |
490 | /* with multiple calendars */
491 | .ui-datepicker.ui-datepicker-multi { width:auto; }
492 | .ui-datepicker-multi .ui-datepicker-group { float:left; }
493 | .ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
494 | .ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
495 | .ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
496 | .ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
497 | .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
498 | .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
499 | .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
500 | .ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
501 |
502 | /* RTL support */
503 | .ui-datepicker-rtl { direction: rtl; }
504 | .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
505 | .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
506 | .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
507 | .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
508 | .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
509 | .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
510 | .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
511 | .ui-datepicker-rtl .ui-datepicker-group { float:right; }
512 | .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
513 | .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
514 |
515 | /* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
516 | .ui-datepicker-cover {
517 | display: none; /*sorry for IE5*/
518 | display/**/: block; /*sorry for IE5*/
519 | position: absolute; /*must have*/
520 | z-index: -1; /*must have*/
521 | filter: mask(); /*must have*/
522 | top: -4px; /*must have*/
523 | left: -4px; /*must have*/
524 | width: 200px; /*must have*/
525 | height: 200px; /*must have*/
526 | }/*
527 | * jQuery UI Progressbar 1.8.17
528 | *
529 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
530 | * Dual licensed under the MIT or GPL Version 2 licenses.
531 | * http://jquery.org/license
532 | *
533 | * http://docs.jquery.com/UI/Progressbar#theming
534 | */
535 | .ui-progressbar { height:2em; text-align: left; overflow: hidden; }
536 | .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
--------------------------------------------------------------------------------