diff --git a/.gitignore b/.gitignore index 8ef40b8f3c..7227f5f440 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,6 @@ bindings/flow/bin/ bindings/java/foundationdb-client*.jar bindings/java/foundationdb-tests*.jar bindings/java/fdb-java-*-sources.jar -bindings/nodejs/build/ -bindings/nodejs/modules/ packaging/msi/FDBInstaller.msi # Generated source, build, and packaging files @@ -24,7 +22,6 @@ bindings/java/src*/main/com/apple/foundationdb/StreamingMode.java bindings/java/src*/main/com/apple/foundationdb/MutationType.java bindings/java/src*/main/com/apple/foundationdb/ConflictRangeType.java bindings/java/src*/main/com/apple/foundationdb/FDBException.java -bindings/nodejs/package.json bindings/python/fdb/fdb*options.py bindings/python/dist/ bindings/python/setup.py @@ -52,12 +49,8 @@ bindings/go/godoc bindings/java/.classstamp* bindings/java/classes*/ bindings/java/javadoc*/ -bindings/nodejs/fdb_node.stamp -bindings/nodejs/node_modules/ # Testing and logging -bindings/nodejs/fdb_node*.log -bindings/nodejs/npm-debug.log packaging/msi/*.log packaging/msi/obj simfdb diff --git a/Makefile b/Makefile index a2311cc52d..55bc077bf9 100644 --- a/Makefile +++ b/Makefile @@ -93,7 +93,7 @@ VPATH += $(addprefix :,$(filter-out lib,$(patsubst -L%,%,$(filter -L%,$(LDFLAGS) CS_PROJECTS := flow/actorcompiler flow/coveragetool fdbclient/vexillographer CPP_PROJECTS := flow fdbrpc fdbclient fdbbackup fdbserver fdbcli bindings/c bindings/java fdbmonitor bindings/flow/tester bindings/flow -OTHER_PROJECTS := bindings/python bindings/ruby bindings/nodejs bindings/go +OTHER_PROJECTS := bindings/python bindings/ruby bindings/go CS_MK_GENERATED := $(CS_PROJECTS:=/generated.mk) CPP_MK_GENERATED := $(CPP_PROJECTS:=/generated.mk) @@ -127,7 +127,7 @@ else endif @echo "#define FDB_VT_PACKAGE_NAME \"$(PACKAGE_NAME)\"" >> $@ -bindings: fdb_c fdb_python fdb_ruby fdb_java fdb_node fdb_flow fdb_flow_tester fdb_go fdb_go_tester +bindings: fdb_c fdb_python fdb_ruby fdb_java fdb_flow fdb_flow_tester fdb_go fdb_go_tester Makefiles: $(MK_GENERATED) diff --git a/README.md b/README.md index 68edc85987..6c1009ec42 100755 --- a/README.md +++ b/README.md @@ -1,3 +1,21 @@ # FoundationDB FoundationDB is a distributed database designed to handle large volumes of structured data across clusters of commodity servers. It organizes data as an ordered key-value store and employs ACID transactions for all operations. It is especially well-suited for read/write workloads but also has excellent performance for write-intensive workloads. Users interact with the database using API language binding. + +# Building Locally + +## macOS + +1. Check out this repo on your Mac. +1. Install the Xcode command-line tools. +1. Download version 1.52 of [Boost](https://sourceforge.net/projects/boost/files/boost/1.52.0/). +1. Set the BOOSTDIR environment variable to the location containing this boost installation. +1. Install [Mono](http://www.mono-project.com/download/stable/). +1. Install a [JDK](http://www.oracle.com/technetwork/java/javase/downloads/index.html). FoundationDB currently builds with Java 8. +1. Navigate to the directory where you checked out the foundationdb repo. +1. Run `make`. + +This will build the fdbserver binary and the python bindings. If you +want to build our other bindings, you will need to install a runtime for the +language whose binding you want to build. Each binding has an `.mk` file +which provides specific targets for that binding. \ No newline at end of file diff --git a/bindings/bindingtester/known_testers.py b/bindings/bindingtester/known_testers.py index 683d79eba9..b7aca6808a 100644 --- a/bindings/bindingtester/known_testers.py +++ b/bindings/bindingtester/known_testers.py @@ -58,8 +58,6 @@ _java_cmd = 'java -ea -cp %s:%s com.apple.foundationdb.test.' % ( testers = { 'python': Tester('python', 'python ' + _absolute_path('python/tests/tester.py'), 2040, 23, MAX_API_VERSION, types=ALL_TYPES), 'python3': Tester('python3', 'python3 ' + _absolute_path('python/tests/tester.py'), 2040, 23, MAX_API_VERSION, types=ALL_TYPES), - 'node': Tester('node', _absolute_path('nodejs/tests/tester.js'), 53, 500, MAX_API_VERSION), - 'streamline': Tester('streamline', _absolute_path('nodejs/tests/streamline_tester._js'), 53, 500, MAX_API_VERSION), 'ruby': Tester('ruby', _absolute_path('ruby/tests/tester.rb'), 64, 23, MAX_API_VERSION), 'java': Tester('java', _java_cmd + 'StackTester', 2040, 510, MAX_API_VERSION, types=ALL_TYPES), 'java_async': Tester('java', _java_cmd + 'AsyncStackTester', 2040, 510, MAX_API_VERSION, types=ALL_TYPES), diff --git a/bindings/bindingtester/run_binding_tester.sh b/bindings/bindingtester/run_binding_tester.sh index 42af9d593f..b8d94e12e3 100644 --- a/bindings/bindingtester/run_binding_tester.sh +++ b/bindings/bindingtester/run_binding_tester.sh @@ -25,7 +25,7 @@ BREAKONERROR="${BREAKONERROR:-0}" RUNSCRIPTS="${RUNSCRIPTS:-1}" RUNTESTS="${RUNTESTS:-1}" RANDOMTEST="${RANDOMTEST:-0}" -BINDINGTESTS="${BINDINGTESTS:-python python3 java java_async ruby node go flow}" +BINDINGTESTS="${BINDINGTESTS:-python python3 java java_async ruby go flow}" LOGLEVEL="${LOGLEVEL:-INFO}" _BINDINGTESTS=(${BINDINGTESTS}) DISABLEDTESTS=() diff --git a/bindings/bindingtester/run_tester_loop.sh b/bindings/bindingtester/run_tester_loop.sh index d1eff08b43..d78915a489 100755 --- a/bindings/bindingtester/run_tester_loop.sh +++ b/bindings/bindingtester/run_tester_loop.sh @@ -24,7 +24,6 @@ function run_scripted() { scripted ruby scripted java scripted java_async - scripted node scripted go scripted flow } @@ -40,8 +39,6 @@ while `true`; do run ruby run java run java_async - run node - #run streamline run go run flow done diff --git a/bindings/c/local.mk b/bindings/c/local.mk index 7bab3d9919..44f0c31b42 100644 --- a/bindings/c/local.mk +++ b/bindings/c/local.mk @@ -102,5 +102,3 @@ fdb_c_tests: packages/fdb-c-tests-$(VERSION)-$(PLATFORM).tar.gz fdb_c_tests_clean: @rm -f packages/fdb-c-tests-$(VERSION)-$(PLATFORM).tar.gz - -packages: fdb_c_tests diff --git a/bindings/java/fdb-java-style.xml b/bindings/java/fdb-java-style.xml index 62d6232eed..b47b094118 100644 --- a/bindings/java/fdb-java-style.xml +++ b/bindings/java/fdb-java-style.xml @@ -30,11 +30,6 @@ - - - - -PRERELEASE - - - - - - - - - Debug - x64 - - - Release - x64 - - - - {9463CB25-DCA0-9D45-C46E-0A8E68EE7FAE} - Win32Proj - - - - v140_xp - - - - $(SystemDrive)\temp\msvcfdb\$(Platform)$(Configuration)\$(MSBuildProjectName)\ - - - - - - del "$(SolutionDir)bin\$(Configuration)\fdb-node*.tar.gz" - - - - -c:\python27\python -c "print open(\"package.json.in\").read().replace(\"VERSION\",\"$(Version)$(PreReleaseDecoration)\")" > package.json -copy ..\..\LICENSE -c:\python27\python "$(SolutionDir)build/tarball.py" -r nodejs "$(SolutionDir)bin\$(Configuration)\fdb-node-$(Version)$(PreReleaseDecoration)-windows-$(Platform).tar.gz" lib modules package.json README.md LICENSE -del LICENSE - - - - - - - - false - - - false - - - - - - \ No newline at end of file diff --git a/bindings/nodejs/fdb_node_0_10.vcxproj b/bindings/nodejs/fdb_node_0_10.vcxproj deleted file mode 100644 index f47ce8ef11..0000000000 --- a/bindings/nodejs/fdb_node_0_10.vcxproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - {E22D4EF8-E75D-4281-93F9-A9F73936DE54} - - - v140_xp - - - 0.10.0 - 0.10 - - - \ No newline at end of file diff --git a/bindings/nodejs/fdb_node_0_8.vcxproj b/bindings/nodejs/fdb_node_0_8.vcxproj deleted file mode 100644 index e783b03ed1..0000000000 --- a/bindings/nodejs/fdb_node_0_8.vcxproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - {E936E200-689E-49FD-8463-32FE763F1860} - - - v140_xp - - - 0.8.22 - 0.8 - - - \ No newline at end of file diff --git a/bindings/nodejs/include.mk b/bindings/nodejs/include.mk deleted file mode 100644 index da829d990a..0000000000 --- a/bindings/nodejs/include.mk +++ /dev/null @@ -1,99 +0,0 @@ -# -# include.mk -# -# This source file is part of the FoundationDB open source project -# -# Copyright 2013-2018 Apple Inc. and the FoundationDB project authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# -*- mode: makefile-gmake; -*- - -TARGETS += fdb_node fdb_node_npm -CLEAN_TARGETS += fdb_node_clean fdb_node_npm_clean - -NODE_VERSIONS := 0.8.22 0.10.0 - -NODE_DIST_URL ?= https://nodejs.org/dist -NODE_REGISTRY_URL ?= https://registry.npmjs.org/ - -ifeq ($(RELEASE),true) - NPMVER = $(VERSION) -else - NPMVER = $(VERSION)-PRERELEASE -endif - -packages: fdb_node_npm - -packages_clean: fdb_node_npm_clean - -fdb_node: fdb_c bindings/nodejs/fdb_node.stamp - -bindings/nodejs/fdb_node.stamp: bindings/nodejs/src/FdbOptions.g.cpp bindings/nodejs/src/*.cpp bindings/nodejs/src/*.h bindings/nodejs/binding.gyp lib/libfdb_c.$(DLEXT) bindings/nodejs/package.json - @echo "Building $@" - @rm -f $@ - @cd bindings/nodejs && \ - mkdir -p modules && \ - rm -rf modules/* && \ - for ver in $(NODE_VERSIONS); do \ - MMVER=`echo $$ver | sed -e 's,\., ,g' | awk '{print $$1 "." $$2}'` && \ - mkdir modules/$$MMVER && \ - node-gyp configure --dist-url=$(NODE_DIST_URL) --target=$$ver && \ - node-gyp -v build && \ - cp build/Release/fdblib.node modules/$${MMVER} ; \ - done - @touch $@ - -bindings/nodejs/src/FdbOptions.g.cpp: bin/vexillographer.exe fdbclient/vexillographer/fdb.options - @echo "Building $@" - @$(MONO) bin/vexillographer.exe fdbclient/vexillographer/fdb.options nodejs $@ - -fdb_node_clean: - @echo "Cleaning fdb_node" - @rm -f bindings/nodejs/src/FdbOptions.g.cpp - @rm -rf bindings/nodejs/modules - @(cd bindings/nodejs && node-gyp clean) - @rm -f bindings/nodejs/fdb_node.stamp - -bindings/nodejs/package.json: bindings/nodejs/package.json.in $(ALL_MAKEFILES) versions.target - @m4 -DVERSION=$(NPMVER) $< > $@ - @echo "Updating Node dependencies" - @cd bindings/nodejs && \ - npm config set registry "$(NODE_REGISTRY_URL)" && \ - npm update - -fdb_node_npm: fdb_node versions.target bindings/nodejs/README.md bindings/nodejs/lib/*.js bindings/nodejs/src/* bindings/nodejs/binding.gyp LICENSE - @echo "Packaging NPM" - @mkdir -p packages - @rm -f packages/fdb-node-* - @rm -rf packages/nodejs.tmp - @mkdir -p packages/nodejs.tmp/nodejs - @cp LICENSE packages/nodejs.tmp/nodejs/LICENSE - @tar -C bindings -czf packages/fdb-node-$(NPMVER)-$(PLATFORM)-$(ARCH).tar.gz nodejs/lib nodejs/modules nodejs/package.json nodejs/README.md -C ../packages/nodejs.tmp nodejs/LICENSE - @rm -rf packages/nodejs.tmp -ifeq ($(PLATFORM),linux) - @echo "Packaging NPM (unbuilt)" - @rm -rf packages/nodejs.tmp - @mkdir -p packages/nodejs.tmp/npmsrc/nodejs - @cat bindings/nodejs/package.json | grep -v private | grep -v engineStrict | awk '/"semver"/ {print " \"bindings\": \"*\""; next} {print}' > packages/nodejs.tmp/npmsrc/nodejs/package.json - @cp -r bindings/nodejs/lib bindings/nodejs/src bindings/nodejs/README.md LICENSE packages/nodejs.tmp/npmsrc/nodejs - @cp bindings/nodejs/binding.gyp.npmsrc packages/nodejs.tmp/npmsrc/nodejs/binding.gyp - @cp bindings/nodejs/fdbModule.js.npmsrc packages/nodejs.tmp/npmsrc/nodejs/lib/fdbModule.js - @tar -C packages/nodejs.tmp/npmsrc -czf packages/fdb-node-$(NPMVER).tar.gz nodejs - @rm -rf packages/nodejs.tmp -endif - -fdb_node_npm_clean: - @echo "Cleaning NPM" - @rm -f packages/fdb-node-* bindings/nodejs/package.json diff --git a/bindings/nodejs/lib/apiVersion.js b/bindings/nodejs/lib/apiVersion.js deleted file mode 100644 index 9bcde04422..0000000000 --- a/bindings/nodejs/lib/apiVersion.js +++ /dev/null @@ -1,26 +0,0 @@ -/* - * apiVersion.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var apiVersion; -module.exports = { value: apiVersion }; - diff --git a/bindings/nodejs/lib/bufferConversion.js b/bindings/nodejs/lib/bufferConversion.js deleted file mode 100644 index 97923ca82d..0000000000 --- a/bindings/nodejs/lib/bufferConversion.js +++ /dev/null @@ -1,86 +0,0 @@ -/* - * bufferConversion.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var toBuffer = function(obj) { - if(Buffer.isBuffer(obj)) - return obj; - - if(obj instanceof ArrayBuffer) - obj = new Uint8Array(obj); - - if(obj instanceof Uint8Array) { - var buf = new Buffer(obj.length); - for(var i = 0; i < obj.length; ++i) - buf[i] = obj[i]; - - return buf; - } - - if(typeof obj === 'string') - return new Buffer(obj, 'utf8'); - - throw new TypeError('toBuffer function expects a string, buffer, ArrayBuffer, or Uint8Array'); -}; - -toBuffer.fromByteLiteral = function(str) { - if(typeof str === 'string') { - var buf = new Buffer(str.length); - for(var i = 0; i < str.length; ++i) { - if(str[i] > 255) - throw new RangeError('fromByteLiteral string argument cannot have codepoints larger than 1 byte'); - buf[i] = str.charCodeAt(i); - } - return buf; - } - else - throw new TypeError('fromByteLiteral function expects a string'); -}; - -toBuffer.toByteLiteral = function(buf) { - if(Buffer.isBuffer(buf)) - return String.fromCharCode.apply(null, buf); - else - throw new TypeError('toByteLiteral function expects a buffer'); -}; - -toBuffer.printable = function(buf) { - buf = toBuffer(buf); - var out = ''; - for(var i = 0; i < buf.length; ++i) { - if(buf[i] >= 32 && buf[i] < 127 && buf[i] !== 92) - out += String.fromCharCode(buf[i]); - else if(buf[i] === 92) - out += '\\\\'; - else { - var str = buf[i].toString(16); - out += '\\x'; - if(str.length == 1) - out += '0'; - out += str; - } - } - - return out; -}; - -module.exports = toBuffer; diff --git a/bindings/nodejs/lib/cluster.js b/bindings/nodejs/lib/cluster.js deleted file mode 100644 index f00f51fa80..0000000000 --- a/bindings/nodejs/lib/cluster.js +++ /dev/null @@ -1,38 +0,0 @@ -/* - * cluster.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var future = require('./future'); -var Database = require('./database'); - -var Cluster = function(_cluster) { - this._cluster = _cluster; - this.options = _cluster.options; - -}; - -Cluster.prototype.openDatabase = function() { - return new Database(this._cluster.openDatabase()); -}; - -module.exports = Cluster; - diff --git a/bindings/nodejs/lib/database.js b/bindings/nodejs/lib/database.js deleted file mode 100644 index 0ddd21f907..0000000000 --- a/bindings/nodejs/lib/database.js +++ /dev/null @@ -1,172 +0,0 @@ -/* - * database.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var Transaction = require('./transaction'); -var future = require('./future'); -var fdb = require('./fdbModule'); -var fdbUtil = require('./fdbUtil'); - -var onError = function(tr, err, func, cb) { - tr.onError(err, function(retryErr, retryRes) { - if(retryErr) - cb(retryErr, retryRes); - else - retryLoop(tr, func, cb); - }); -}; - -var retryLoop = function(tr, func, cb) { - func(tr, function(err, res) { - if(err) { - onError(tr, err, func, cb); - } - else { - tr.commit(function(commitErr, commitRes) { - if(commitErr) - onError(tr, commitErr, func, cb); - else - cb(commitErr, res); - }); - } - }); -}; - -var atomic = function(db, op) { - return function(key, value, cb) { - return db.doTransaction(function(tr, innerCb) { - fdb.atomic[op].call(tr.tr, fdbUtil.keyToBuffer(key), fdbUtil.valueToBuffer(value)); - innerCb(); - }, cb); - }; -}; - -var Database = function(_db) { - this._db = _db; - this.options = _db.options; - - for(var op in fdb.atomic) - this[op] = atomic(this, op); -}; - -Database.prototype.createTransaction = function() { - return new Transaction(this, this._db.createTransaction()); -}; - -Database.prototype.doTransaction = function(func, cb) { - var tr = this.createTransaction(); - - return future.create(function(futureCb) { - retryLoop(tr, func, futureCb); - }, cb); -}; - -Database.prototype.get = function(key, cb) { - return this.doTransaction(function(tr, innerCb) { - tr.get(key, innerCb); - }, cb); -}; - -Database.prototype.getKey = function(keySelector, cb) { - return this.doTransaction(function(tr, innerCb) { - tr.getKey(keySelector, innerCb); - }, cb); -}; - -Database.prototype.getRange = function(start, end, options, cb) { - return this.doTransaction(function(tr, innerCb) { - tr.getRange(start, end, options).toArray(innerCb); - }, cb); -}; - -Database.prototype.getRangeStartsWith = function(prefix, options, cb) { - return this.doTransaction(function(tr, innerCb) { - try { - tr.getRangeStartsWith(prefix, options).toArray(innerCb); - } - catch(e) { - innerCb(e); - } - }, cb); -}; - -Database.prototype.getAndWatch = function(key, cb) { - return this.doTransaction(function(tr, innerCb) { - tr.get(key, function(err, val) { - if(err) - innerCb(err); - else - innerCb(undefined, { value: val, watch: tr.watch(key) }); - }); - }, cb); -}; - -Database.prototype.setAndWatch = function(key, value, cb) { - return this.doTransaction(function(tr, innerCb) { - tr.set(key, value); - var watchObj = tr.watch(key); - innerCb(undefined, { watch: watchObj }); - }, cb); -}; - -Database.prototype.clearAndWatch = function(key, cb) { - return this.doTransaction(function(tr, innerCb) { - tr.clear(key); - var watchObj = tr.watch(key); - innerCb(undefined, { watch: watchObj }); - }, cb); -}; - -Database.prototype.set = function(key, value, cb) { - return this.doTransaction(function(tr, innerCb) { - tr.set(key, value); - innerCb(); - }, cb); -}; - -Database.prototype.clear = function(key, cb) { - return this.doTransaction(function(tr, innerCb) { - tr.clear(key); - innerCb(); - }, cb); -}; - -Database.prototype.clearRange = function(start, end, cb) { - return this.doTransaction(function(tr, innerCb) { - tr.clearRange(start, end); - innerCb(); - }, cb); -}; - -Database.prototype.clearRangeStartsWith = function(prefix, cb) { - return this.doTransaction(function(tr, innerCb) { - try { - tr.clearRangeStartsWith(prefix); - innerCb(); - } - catch(e) { - innerCb(e); - } - }, cb); -}; - -module.exports = Database; diff --git a/bindings/nodejs/lib/directory.js b/bindings/nodejs/lib/directory.js deleted file mode 100644 index 81b4e76559..0000000000 --- a/bindings/nodejs/lib/directory.js +++ /dev/null @@ -1,850 +0,0 @@ -/* - * directory.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var util = require('util'); - -var buffer = require('./bufferConversion'); -var future = require('./future'); -var transactional = require('./retryDecorator'); -var tuple = require('./tuple'); -var Subspace = require('./subspace'); -var fdbUtil = require('./fdbUtil'); - -/************* - * Utilities * - *************/ - -function whileLoop(func, cb) { - return future.create(function(futureCb) { - fdbUtil.whileLoop(function(f) { - func()(f); - }, futureCb); - }, cb); -} - -function startsWith(str, prefix) { - return str.length >= prefix.length && fdbUtil.buffersEqual(str.slice(0, prefix.length), prefix); -} - -function valueOrDefault(value, defaultValue) { - if(typeof value === 'undefined') - return defaultValue; - - return value; -} - -function pathsEqual(path1, path2) { - if(path1.length !== path2.length) - return false; - - for(var i = 0; i < path1.length; ++i) - if(path1[i] !== path2[i]) - return false; - - return true; -} - -function tuplifyPath(path) { - if(!(path instanceof Array)) - path = [path]; - - return path; -} - -function checkLayer(layer, required) { - if(layer && layer.length > 0 && !fdbUtil.buffersEqual(layer, required)) - throw new Error('The directory was created with an incompatible layer.'); -} - -/*************************** - * HighContentionAllocator * - ***************************/ - -var HighContentionAllocator = function(subspace) { - this.counters = subspace.subspace([0]); - this.recent = subspace.subspace([1]); -}; - -HighContentionAllocator.prototype.allocate = transactional(function(tr) { - var self = this; - var windowStart = 0; - return whileLoop(function() { - return tr.snapshot.getRange(self.counters.range().begin, self.counters.range().end, { limit: 1, reverse: true }) - .toArray() - .then(function(arr) { - if(arr.length > 0) { - windowStart = self.counters.unpack(arr[0].key)[0]; - } - }) - .then(function() { - return self.chooseWindow(tr, windowStart); - }) - .then(function(window) { - return self.choosePrefix(tr, window); - }) - .then(function(prefix) { - if(prefix !== null) { - prefix = tuple.pack([prefix]); // exit the loop - return prefix; - } - }); - }) -}); - -HighContentionAllocator.prototype.chooseWindow = function(tr, windowStart) { - var self = this; - - var increment = new Buffer(8); - increment.fill(0); - increment.writeUInt32LE(1, 0); - - var window = { start: windowStart, size: 0 }; - - return whileLoop(function() { - // Cannot yield to event loop in this block { - if(window.start > windowStart) { - tr.clearRange(self.counters, self.counters.get(window.start)); - tr.options.setNextWriteNoWriteConflictRange(); - tr.clearRange(self.recent, self.recent.get(window.start)); - } - - tr.add(self.counters.pack([window.start]), increment); - return tr.snapshot.get(self.counters.get(window.start)) - // } - .then(function(newCountBuffer) { - var newCount = (newCountBuffer === null) ? 0 : newCountBuffer.readUInt32LE(0); - window.size = windowSize(window.start); - if(newCount * 2 < window.size) { - return window; // exit the loop - } - - window.start += window.size; - }); - }); -}; - -HighContentionAllocator.prototype.choosePrefix = function(tr, window) { - var self = this; - - return whileLoop(function() { - var candidate = Math.floor(Math.random() * window.size) + window.start; - var allocationKey = self.recent.pack([candidate]); - - // Cannot yield to event loop in this block { - var counterRange = tr.snapshot.getRange(self.counters.range().begin, self.counters.range().end, { limit: 1, reverse: true }).toArray(); - var allocation = tr.get(allocationKey); - tr.options.setNextWriteNoWriteConflictRange(); - tr.set(allocationKey, buffer('')); - // } - - return future.all([counterRange, allocation]) - .then(function(vals) { - var currentWindowStart = vals[0].length > 0 ? self.counters.unpack(vals[0][0].key)[0] : 0; - if(currentWindowStart > window.start) { - return null; // exit the loop and force find() to retry - } - if(vals[1] === null) { - tr.addWriteConflictKey(allocationKey); - return candidate; // exit the loop - } - }); - }); -}; - -function windowSize(start) { - if(start < 255) - return 64; - if(start < 65535) - return 1024; - - return 8192; -} - -/****************** - * DirectoryLayer * -******************/ - -var VERSION = [1, 0, 0]; -var SUBDIRS = 0; - -var DirectoryLayer = function(options) { - options = valueOrDefault(options, {}); - - this._nodeSubspace = valueOrDefault(options.nodeSubspace, new Subspace([], buffer.fromByteLiteral('\xfe'))); - - // If specified, new automatically allocated prefixes will all fall within the contentSubspace - this._contentSubspace = valueOrDefault(options.contentSubspace, new Subspace()); - this._allowManualPrefixes = valueOrDefault(options.allowManualPrefixes, false); - - this._rootNode = this._nodeSubspace.subspace([this._nodeSubspace.key()]); - this._allocator = new HighContentionAllocator(this._rootNode.subspace([buffer('hca')])); - - this._path = []; -}; - -var createOrOpen = transactional(function(tr, self, path, options, allowCreate, allowOpen, cb) { - options = valueOrDefault(options, {}); - var layer = valueOrDefault(options.layer, buffer('')); - var prefix = options.prefix; - - allowCreate = valueOrDefault(allowCreate, true); - allowOpen = valueOrDefault(allowOpen, true); - - return checkVersion(self, tr, false) - .then(function() { - if(typeof prefix !== 'undefined') { - if(allowCreate && allowOpen) - throw new Error('Cannot specify a prefix when calling create_or_open.'); - else if(!self._allowManualPrefixes) { - if(self._path.length === 0) - throw new Error('Cannot specify a prefix unless manual prefixes are enabled.'); - else - throw new Error('Cannot specify a prefix in a partition.'); - } - } - - path = toUnicodePath(path); - if(path.length === 0) - throw new Error('The root directory cannot be opened.'); - - return find(self, tr, path).then(loadMetadata(tr)); - }) - .then(function(existingNode) { - if(existingNode.exists()) { - if(existingNode.isInPartition(false)) { - var subpath = existingNode.getPartitionSubpath(); - var directoryLayer = existingNode.getContents(self)._directoryLayer; - return createOrOpen(tr, - existingNode.getContents(self)._directoryLayer, - subpath, - options, - allowCreate, - allowOpen); - } - - return openDirectory(tr, self, path, layer, existingNode, allowOpen); - } - else - return createDirectory(tr, self, path, layer, prefix, allowCreate); - })(cb); -}); - -var openDirectory = function(tr, self, path, layer, existingNode, allowOpen) { - if(!allowOpen) - throw new Error('The directory already exists.'); - - checkLayer(layer, existingNode.layer); - - return existingNode.getContents(self); -}; - -var createDirectory = function(tr, self, path, layer, prefix, allowCreate) { - if(!allowCreate) - throw new Error('The directory does not exist.'); - - var prefixIsAllocated = typeof(prefix) === 'undefined'; - return checkVersion(self, tr, true) - .then(function() { - return getPrefix(self, tr, prefix); - }) - .then(function(prefix) { - return isPrefixFree(self, prefixIsAllocated ? tr.snapshot : tr, prefix) - .then(function(isFree) { - if(!isFree) { - if(prefixIsAllocated) - throw new Error('The directory layer has manually allocated prefixes that conflict with the automatic prefix allocator.'); - else - throw new Error('The given prefix is already in use.'); - } - - return getParentNode(self, tr, path); - }) - .then(function(parentNode) { - if(!parentNode) - throw new Error('The parent directory doesn\'t exist.'); - - var node = nodeWithPrefix(self, prefix); - tr.set(parentNode.subspace([SUBDIRS]).pack([path[path.length-1]]), prefix); - tr.set(node.pack([buffer('layer')]), layer); - - return contentsOfNode(self, node, path, layer); - }); - }); -}; - -DirectoryLayer.prototype.getLayer = function() { - return new Buffer(0); -}; - -DirectoryLayer.prototype.getPath = function() { - return this._path.slice(0); -}; - -DirectoryLayer.prototype.createOrOpen = function(databaseOrTransaction, path, options, cb) { - return createOrOpen(databaseOrTransaction, this, path, options, true, true, cb); -}; - -DirectoryLayer.prototype.open = function(databaseOrTransaction, path, options, cb) { - return createOrOpen(databaseOrTransaction, this, path, options, false, true, cb); -}; - -DirectoryLayer.prototype.create = function(databaseOrTransaction, path, options, cb) { - return createOrOpen(databaseOrTransaction, this, path, options, true, false, cb); -}; - -DirectoryLayer.prototype.moveTo = function(databaseOrTransaction, newAbsolutePath, cb) { - return future.reject(new Error('The root directory cannot be moved.'))(cb); -}; - -DirectoryLayer.prototype.move = transactional(function(tr, oldPath, newPath, cb) { - var self = this; - var oldNode, newNode; - - return checkVersion(self, tr, true) - .then(function() { - oldPath = toUnicodePath(oldPath); - newPath = toUnicodePath(newPath); - - if(pathsEqual(oldPath, newPath.slice(0, oldPath.length))) - throw new Error('The destination directory cannot be a subdirectory of the source directory.'); - - var oldNodeFuture = find(self, tr, oldPath).then(loadMetadata(tr)); - var newNodeFuture = find(self, tr, newPath).then(loadMetadata(tr)); - return future.all([oldNodeFuture, newNodeFuture]); - }) - .then(function(nodes) { - oldNode = nodes[0]; - newNode = nodes[1]; - - if(!oldNode.exists()) - throw new Error('The source directory does not exist.'); - - if(oldNode.isInPartition(false) || newNode.isInPartition(false)) { - if(!oldNode.isInPartition(false) || !newNode.isInPartition(false) || !pathsEqual(oldNode.path, newNode.path)) - throw new Error('Cannot move between partitions.'); - - return newNode.getContents(self).move(tr, oldNode.getPartitionSubpath(), newNode.getPartitionSubpath()); - } - - if(newNode.exists()) - throw new Error('The destination directory already exists. Remove it first.'); - - return find(self, tr, newPath.slice(0, newPath.length-1)) - .then(function(parentNode) { - if(!parentNode.exists()) - throw new Error('The parent of the destination directory does not exist. Create it first.'); - - tr.set(parentNode.subspace.subspace([SUBDIRS]).pack([newPath[newPath.length-1]]), - self._nodeSubspace.unpack(oldNode.subspace.key())[0]); - - return removeFromParent(self, tr, oldPath); - }) - .then(function() { - return contentsOfNode(self, oldNode.subspace, newPath, oldNode.layer); - }); - })(cb); -}); - -DirectoryLayer.prototype.remove = transactional(function(tr, path, cb) { - return removeInternal(this, tr, path, true)(cb); -}); - -DirectoryLayer.prototype.removeIfExists = transactional(function(tr, path, cb) { - return removeInternal(this, tr, path, false)(cb); -}); - -function removeInternal(self, tr, path, failOnNonexistent) { - return checkVersion(self, tr, true) - .then(function() { - path = valueOrDefault(path, []); - if(path.length === 0) - return future.reject(new Error('The root directory cannot be removed.')); - - path = toUnicodePath(path); - return find(self, tr, path).then(loadMetadata(tr)); - }) - .then(function(node) { - if(!node.exists()) { - if(failOnNonexistent) - throw new Error('The directory doesn\'t exist'); - else - return false; - } - - if(node.isInPartition(false)) { - return removeInternal(node.getContents(self)._directoryLayer, - tr, - node.getPartitionSubpath(), - failOnNonexistent); - } - - return removeRecursive(self, tr, node.subspace) - .then(function() { - return removeFromParent(self, tr, path); - }). - then(function() { - return true; - }); - }); -} - -DirectoryLayer.prototype.list = transactional(function(tr, path, cb) { - var self = this; - return checkVersion(self, tr, false) - .then(function() { - path = valueOrDefault(path, []); - path = toUnicodePath(path); - - return find(self, tr, path).then(loadMetadata(tr)); - }) - .then(function(node) { - if(!node.exists()) - throw new Error('The given directory does not exist'); - - if(node.isInPartition(true)) - return node.getContents(self).list(tr, node.getPartitionSubpath()); - - var subdir = node.subspace.subspace([SUBDIRS]); - - return tr.getRange(subdir.range().begin, subdir.range().end).toArray() - .then(function(arr) { - return arr.map(function(kv) { return subdir.unpack(kv.key)[0].toString('utf8'); }); - }); - })(cb); -}); - -DirectoryLayer.prototype.exists = transactional(function(tr, path, cb) { - var self = this; - return checkVersion(self, tr, false) - .then(function() { - path = valueOrDefault(path, []); - path = toUnicodePath(path); - return find(self, tr, path).then(loadMetadata(tr)); - }) - .then(function(node) { - if(!node.exists()) - return false; - - if(node.isInPartition(false)) - return node.getContents(self).exists(tr, node.getPartitionSubpath()); - - return true; - })(cb); -}); - -// Private functions: - -function checkVersion(self, tr, writeAccess) { - return tr.get(self._rootNode.pack([buffer('version')])) - .then(function(versionBuf) { - if(!versionBuf) { - if(writeAccess) - initializeDirectory(self, tr); - - return; - } - - var version = []; - for(var i = 0; i < 3; ++i) - version.push(versionBuf.readInt32LE(4*i)); - - var dirVersion = util.format('%d.%d.%d', version[0], version[1], version[2]); - var layerVersion = util.format('%d.%d.%d', VERSION[0], VERSION[1], VERSION[2]); - - if(version[0] > VERSION[0]) { - throw new Error(util.format('Cannot load directory with version %s using directory layer %s', - dirVersion, - layerVersion)); - } - - if(version[1] > VERSION[1]) { - throw new Error(util.format('Directory with version %s is read-only when opened using directory layer %s', - dirVersion, - layerVersion)); - } - }); -} - -function initializeDirectory(self, tr) { - var versionBuf = new Buffer(12); - for(var i = 0; i < 3; ++i) - versionBuf.writeUInt32LE(VERSION[i], i*4); - - tr.set(self._rootNode.pack([buffer('version')]), versionBuf); -} - -function nodeWithPrefix(self, prefix) { - if(prefix === null) - return null; - - return self._nodeSubspace.subspace([prefix]); -} - -function find(self, tr, path) { - var pathIndex = 0; - var node = new Node(self._rootNode, [], path); - - return whileLoop(function() { - if(pathIndex === path.length) - return future.resolve(node); - - return tr.get(node.subspace.subspace([SUBDIRS]).pack([path[pathIndex++]])) - .then(function(val) { - node = new Node(nodeWithPrefix(self, val), path.slice(0, pathIndex), path); - if(!node.exists()) - return node; - return node.loadMetadata(tr) - .then(function() { - if(fdbUtil.buffersEqual(node.layer, buffer('partition'))) - return node; - }); - }); - }); -} - -function contentsOfNode(self, node, path, layer) { - var prefix = self._nodeSubspace.unpack(node.key())[0]; - - if(fdbUtil.buffersEqual(layer, buffer('partition'))) - return new DirectoryPartition(self._path.concat(path), prefix, self); - else - return new DirectorySubspace(self._path.concat(path), prefix, self, layer); -} - -function getPrefix(self, tr, prefix) { - if(typeof prefix === 'undefined') { - return self._allocator.allocate(tr) - .then(function(prefix) { - var allocated = Buffer.concat([self._contentSubspace.key(), prefix], self._contentSubspace.key().length + prefix.length); - return tr.getRangeStartsWith(allocated, { limit: 1 }) - .toArray() - .then(function(arr) { - if(arr.length > 0) - throw new Error('The database has keys stored at the prefix chosen by the automatic prefix allocator: ' + prefix); - - return allocated; - }); - }); - } - else - return future.resolve(buffer(prefix)); -} - -function getNodeContainingKey(self, tr, key) { - if(self._nodeSubspace.contains(key)) - return future.resolve(self._rootNode); - - return tr.getRange(self._nodeSubspace.range([]).begin, - self._nodeSubspace.subspace([key]).range().begin, - { limit: 1, reverse: true }) - .toArray() - .then(function(arr) { - if(arr.length > 0) { - var prevPrefix = self._nodeSubspace.unpack(arr[0].key)[0]; - if(startsWith(key, prevPrefix)) - return nodeWithPrefix(self, prevPrefix); - } - - return null; - }); -} - -function isPrefixFree(self, tr, prefix) { - if(!prefix || prefix.length === 0) - return future.resolve(false); - - return getNodeContainingKey(self, tr, prefix) - .then(function(node) { - if(node) - return false; - - return tr.getRange(self._nodeSubspace.pack([prefix]), - self._nodeSubspace.pack([fdbUtil.strinc(prefix)]), - { limit: 1 }) - .toArray() - .then(function(arr) { - return arr.length === 0; - }); - }); -} - -function getParentNode(self, tr, path) { - if(path.length > 1) { - return self.createOrOpen(tr, path.slice(0, path.length-1)) - .then(function(dir) { - return nodeWithPrefix(self, dir.key()); - }); - } - else - return future.resolve(self._rootNode); -} - -function removeFromParent(self, tr, path) { - return find(self, tr, path.slice(0, path.length-1)) - .then(function(parentNode) { - tr.clear(parentNode.subspace.subspace([SUBDIRS]).pack([path[path.length-1]])); - }); -} - -function removeRecursive(self, tr, node) { - var subdir = node.subspace([SUBDIRS]); - return tr.getRange(subdir.range().begin, subdir.range().end) - .forEach(function(kv, loopCb) { - removeRecursive(self, tr, nodeWithPrefix(self, kv.value))(loopCb); - }) - .then(function() { - tr.clearRangeStartsWith(self._nodeSubspace.unpack(node.key())[0]); - tr.clearRange(node.range().begin, node.range().end); - }); -} - -function toUnicodePath(path) { - if(Buffer.isBuffer(path) || path instanceof ArrayBuffer || path instanceof Uint8Array) - path = buffer(path).toString('utf8'); - - if(typeof path === 'string') - return [path]; - - if(path instanceof Array) { - for(var i = 0; i < path.length; ++i) { - if(Buffer.isBuffer(path[i]) || path[i] instanceof ArrayBuffer || path[i] instanceof Uint8Array) - path[i] = buffer(path[i]).toString('utf8'); - if(typeof path[i] !== 'string') - throw new TypeError('Invalid path: must be a string, Buffer, ArrayBuffer, Uint8Array, or an array of such items'); - } - - return path; - } - - throw new TypeError('Invalid path: must be a string, Buffer, ArrayBuffer, Uint8Array, or an array of such items'); -} - -/********************* - * DirectorySubspace * - *********************/ - -var DirectorySubspace = function(path, prefix, directoryLayer, layer) { - Subspace.call(this, undefined, prefix); - this._path = path; - this._directoryLayer = directoryLayer; - this._layer = layer; -}; - -DirectorySubspace.prototype = new Subspace(); -DirectorySubspace.constructor = DirectorySubspace; - -DirectorySubspace.prototype.getLayer = function() { - return this._layer; -}; - -DirectorySubspace.prototype.getPath = function() { - return this._path.slice(0); -}; - -DirectorySubspace.prototype.createOrOpen = function(databaseOrTransaction, nameOrPath, options, cb) { - var path = tuplifyPath(nameOrPath); - return this._directoryLayer.createOrOpen(databaseOrTransaction, partitionSubpath(this, path), options, cb); -}; - -DirectorySubspace.prototype.open = function(databaseOrTransaction, nameOrPath, options, cb) { - var path = tuplifyPath(nameOrPath); - return this._directoryLayer.open(databaseOrTransaction, partitionSubpath(this, path), options, cb); -}; - -DirectorySubspace.prototype.create = function(databaseOrTransaction, nameOrPath, options, cb) { - var path = tuplifyPath(nameOrPath); - return this._directoryLayer.create(databaseOrTransaction, partitionSubpath(this, path), options, cb); -}; - -DirectorySubspace.prototype.list = function(databaseOrTransaction, nameOrPath, cb) { - var path = tuplifyPath(valueOrDefault(nameOrPath, [])); - return this._directoryLayer.list(databaseOrTransaction, partitionSubpath(this, path), cb); -}; - -DirectorySubspace.prototype.move = function(databaseOrTransaction, oldNameOrPath, newNameOrPath, cb) { - var oldPath = tuplifyPath(oldNameOrPath); - var newPath = tuplifyPath(newNameOrPath); - return this._directoryLayer.move(databaseOrTransaction, - partitionSubpath(this, oldPath), - partitionSubpath(this, newPath), - cb); -}; - -DirectorySubspace.prototype.moveTo = function(databaseOrTransaction, newAbsoluteNameOrPath, cb) { - var directoryLayer; - var newAbsolutePath; - try { - directoryLayer = getLayerForPath(this, []); - newAbsolutePath = toUnicodePath(newAbsoluteNameOrPath); - var partitionPath = newAbsolutePath.slice(0, directoryLayer._path.length); - if(!pathsEqual(partitionPath, directoryLayer._path)) - throw new Error('Cannot move between partitions.'); - } - catch(err) { - return future.reject(err)(cb); - } - - return directoryLayer.move(databaseOrTransaction, - this._path.slice(directoryLayer._path.length), - newAbsolutePath.slice(directoryLayer._path.length), - cb); -}; - -DirectorySubspace.prototype.remove = function(databaseOrTransaction, nameOrPath, cb) { - var path = tuplifyPath(valueOrDefault(nameOrPath, [])); - var directoryLayer = getLayerForPath(this, path); - return directoryLayer.remove(databaseOrTransaction, partitionSubpath(this, path, directoryLayer), cb); -}; - -DirectorySubspace.prototype.removeIfExists = function(databaseOrTransaction, nameOrPath, cb) { - var path = tuplifyPath(valueOrDefault(nameOrPath, [])); - var directoryLayer = getLayerForPath(this, path); - return directoryLayer.removeIfExists(databaseOrTransaction, partitionSubpath(this, path, directoryLayer), cb); -}; - -DirectorySubspace.prototype.exists = function(databaseOrTransaction, nameOrPath, cb) { - var path = tuplifyPath(valueOrDefault(nameOrPath, [])); - var directoryLayer = getLayerForPath(this, path); - return directoryLayer.exists(databaseOrTransaction, partitionSubpath(this, path, directoryLayer), cb); -}; - -var partitionSubpath = function(directorySubspace, path, directoryLayer) { - directoryLayer = valueOrDefault(directoryLayer, directorySubspace._directoryLayer); - return directorySubspace._path.slice(directoryLayer._path.length).concat(path); -}; - -/********************** - * DirectoryPartition * - **********************/ - -var DirectoryPartition = function(path, prefix, parentDirectoryLayer) { - var directoryLayer = new DirectoryLayer({ - nodeSubspace: new Subspace(undefined, Buffer.concat([prefix, buffer.fromByteLiteral('\xfe')], prefix.length+1)), - contentSubspace: new Subspace(undefined, prefix) - }); - - directoryLayer._path = path; - DirectorySubspace.call(this, path, prefix, directoryLayer, buffer('partition')); - this._parentDirectoryLayer = parentDirectoryLayer; -}; - -DirectoryPartition.prototype = new DirectorySubspace(); -DirectoryPartition.constructor = DirectoryPartition; - -DirectoryPartition.prototype.key = function() { - throw new Error('Cannot get key for the root of a directory partition.'); -}; - -DirectoryPartition.prototype.pack = function(arr) { - throw new Error('Cannot pack keys using the root of a directory partition.'); -}; - -DirectoryPartition.prototype.unpack = function(arr) { - throw new Error('Cannot unpack keys using the root of a directory partition.'); -}; - -DirectoryPartition.prototype.range = function(arr) { - throw new Error('Cannot get range for the root of a directory partition.'); -}; - -DirectoryPartition.prototype.contains = function(key) { - throw new Error('Cannot check whether a key belongs to the root of a directory partition.'); -}; - -DirectoryPartition.prototype.get = function(name) { - throw new Error('Cannot open subspace in the root of a directory partition.'); -}; - -DirectoryPartition.prototype.subspace = function(arr) { - throw new Error('Cannot open subspace in the root of a directory partition.'); -}; - -DirectoryPartition.prototype.asFoundationDBKey = function() { - throw new Error('Cannot use the root of a directory partition as a key.'); -}; - -var getLayerForPath = function(directorySubspace, path) { - if(directorySubspace instanceof DirectoryPartition && path.length === 0) - return directorySubspace._parentDirectoryLayer; - else - return directorySubspace._directoryLayer; -}; - -/******** - * Node * - ********/ - -var Node = function(subspace, path, targetPath) { - this.subspace = subspace; - this.path = path; - this.targetPath = targetPath; -}; - -Node.prototype.exists = function() { - return typeof(this.subspace) !== 'undefined' && this.subspace !== null; -}; - -Node.prototype.loadMetadata = function(tr) { - var self = this; - if(!self.exists()) { - self.loadedMetadata = true; - return future.resolve(self); - } - - return tr.get(self.subspace.pack([buffer('layer')])) - .then(function(layer) { - self.loadedMetadata = true; - self.layer = layer; - return self; - }); -}; - -Node.prototype.ensureMetadataLoaded = function() { - if(!this.loadedMetadata) - throw new Error('Metadata for node has not been loaded'); -}; - -Node.prototype.isInPartition = function(includeEmptySubpath) { - this.ensureMetadataLoaded(); - return this.exists() && - fdbUtil.buffersEqual(this.layer, buffer('partition')) && - (includeEmptySubpath || this.targetPath.length > this.path.length); -}; - -Node.prototype.getPartitionSubpath = function() { - this.ensureMetadataLoaded(); - return this.targetPath.slice(this.path.length); -}; - -Node.prototype.getContents = function(directoryLayer) { - this.ensureMetadataLoaded(); - return contentsOfNode(directoryLayer, this.subspace, this.path, this.layer); -}; - -var loadMetadata = function(tr) { - return function(node) { - return node.loadMetadata(tr); - }; -}; - -module.exports = { directory: new DirectoryLayer(), DirectoryLayer: DirectoryLayer }; diff --git a/bindings/nodejs/lib/error.js b/bindings/nodejs/lib/error.js deleted file mode 100644 index feb16957b3..0000000000 --- a/bindings/nodejs/lib/error.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - * error.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -function FDBError(description, code) { - Error.captureStackTrace(this, this.constructor); - this.message = description; - this.code = code; -} - -FDBError.prototype = new Error(); -FDBError.constructor = FDBError; -FDBError.prototype.name = "FDBError"; // affects error messages, also needed for compatibility with older bindings - -module.exports = FDBError; diff --git a/bindings/nodejs/lib/fdb.js b/bindings/nodejs/lib/fdb.js deleted file mode 100644 index 056a3bad41..0000000000 --- a/bindings/nodejs/lib/fdb.js +++ /dev/null @@ -1,115 +0,0 @@ -/* - * fdb.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var KeySelector = require('./keySelector'); -var Cluster = require('./cluster'); -var future = require('./future'); -var Transactional = require('./retryDecorator'); -var tuple = require('./tuple'); -var buffer = require('./bufferConversion'); -var fdb = require('./fdbModule'); -var FDBError = require('./error'); -var locality = require('./locality'); -var directory = require('./directory'); -var Subspace = require('./subspace'); -var selectedApiVersion = require('./apiVersion'); - -var fdbModule = {}; - -module.exports = { - FDBError: FDBError, - apiVersion: function(version) { - if(selectedApiVersion.value && version !== selectedApiVersion.value) - throw new Error('Cannot select multiple different FDB API versions'); - if(version < 500) - throw new RangeError('FDB API versions before 500 are not supported'); - if(version > 510) - throw new RangeError('Latest known FDB API version is 510'); - - if(!selectedApiVersion.value) { - fdb.apiVersion(version); - - fdbModule.FDBError = this.FDBError; - fdbModule.KeySelector = KeySelector; - fdbModule.future = future; - fdbModule.transactional = Transactional; - fdbModule.tuple = tuple; - fdbModule.buffer = buffer; - fdbModule.locality = locality; - fdbModule.directory = directory.directory; - fdbModule.DirectoryLayer = directory.DirectoryLayer; - fdbModule.Subspace = Subspace; - - fdbModule.options = fdb.options; - fdbModule.streamingMode = fdb.streamingMode; - - var dbCache = {}; - - var doInit = function() { - fdb.startNetwork(); - - process.on('exit', function() { - //Clearing out the caches makes memory debugging a little easier - dbCache = null; - - fdb.stopNetwork(); - }); - - //Subsequent calls do nothing - doInit = function() { }; - }; - - fdbModule.init = function() { - doInit(); - }; - - fdbModule.createCluster = function(clusterFile, cb) { - if(!clusterFile) - clusterFile = ''; - - return new Cluster(fdb.createCluster(clusterFile)); - }; - - fdbModule.open = function(clusterFile, cb) { - if(clusterFile) - fdb.options.setClusterFile(clusterFile); - - this.init(); - - var database = dbCache[clusterFile]; - if(!database) { - var cluster = fdbModule.createCluster(clusterFile); - database = cluster.openDatabase(); - dbCache[clusterFile] = database; - } - - return database; - }; - } - - selectedApiVersion.value = version; - return fdbModule; - } -}; - -fdb.FDBError = module.exports.FDBError; diff --git a/bindings/nodejs/lib/fdbModule.js b/bindings/nodejs/lib/fdbModule.js deleted file mode 100644 index 047279d184..0000000000 --- a/bindings/nodejs/lib/fdbModule.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * fdbModule.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var semver = require('semver'); - -if(semver.satisfies(process.version, '0.10.x')) - var fdb = require('../modules/0.10/fdblib'); -else if(semver.satisfies(process.version, '0.8.x')) - var fdb = require('../modules/0.8/fdblib'); -else - throw new Error('FoundationDB binary NPM does not support Node.js ' + process.version + '; only v0.8.x and v0.10.x are supported'); - -module.exports = fdb; diff --git a/bindings/nodejs/lib/fdbUtil.js b/bindings/nodejs/lib/fdbUtil.js deleted file mode 100644 index ed3b80777b..0000000000 --- a/bindings/nodejs/lib/fdbUtil.js +++ /dev/null @@ -1,104 +0,0 @@ -/* - * fdbUtil.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var buffer = require('./bufferConversion'); -var future = require('./future'); - -var strinc = function(str) { - var buf = buffer(str); - - var lastNonFFByte; - for(lastNonFFByte = buf.length-1; lastNonFFByte >= 0; --lastNonFFByte) - if(buf[lastNonFFByte] != 0xFF) - break; - - if(lastNonFFByte < 0) - throw new Error('invalid argument \'' + str + '\': prefix must have at least one byte not equal to 0xFF'); - - var copy = new Buffer(lastNonFFByte + 1); - str.copy(copy, 0, 0, copy.length); - ++copy[lastNonFFByte]; - - return copy; -}; - -var whileLoop = function(func, cb) { - return future.create(function(futureCb) { - var calledCallback = true; - function outer(err, res) { - if(err || typeof(res) !== 'undefined') { - futureCb(err, res); - } - else if(!calledCallback) { - calledCallback = true; - } - else { - while(calledCallback) { - calledCallback = false; - func(outer); - } - - calledCallback = true; - } - } - - outer(); - }, cb); -}; - -var keyToBuffer = function(key) { - if(typeof(key.asFoundationDBKey) == 'function') - return buffer(key.asFoundationDBKey()); - - return buffer(key); -}; - -var valueToBuffer = function(val) { - if(typeof(val.asFoundationDBValue) == 'function') - return buffer(val.asFoundationDBValue()); - - return buffer(val); -}; - -var buffersEqual = function(buf1, buf2) { - if(!buf1 || !buf2) - return buf1 === buf2; - - if(buf1.length !== buf2.length) - return false; - - for(var i = 0; i < buf1.length; ++i) - if(buf1[i] !== buf2[i]) - return false; - - return true; -}; - -module.exports = { - strinc: strinc, - whileLoop: whileLoop, - keyToBuffer: keyToBuffer, - valueToBuffer: valueToBuffer, - buffersEqual: buffersEqual -}; - diff --git a/bindings/nodejs/lib/future.js b/bindings/nodejs/lib/future.js deleted file mode 100644 index e21293b42b..0000000000 --- a/bindings/nodejs/lib/future.js +++ /dev/null @@ -1,244 +0,0 @@ -/* - * future.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; -var semver = require('semver'); - -function isFunction(f) { - return typeof(f) == 'function'; -} - -function isObject(o) { - return o === Object(o); -} - -var resolvePromise = function(promise, value) { - var called = false; - try { - if(promise === value) - promise._state.reject(new TypeError('promise.then cannot be fulfilled with itself as the argument.')); - - if(isObject(value)) { - var then = value.then; - if(isFunction(then)) { - then.call(value, function(res) { - if(!called) { - called = true; - resolvePromise(promise, res, promise); - } - }, function(err) { - if(!called) { - called = true; - promise._state.reject(err); - } - }); - } - else - promise._state.fulfill(value); - } - else - promise._state.fulfill(value); - } - catch(error) { - if(!called) - promise._state.reject(error); - } -}; - -var FuturePrototype = { - cancel: function() { - //cancel is not implemented for most futures - }, - - then: function(onFulfilled, onRejected) { - var self = this; - var future = create(); - this._state.addCallback(function(err, res) { - var setImmediateFunc; - if(semver.satisfies(process.version, '>=0.10.0')) { - setImmediateFunc = setImmediate; - } - else { - setImmediateFunc = process.nextTick; - } - setImmediateFunc(function() { - try { - if(self._state.rejected) { - if(isFunction(onRejected)) - res = onRejected(err); - else { - future._state.reject(err); - return; - } - } - else if(isFunction(onFulfilled)) - res = onFulfilled(res); - - resolvePromise(future, res); - } - catch(error) { - future._state.reject(error); - } - }); - }); - - return future; - }, - - "catch": function(onRejected) { - this.then(undefined, onRejected); - } -}; - -FuturePrototype.__proto__ = Function.__proto__; - -var FutureState = function() { - this.callbacks = []; - this.fulfilled = false; - this.rejected = false; -}; - -FutureState.prototype.triggerCallbacks = function() { - for(var i = 0; i < this.callbacks.length; ++i) - this.callbacks[i](this.error, this.value); - - this.callbacks = []; -}; - -FutureState.prototype.addCallback = function(cb) { - if(!this.rejected && !this.fulfilled) - this.callbacks.push(cb); - else - cb(this.error, this.value); -}; - -FutureState.prototype.fulfill = function(value) { - if(!this.fulfilled && !this.rejected) { - this.fulfilled = true; - this.value = value; - this.triggerCallbacks(); - } -}; - -FutureState.prototype.reject = function(reason) { - if(!this.fulfilled && !this.rejected) { - this.rejected = true; - this.error = reason; - this.triggerCallbacks(); - } -}; - -var getFutureCallback = function(futureState) { - return function(err, val) { - if(err) - futureState.reject(err); - else - futureState.fulfill(val); - }; -}; - -var create = function(func, cb) { - if(cb) - func(cb); - else { - // This object is used to break a reference cycle with C++ objects - var futureState = new FutureState(); - - var future = function(callback) { - if(typeof callback === 'undefined') - return future; - - future.then(function(val) { callback(undefined, val); }, callback); - }; - - future._state = futureState; - future.__proto__ = FuturePrototype; - - if(func) - func.call(future, getFutureCallback(futureState)); - - return future; - } -}; - -var resolve = function(value) { - var f = create(); - f._state.fulfill(value); - return f; -}; - -var reject = function(reason) { - var f = create(); - f._state.reject(reason); - return f; -}; - -var all = function(futures) { - var future = create(function(futureCb) { - var count = futures.length; - - if(count === 0) - futureCb(undefined, []); - - var successCallback = function() { - if(--count === 0) - futureCb(undefined, futures.map(function(f) { return f._state.value; })); - }; - - for(var i = 0; i < futures.length; ++i) { - if(futures[i] && isFunction(futures[i].then)) - futures[i].then(successCallback, futureCb); - else - successCallback(); - } - }); - - return future; -}; - -var race = function(futures) { - var future = create(function(futureCb) { - var successCallback = function(val) { - futureCb(undefined, val); - }; - - for(var i = 0; i < futures.length; ++i) { - if(futures[i] && isFunction(futures[i].then)) - futures[i].then(successCallback, futureCb); - else { - futureCb(undefined, futures[i]); - break; - } - } - }); - - return future; -}; - -module.exports = { - FuturePrototype: FuturePrototype, - create: create, - resolve: resolve, - reject: reject, - all: all, - race: race -}; - diff --git a/bindings/nodejs/lib/keySelector.js b/bindings/nodejs/lib/keySelector.js deleted file mode 100644 index a0960d375a..0000000000 --- a/bindings/nodejs/lib/keySelector.js +++ /dev/null @@ -1,65 +0,0 @@ -/* - * keySelector.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var fdbUtil = require('./fdbUtil'); - -var KeySelector = function(key, orEqual, offset) { - this.key = fdbUtil.keyToBuffer(key); - this.orEqual = orEqual; - this.offset = offset; -}; - -KeySelector.prototype.next = function() { - return this.add(1); -}; - -KeySelector.prototype.prev = function() { - return this.add(-1); -}; - -KeySelector.prototype.add = function(addOffset) { - return new KeySelector(this.key, this.orEqual, this.offset + addOffset); -}; - -KeySelector.isKeySelector = function(sel) { - return sel instanceof KeySelector; -}; - -KeySelector.lastLessThan = function(key) { - return new KeySelector(key, false, 0); -}; - -KeySelector.lastLessOrEqual = function(key) { - return new KeySelector(key, true, 0); -}; - -KeySelector.firstGreaterThan = function(key) { - return new KeySelector(key, true, 1); -}; - -KeySelector.firstGreaterOrEqual = function(key) { - return new KeySelector(key, false, 1); -}; - -module.exports = KeySelector; - diff --git a/bindings/nodejs/lib/lazyIterator.js b/bindings/nodejs/lib/lazyIterator.js deleted file mode 100644 index b746493d0b..0000000000 --- a/bindings/nodejs/lib/lazyIterator.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - * lazyIterator.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var fdbUtil = require('./fdbUtil'); -var future = require('./future'); - -function fetch(state, cb) { - if(cb) - state.fetchCallbacks.push(cb); - if(!state.fetching) { - state.fetching = true; - state.fetcher.fetch(function(err, res) { - var cbs = state.fetchCallbacks; - state.fetching = false; - state.fetchCallbacks = []; - state.results = res; - state.index = -1; - state.finished = !res || res.length === 0; - - for(var i = 0; i < cbs.length; ++i) - cbs[i](err); - }); - } -} - -function iterState(fetcher) { - return { - index: -1, - results: undefined, - - fetching: false, - fetchCallbacks: [], - fetcher: fetcher - }; -} - -var LazyIterator = function(Fetcher) { - this.Fetcher = Fetcher; - this.stateForNext = undefined; - - this.startState = iterState(new Fetcher()); - - var startState = this.startState; - fetch(this.startState); -}; - -function copyState(state, wantAll) { - var newState = iterState(); - newState.index = state.index; - newState.results = state.results; - newState.fetching = state.fetching; - - if(state.fetching) { - state.fetchCallbacks.push(function(err) { - var cbs = newState.fetchCallbacks; - newState.index = state.index; - newState.results = state.results; - newState.fetching = false; - newState.fetchCallbacks = []; - newState.finished = state.finished; - newState.fetcher = state.fetcher.clone(wantAll); - for(var i = 0; i < cbs.length; ++i) - cbs[i](err); - }); - } - else { - newState.fetcher = state.fetcher.clone(wantAll); - } - - return newState; -} - -function nextImpl(state, cb) { - if(state.finished) - cb(); - else if(state.results && (state.index + 1) < state.results.length) - cb(null, state.results[++state.index]); - else { - fetch(state, function(err) { - if(err) - cb(err); - else if(state.finished) - cb(); - else - nextImpl(state, cb); - }); - } -} - -LazyIterator.prototype.next = function(cb) { - var itr = this; - return future.create(function(futureCb) { - if(!itr.stateForNext) - itr.stateForNext = copyState(itr.startState); - - nextImpl(itr.stateForNext, futureCb); - }, cb); -}; - -LazyIterator.prototype.forEach = function(func, cb) { - var itr = this; - return future.create(function(futureCb) { - var state = copyState(itr.startState); - - fdbUtil.whileLoop(function(loopCb) { - nextImpl(state, function(err, res) { - if(err || !res) - loopCb(err, null); - else - func(res, loopCb); - }); - }, futureCb); - - }, cb); -}; - -function forEachBatchImpl(state, func, cb) { - function loopBody(loopCb) { - function processBatch(err) { - if(err || state.finished) - loopCb(err, null); - else { - state.index = state.results.length; - func(state.results, loopCb); - } - } - - if(!state.results || state.index === state.results.length) - fetch(state, processBatch); - else - processBatch(); - } - - fdbUtil.whileLoop(loopBody, cb); -} - -LazyIterator.prototype.forEachBatch = function(func, cb) { - var itr = this; - return future.create(function(futureCb) { - forEachBatchImpl(copyState(itr.startState), func, futureCb); - }, cb); -}; - -LazyIterator.prototype.toArray = function(cb) { - var itr = this; - return future.create(function(futureCb) { - var state = copyState(itr.startState, true); - var result = []; - - forEachBatchImpl(state, function(arr, itrCb) { - result = result.concat(arr); - itrCb(); - }, function(err, res) { - if(err) - futureCb(err); - else - futureCb(null, result); - }); - }, cb); -}; - -module.exports = LazyIterator; diff --git a/bindings/nodejs/lib/locality.js b/bindings/nodejs/lib/locality.js deleted file mode 100644 index e7ca31d700..0000000000 --- a/bindings/nodejs/lib/locality.js +++ /dev/null @@ -1,131 +0,0 @@ -/* - * locality.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var buffer = require('./bufferConversion'); -var transactional = require('./retryDecorator'); -var Database = require('./database'); -var LazyIterator = require('./lazyIterator'); -var fdb = require('./fdbModule'); -var fdbUtil = require('./fdbUtil'); - -var KEY_SERVERS_PREFIX = buffer.fromByteLiteral('\xff/keyServers/'); -var PAST_VERSION_ERROR_CODE = 1007; - -function getBoundaryKeysImpl(tr, begin, end, callback) { - function BoundaryFetcher(wantAll) { - this.tr = tr; - this.begin = begin; - this.end = end; - this.lastBegin = undefined; - - var fetcher = this; - - if(wantAll) - this.streamingMode = fdb.streamingMode.wantAll; - else - this.streamingMode = fdb.streamingMode.iterator; - - function iteratorCb(err, res) { - if(err) { - if(err.code === PAST_VERSION_ERROR_CODE && fetcher.begin !== fetcher.lastBegin) { - fetcher.tr = fetcher.tr.db.createTransaction(); - readKeys(); - } - else { - fetcher.tr.onError(err, function(e) { - if(e) - fetcher.fetchCb(e); - else - readKeys(); - }); - } - } - else - fetcher.fetchCb(); - } - - function readKeys() { - fetcher.lastBegin = fetcher.begin; - fetcher.tr.options.setReadSystemKeys(); - fetcher.tr.options.setLockAware(); - fetcher.tr.snapshot.getRange(fetcher.begin, fetcher.end, {streamingMode: fetcher.streamingMode}).forEachBatch(function(kvs, innerCb) { - fetcher.forEachCb = innerCb; - var keys = kvs.map(function(kv) { return kv.key.slice(13); }); - var last = kvs[kvs.length-1].key; - fetcher.begin = Buffer.concat([last, buffer.fromByteLiteral('\x00')], last.length + 1); - fetcher.fetchCb(undefined, keys); - }, iteratorCb); - - fetcher.streamingMode = fdb.streamingMode.wantAll; - } - - this.fetch = function(cb) { - this.fetchCb = cb; - if(this.read) - this.forEachCb(); - else { - this.read = true; - readKeys(); - } - }; - - this.clone = function(wantAll) { - var clone = new BoundaryFetcher(wantAll); - - clone.tr = this.tr.db.createTransaction(); - clone.begin = this.begin; - clone.end = this.end; - clone.lastBegin = this.lastBegin; - - return clone; - }; - } - - callback(null, new LazyIterator(BoundaryFetcher)); -} - -function getBoundaryKeys(databaseOrTransaction, begin, end, callback) { - begin = fdbUtil.keyToBuffer(begin); - end = fdbUtil.keyToBuffer(end); - - begin = Buffer.concat([KEY_SERVERS_PREFIX, begin], KEY_SERVERS_PREFIX.length + begin.length); - end = Buffer.concat([KEY_SERVERS_PREFIX, end], KEY_SERVERS_PREFIX.length + end.length); - - if(databaseOrTransaction instanceof Database) { - getBoundaryKeysImpl(databaseOrTransaction.createTransaction(), begin, end, callback); - } - else { - var tr = databaseOrTransaction.db.createTransaction(); - databaseOrTransaction.getReadVersion(function(err, ver) { - tr.setReadVersion(ver); - getBoundaryKeysImpl(tr, begin, end, callback); - }); - } -} - -var getAddressesForKey = transactional(function (tr, key, cb) { - key = fdbUtil.keyToBuffer(key); - tr.tr.getAddressesForKey(key, cb); -}); - -module.exports = {getBoundaryKeys: getBoundaryKeys, getAddressesForKey: getAddressesForKey}; diff --git a/bindings/nodejs/lib/rangeIterator.js b/bindings/nodejs/lib/rangeIterator.js deleted file mode 100644 index 15e8723ef9..0000000000 --- a/bindings/nodejs/lib/rangeIterator.js +++ /dev/null @@ -1,106 +0,0 @@ -/* - * rangeIterator.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var KeySelector = require('./keySelector'); -var Future = require('./future'); -var fdb = require('./fdbModule'); -var LazyIterator = require('./lazyIterator'); - -function getStreamingMode(requestedMode, limit, wantAll) { - if(wantAll && requestedMode === fdb.streamingMode.iterator) { - if(limit) - return fdb.streamingMode.exact; - else - return fdb.streamingMode.wantAll; - } - - return requestedMode; -} - -module.exports = function(tr, start, end, options, snapshot) { - if(!options) - options = {}; - - if(!options.limit) - options.limit = 0; - if(!options.reverse) - options.reverse = false; - if(!options.streamingMode && options.streamingMode !== 0) - options.streamingMode = fdb.streamingMode.iterator; - - var RangeFetcher = function(wantAll) { - this.finished = false; - this.limit = options.limit; - this.iterStart = start; - this.iterEnd = end; - this.iterationCount = 1; - this.streamingMode = getStreamingMode(options.streamingMode, this.limit, wantAll); - }; - - RangeFetcher.prototype.clone = function(wantAll) { - var clone = new RangeFetcher(wantAll); - - clone.finished = this.finished; - clone.limit = this.limit; - clone.iterStart = this.iterStart; - clone.iterEnd = this.iterEnd; - clone.iterationCount = this.iterationCount; - - return clone; - }; - - RangeFetcher.prototype.fetch = function(cb) { - var fetcher = this; - if(fetcher.finished) { - cb(); - } - else { - tr.getRange(fetcher.iterStart.key, fetcher.iterStart.orEqual, fetcher.iterStart.offset, fetcher.iterEnd.key, fetcher.iterEnd.orEqual, fetcher.iterEnd.offset, fetcher.limit, fetcher.streamingMode, fetcher.iterationCount++, snapshot, options.reverse, function(err, res) - { - if(!err) { - var results = res.array; - if(results.length > 0) { - if(!options.reverse) - fetcher.iterStart = KeySelector.firstGreaterThan(results[results.length-1].key); - else - fetcher.iterEnd = KeySelector.firstGreaterOrEqual(results[results.length-1].key); - } - - if(fetcher.limit !== 0) { - fetcher.limit -= results.length; - if(fetcher.limit <= 0) - fetcher.finished = true; - } - if(!res.more) - fetcher.finished = true; - cb(undefined, results); - } - else { - cb(err); - } - }); - } - }; - - return new LazyIterator(RangeFetcher); -}; diff --git a/bindings/nodejs/lib/retryDecorator.js b/bindings/nodejs/lib/retryDecorator.js deleted file mode 100644 index ffbb8f8ce5..0000000000 --- a/bindings/nodejs/lib/retryDecorator.js +++ /dev/null @@ -1,50 +0,0 @@ -/* - * retryDecorator.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var Database = require('./database'); -var Transaction = require('./transaction'); - -module.exports = function(func) { - return function(db) { - var self = this; - - if(db instanceof Database) { - var cb = arguments[func.length - 1]; - - if(typeof cb !== "undefined" && !(cb instanceof Function)) - throw new TypeError("fdb.transactional function must declare a callback function as last argument"); - else { - var args = Array.prototype.slice.call(arguments); - return db.doTransaction(function(tr, innerCb) { - args[0] = tr; - args[func.length - 1] = innerCb; - func.apply(self, args); - })(cb); - } - } - else if(db instanceof Transaction || db instanceof Transaction.SnapshotTransaction) - return func.apply(self, arguments); - else - throw new TypeError("fdb.transactional function must pass a Database, Transaction, or SnapshotTransaction as first argument"); - }; -}; diff --git a/bindings/nodejs/lib/subspace.js b/bindings/nodejs/lib/subspace.js deleted file mode 100644 index e6b05942ad..0000000000 --- a/bindings/nodejs/lib/subspace.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * subspace.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var buffer = require('./bufferConversion'); -var fdbUtil = require('./fdbUtil'); -var tuple = require('./tuple'); - -var Subspace = function(prefixArray, rawPrefix) { - if(typeof rawPrefix === 'undefined') - rawPrefix = new Buffer(0); - if(typeof prefixArray === 'undefined') - prefixArray = []; - - rawPrefix = fdbUtil.keyToBuffer(rawPrefix); - var packed = tuple.pack(prefixArray); - - this.rawPrefix = Buffer.concat([rawPrefix, packed], rawPrefix.length + packed.length); -}; - -Subspace.prototype.key = function() { - return this.rawPrefix; -}; - -Subspace.prototype.pack = function(arr) { - var packed = tuple.pack(arr); - return Buffer.concat([this.rawPrefix, packed], this.rawPrefix.length + packed.length) ; -}; - -Subspace.prototype.unpack = function(key) { - key = fdbUtil.keyToBuffer(key); - if(!this.contains(key)) - throw new Error('Cannot unpack key that is not in subspace.'); - - return tuple.unpack(key.slice(this.rawPrefix.length)); -}; - -Subspace.prototype.range = function(arr) { - if(typeof arr === 'undefined') - arr = []; - - var range = tuple.range(arr); - return { - begin: Buffer.concat([this.rawPrefix, range.begin], this.rawPrefix.length + range.begin.length), - end: Buffer.concat([this.rawPrefix, range.end], this.rawPrefix.length + range.end.length) - }; -}; - -Subspace.prototype.contains = function(key) { - key = fdbUtil.keyToBuffer(key); - return key.length >= this.rawPrefix.length && fdbUtil.buffersEqual(key.slice(0, this.rawPrefix.length), this.rawPrefix); -}; - -Subspace.prototype.get = function(item) { - return this.subspace([item]); -}; - -Subspace.prototype.subspace = function(arr) { - return new Subspace(arr, this.rawPrefix); -}; - -Subspace.prototype.asFoundationDBKey = function() { - return this.key(); -}; - -module.exports = Subspace; diff --git a/bindings/nodejs/lib/transaction.js b/bindings/nodejs/lib/transaction.js deleted file mode 100644 index ecd4ef83e8..0000000000 --- a/bindings/nodejs/lib/transaction.js +++ /dev/null @@ -1,203 +0,0 @@ -/* - * transaction.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var future = require('./future'); -var KeySelector = require('./keySelector'); -var rangeIterator = require('./rangeIterator'); -var buffer = require('./bufferConversion'); -var FDBError = require('./error'); -var fdb = require('./fdbModule'); -var fdbUtil = require('./fdbUtil'); - -function addReadOperations(object, snapshot) { - object.prototype.get = function(key, cb) { - var tr = this.tr; - key = fdbUtil.keyToBuffer(key); - - return future.create(function(futureCb) { - tr.get(key, snapshot, futureCb); - }, cb); - }; - - object.prototype.getKey = function(keySelector, cb) { - var tr = this.tr; - return future.create(function(futureCb) { - tr.getKey(keySelector.key, keySelector.orEqual, keySelector.offset, snapshot, futureCb); - }, cb); - }; - - object.prototype.getRange = function(start, end, options) { - if(!KeySelector.isKeySelector(start)) - start = KeySelector.firstGreaterOrEqual(start); - if(!KeySelector.isKeySelector(end)) - end = KeySelector.firstGreaterOrEqual(end); - - return rangeIterator(this.tr, start, end, options, snapshot); - }; - - object.prototype.getRangeStartsWith = function(prefix, options) { - prefix = fdbUtil.keyToBuffer(prefix); - return this.getRange(prefix, fdbUtil.strinc(prefix), options, snapshot); - }; - - object.prototype.getReadVersion = function(cb) { - var tr = this.tr; - return future.create(function(futureCb) { - tr.getReadVersion(futureCb, snapshot); - }, cb); - }; -} - -var atomic = function(tr, op) { - return function(key, value) { fdb.atomic[op].call(tr, fdbUtil.keyToBuffer(key), fdbUtil.valueToBuffer(value)); }; -}; - -var Transaction = function(db, tr) { - this.db = db; - this.tr = tr; - - this.options = tr.options; - this.snapshot = new Transaction.SnapshotTransaction(tr); - - for(var op in fdb.atomic) - this[op] = atomic(tr, op); -}; - -Transaction.SnapshotTransaction = function(tr) { - this.tr = tr; -}; - -addReadOperations(Transaction, false); -addReadOperations(Transaction.SnapshotTransaction, true); - -Transaction.prototype.doTransaction = function(func, cb) { - var self = this; - return future.create(function(futureCb) { - func(self, futureCb); - }, cb); -}; - -Transaction.prototype.set = function(key, value) { - key = fdbUtil.keyToBuffer(key); - value = fdbUtil.valueToBuffer(value); - - this.tr.set(key, value); -}; - -Transaction.prototype.clear = function(key) { - key = fdbUtil.keyToBuffer(key); - - this.tr.clear(key); -}; - -Transaction.prototype.clearRange = function(start, end) { - start = fdbUtil.keyToBuffer(start); - end = fdbUtil.keyToBuffer(end); - - this.tr.clearRange(start, end); -}; - -Transaction.prototype.clearRangeStartsWith = function(prefix) { - prefix = fdbUtil.keyToBuffer(prefix); - this.clearRange(prefix, fdbUtil.strinc(prefix)); -}; - -Transaction.prototype.watch = function(key) { - key = fdbUtil.keyToBuffer(key); - - var self = this; - var watchFuture = future.create(function(futureCb) { - // 'this' is the future that is being created. - // We set its cancel method to cancel the watch. - this._watch = self.tr.watch(key, futureCb); - this.cancel = function() { this._watch.cancel(); }; - }); - - return watchFuture; -}; - -Transaction.prototype.addReadConflictRange = function(start, end) { - start = fdbUtil.keyToBuffer(start); - end = fdbUtil.keyToBuffer(end); - this.tr.addReadConflictRange(start, end); -}; - -Transaction.prototype.addReadConflictKey = function(key) { - key = fdbUtil.keyToBuffer(key); - this.tr.addReadConflictRange(key, Buffer.concat([key, buffer.fromByteLiteral('\x00')], key.length + 1)); -}; - -Transaction.prototype.addWriteConflictRange = function(start, end) { - start = fdbUtil.keyToBuffer(start); - end = fdbUtil.keyToBuffer(end); - - this.tr.addWriteConflictRange(start, end); -}; - -Transaction.prototype.addWriteConflictKey = function(key) { - key = fdbUtil.keyToBuffer(key); - this.tr.addWriteConflictRange(key, Buffer.concat([key, buffer.fromByteLiteral('\x00')], key.length + 1)); -}; - -Transaction.prototype.commit = function(cb) { - var tr = this.tr; - return future.create(function(futureCb) { - tr.commit(futureCb); - }, cb); -}; - -Transaction.prototype.onError = function(fdbError, cb) { - var tr = this.tr; - return future.create(function(futureCb) { - if(fdbError instanceof FDBError) - tr.onError(fdbError.code, futureCb); - else - futureCb(fdbError, null); - }, cb); -}; - -Transaction.prototype.reset = function() { - this.tr.reset(); -}; - -Transaction.prototype.setReadVersion = function(version) { - this.tr.setReadVersion(version); -}; - -Transaction.prototype.getCommittedVersion = function() { - return this.tr.getCommittedVersion(); -}; - -Transaction.prototype.getVersionstamp = function(cb) { - var tr = this.tr; - return future.create(function(futureCb) { - tr.getVersionstamp(futureCb); - }, cb); -}; - -Transaction.prototype.cancel = function() { - this.tr.cancel(); -}; - -module.exports = Transaction; - diff --git a/bindings/nodejs/lib/tuple.js b/bindings/nodejs/lib/tuple.js deleted file mode 100644 index d7b1d25a76..0000000000 --- a/bindings/nodejs/lib/tuple.js +++ /dev/null @@ -1,481 +0,0 @@ -/* - * tuple.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -"use strict"; - -var assert = require('assert'); -var buffer = require('./bufferConversion'); -var fdbUtil = require('./fdbUtil'); -var fdb = require('./fdbModule'); -var FDBError = require('./error'); - -var sizeLimits = new Array(8); - -function setupSizeLimits() { - sizeLimits[0] = 1; - for(var i = 1; i < sizeLimits.length; i++) { - sizeLimits[i] = sizeLimits[i-1] * 256; - sizeLimits[i-1] -= 1; - } - sizeLimits[7] -= 1; -} - -setupSizeLimits(); - -var maxInt = Math.pow(2, 53) - 1; -var minInt = -Math.pow(2, 53); - -var nullByte = new Buffer('00', 'hex'); - -var BYTES_CODE = 0x01; -var STRING_CODE = 0x02; -var NESTED_CODE = 0x05; -var INT_ZERO_CODE = 0x14; -var POS_INT_END = 0x1d; -var NEG_INT_END = 0x0b; -var FLOAT_CODE = 0x20; -var DOUBLE_CODE = 0x21; -var FALSE_CODE = 0x26; -var TRUE_CODE = 0x27; -var UUID_CODE = 0x30; - -function validateData(data, length) { - if(!(data instanceof Buffer) && !(data instanceof Array)) { - throw new TypeError('Data for FDB tuple type not array or buffer.'); - } else if(data.length != length) { - throw new RangeError('Data for FDB tuple type has length ' + data.length + ' instead of expected length ' + length); - } -} - -// If encoding and sign bit is 1 (negative), flip all of the bits. Otherwise, just flip sign. -// If decoding and sign bit is 0 (negative), flip all of the bits. Otherwise, just flip sign. -function adjustFloat(data, start, encode) { - if((encode && (data[start] & 0x80) === 0x80) || (!encode && (data[start] & 0x80) === 0x00)) { - for(var i = start; i < data.length; i++) { - data[i] = data[i] ^ 0xff; - } - } else { - data[start] = data[start] ^ 0x80; - } -} - -function Float(value) { - this.value = value; - this.toBytes = function () { - if (this.rawData !== undefined) { - return this.rawData; - } else { - var buf = new Buffer(4); - buf.writeFloatBE(fdb.toFloat(this.value), 0); - return buf; - } - }; -} - -Float.fromBytes = function (buf) { - validateData(buf, 4); - var f = new Float(buf.readFloatBE(0)); - if(isNaN(f.value)) { - f.rawData = buf; - } - return f; -} - -function Double(value) { - this.value = value; - this.toBytes = function () { - if (this.rawData !== undefined) { - return this.rawData; - } else { - var buf = new Buffer(8); - buf.writeDoubleBE(this.value, 0); - return buf; - } - }; -} - -Double.fromBytes = function (buf) { - validateData(buf, 8); - var d = new Double(buf.readDoubleBE(0)); - if(isNaN(d.value)) { - d.rawData = buf; - } - return d; -} - -function UUID(data) { - if (data.length != 16) { - // There's a special code for this, so we check it first and throw the error if appropriate. - throw new FDBError("invalid_uuid_size", 2268); - } - validateData(data, 16); - this.data = new Buffer(data); -} - -function findNullBytes(buf, pos, searchForTerminators) { - var nullBytes = []; - - var found; - for(pos; pos < buf.length; ++pos) { - if(searchForTerminators && found && buf[pos] !== 255) { - break; - } - - found = false; - if(buf[pos] === 0) { - found = true; - nullBytes.push(pos); - } - } - - if(!found && searchForTerminators) { - nullBytes.push(buf.length); - } - - return nullBytes; -} - -function encode(item, buf, pos) { - var encodedString; - if(typeof item === 'undefined') - throw new TypeError('Packed element cannot be undefined'); - - else if(item === null) - return nullByte; - - //byte string or unicode - else if(Buffer.isBuffer(item) || item instanceof ArrayBuffer || item instanceof Uint8Array || typeof item === 'string') { - var unicode = typeof item === 'string'; - - if(unicode) { - item = new Buffer(item, 'utf8'); - } - else { - item = buffer(item); - } - - var nullBytes = findNullBytes(item, 0); - - encodedString = new Buffer(2 + item.length + nullBytes.length); - encodedString[0] = unicode ? STRING_CODE : BYTES_CODE; - - var srcPos = 0; - var targetPos = 1; - for(var i = 0; i < nullBytes.length; ++i) { - item.copy(encodedString, targetPos, srcPos, nullBytes[i]+1); - targetPos += nullBytes[i]+1 - srcPos; - srcPos = nullBytes[i]+1; - encodedString[targetPos++] = 255; - } - - item.copy(encodedString, targetPos, srcPos); - encodedString[encodedString.length-1] = 0; - - return encodedString; - } - - //64-bit integer - else if((typeof item === 'number' || item instanceof Number) && item % 1 === 0) { - var negative = item < 0; - var posItem = Math.abs(item); - - var length = 0; - for(; length < sizeLimits.length; ++length) { - if(posItem <= sizeLimits[length]) - break; - } - - if(item > maxInt || item < minInt) - throw new RangeError('Cannot pack signed integer larger than 54 bits'); - - var prefix = negative ? INT_ZERO_CODE - length : INT_ZERO_CODE + length; - - var outBuf = new Buffer(length+1); - outBuf[0] = prefix; - for(var byteIdx = length-1; byteIdx >= 0; --byteIdx) { - var b = posItem & 0xff; - if(negative) - outBuf[byteIdx+1] = ~b; - else { - outBuf[byteIdx+1] = b; - } - - posItem = (posItem - b) / 0x100; - } - - return outBuf; - } - - // Floats - else if(item instanceof Float) { - var outBuf = new Buffer(5); - outBuf[0] = FLOAT_CODE; - if (isNaN(item.value) && item.rawData !== undefined) { - item.rawData.copy(outBuf, 1, 0, 4); - } else { - outBuf.writeFloatBE(fdb.toFloat(item.value), 1); - } - adjustFloat(outBuf, 1, true); - return outBuf; - } - - // Doubles - else if(item instanceof Double) { - var outBuf = new Buffer(9); - outBuf[0] = DOUBLE_CODE; - if (isNaN(item.value) && item.rawData !== undefined) { - item.rawData.copy(outBuf, 1, 0, 8); - } else { - outBuf.writeDoubleBE(item.value, 1); - } - adjustFloat(outBuf, 1, true); - return outBuf; - } - - // UUIDs - else if(item instanceof UUID) { - var outBuf = new Buffer(17); - outBuf[0] = UUID_CODE; - item.data.copy(outBuf, 1); - return outBuf; - } - - // booleans - else if(item instanceof Boolean || typeof item === 'boolean') { - var outBuf = new Buffer(1); - var boolItem; - if(item instanceof Boolean) { - boolItem = item.valueOf(); - } else { - boolItem = item; - } - if(boolItem) { - outBuf[0] = TRUE_CODE; - } else { - outBuf[0] = FALSE_CODE; - } - return outBuf; - } - - // nested tuples - else if(item instanceof Array) { - var totalLength = 2; - var outArr = [new Buffer('05', 'hex')]; - for(var i = 0; i < item.length; ++i) { - if(item[i] === null) { - outArr.push(new Buffer('00ff', 'hex')); - totalLength += 2; - } else { - outArr.push(encode(item[i])); - totalLength += outArr[i+1].length; - } - } - outArr.push(new Buffer('00', 'hex')) - return Buffer.concat(outArr, totalLength); - } - - else - throw new TypeError('Packed element must either be a string, a buffer, an integer, or null'); -} - -function pack(arr) { - if(!(arr instanceof Array)) - throw new TypeError('fdb.tuple.pack must be called with a single array argument'); - - var totalLength = 0; - - var outArr = []; - for(var i = 0; i < arr.length; ++i) { - outArr.push(encode(arr[i])); - totalLength += outArr[i].length; - } - - return Buffer.concat(outArr, totalLength); -} - -function decodeNumber(buf, offset, bytes) { - var negative = bytes < 0; - bytes = Math.abs(bytes); - - var num = 0; - var mult = 1; - var odd; - for(var i = bytes-1; i >= 0; --i) { - var b = buf[offset+i]; - if(negative) - b = -(~b & 0xff); - - if(i == bytes-1) - odd = b & 0x01; - - num += b * mult; - mult *= 0x100; - } - - if(num > maxInt || num < minInt || (num === minInt && odd)) - throw new RangeError('Cannot unpack signed integers larger than 54 bits'); - - return num; -} - -function decode(buf, pos, nested) { - if(typeof nested === 'undefined') nested = false; - - var code = buf[pos]; - var value; - - if(code === 0) { - value = null; - if(nested) { - pos += 2; - } else { - pos++; - } - } - else if(code === BYTES_CODE || code === STRING_CODE) { - var nullBytes = findNullBytes(buf, pos+1, true); - - var start = pos+1; - var end = nullBytes[nullBytes.length-1]; - - if(code === STRING_CODE && nullBytes.length === 1) { - value = buf.toString('utf8', start, end); - } - else { - value = new Buffer(end-start-(nullBytes.length-1)); - var valuePos = 0; - - for(var i=0; i < nullBytes.length && start < end; ++i) { - buf.copy(value, valuePos, start, nullBytes[i]); - valuePos += nullBytes[i] - start; - start = nullBytes[i] + 2; - if(start <= end) { - value[valuePos++] = 0; - } - } - - if(code === STRING_CODE) - value = value.toString('utf8'); - } - - pos = end + 1; - } - else if(Math.abs(code-INT_ZERO_CODE) <= 7) { - if(code === INT_ZERO_CODE) - value = 0; - else - value = decodeNumber(buf, pos+1, code-INT_ZERO_CODE); - - pos += Math.abs(INT_ZERO_CODE-code) + 1; - } - else if(Math.abs(code-INT_ZERO_CODE) <= 8) - throw new RangeError('Cannot unpack signed integers larger than 54 bits'); - else if(code === FLOAT_CODE) { - var valBuf = new Buffer(4); - buf.copy(valBuf, 0, pos+1, pos+5); - adjustFloat(valBuf, 0, false); - value = Float.fromBytes(valBuf); - pos += 5; - } - else if(code === DOUBLE_CODE) { - var valBuf = new Buffer(8); - buf.copy(valBuf, 0, pos+1, pos+9); - adjustFloat(valBuf, 0, false); - value = Double.fromBytes(valBuf); - pos += 9; - } - else if(code === UUID_CODE) { - var valBuf = new Buffer(16); - buf.copy(valBuf, 0, pos+1, pos+17); - value = new UUID(valBuf); - pos += 17; - } - else if(code === FALSE_CODE) { - pos++; - value = false; - } - else if(code === TRUE_CODE) { - pos++; - value = true; - } - else if(code === NESTED_CODE) { - pos++; - value = [] - while (buf[pos] != 0 || pos+1 < buf.length && buf[pos+1] === 0xff) { - var nestedVal = decode(buf, pos, true) - pos = nestedVal.pos - value.push(nestedVal.value) - } - pos++; - } - else - throw new TypeError('Unknown data type in DB: ' + buf + ' at ' + pos); - - return { pos: pos, value: value }; -} - -function unpack(key) { - var res = { pos: 0 }; - var arr = []; - - key = fdbUtil.keyToBuffer(key); - - while(res.pos < key.length) { - res = decode(key, res.pos); - arr.push(res.value); - } - - return arr; -} - -function range(arr) { - var packed = pack(arr); - return { begin: Buffer.concat([packed, nullByte]), end: Buffer.concat([packed, new Buffer('ff', 'hex')]) }; -} - -function compare(arr1, arr2) { - // NOTE: There is built-in comparison function included in 0.11.13 that we might want to switch to. - var buf1 = pack(arr1); - var buf2 = pack(arr2); - var pos = 0; - - while(pos < buf1.length && pos < buf2.length) { - if(buf1[pos] != buf2[pos]) { - if(buf1[pos] < buf2[pos]) { - return -1; - } else { - return 1; - } - } - pos += 1; - } - - // The two arrays begin with a common prefix. - if(buf1.length < buf2.length) { - return -1; - } else if(buf1.length == buf2.length) { - return 0; - } else { - return 1; - } -} - -module.exports = {pack: pack, unpack: unpack, range: range, compare: compare, Float: Float, Double: Double, UUID: UUID}; diff --git a/bindings/nodejs/package.json.in b/bindings/nodejs/package.json.in deleted file mode 100644 index c30539a3c2..0000000000 --- a/bindings/nodejs/package.json.in +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "@apple/fdb", - "publishConfig": { - "registry": "https://registry.npmjs.org" - }, - "version": "VERSION", - "author": "FoundationDB (https://www.foundationdb.org)", - "description": "Node.js bindings for the FoundationDB database", - "keywords": [ "FoundationDB", "database", "NoSQL", "ACID" ], - "homepage": "http://17.199.145.104", - "license": "Apache v2", - "main": "./lib/fdb.js", - "cpu": [ "x64" ], - "dependencies": { - "semver": "~ 4.1" - }, - "devDependencies": { - "jshint": ">= 2.5.6", - "promises-aplus-tests": ">= 2.1.0" - }, - "engineStrict": true, - "private": true, - "engines": { - "node" : "0.8.x || 0.10.x" - } -} diff --git a/bindings/nodejs/src/Cluster.cpp b/bindings/nodejs/src/Cluster.cpp deleted file mode 100644 index 53c248beb0..0000000000 --- a/bindings/nodejs/src/Cluster.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Cluster.cpp - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include -#include -#include -#include -#include - -#include "Cluster.h" -#include "Database.h" -#include "FdbOptions.h" -#include "NodeCallback.h" - -using namespace v8; -using namespace std; - -Cluster::Cluster() { } -Cluster::~Cluster() { - fdb_cluster_destroy(cluster); -} - -Persistent Cluster::constructor; - -Handle Cluster::OpenDatabase(const Arguments &args) { - HandleScope scope; - - Cluster *clusterPtr = ObjectWrap::Unwrap(args.Holder()); - - const char *dbName = "DB"; - FDBFuture *f = fdb_cluster_create_database(clusterPtr->cluster, (uint8_t*)dbName, (int)strlen(dbName)); - - fdb_error_t errorCode = fdb_future_block_until_ready(f); - - FDBDatabase *database; - if(errorCode == 0) - errorCode = fdb_future_get_database(f, &database); - - if(errorCode != 0) - return ThrowException(FdbError::NewInstance(errorCode, fdb_get_error(errorCode))); - - Handle jsValue = Database::NewInstance(database); - return scope.Close(jsValue); -} - -void Cluster::Init() { - HandleScope scope; - - Local tpl = FunctionTemplate::New(New); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - tpl->SetClassName(String::NewSymbol("Cluster")); - - tpl->PrototypeTemplate()->Set(String::NewSymbol("openDatabase"), FunctionTemplate::New(OpenDatabase)->GetFunction()); - - constructor = Persistent::New(tpl->GetFunction()); -} - -Handle Cluster::New(const Arguments &args) { - HandleScope scope; - - Cluster *c = new Cluster(); - c->Wrap(args.Holder()); - - return scope.Close(args.Holder()); -} - -Handle Cluster::NewInstance(FDBCluster *ptr) { - HandleScope scope; - - Local instance = constructor->NewInstance(0, NULL); - - Cluster *clusterObj = ObjectWrap::Unwrap(instance); - clusterObj->cluster = ptr; - - instance->Set(String::NewSymbol("options"), FdbOptions::CreateOptions(FdbOptions::ClusterOption, instance)); - - return scope.Close(instance); -} diff --git a/bindings/nodejs/src/Cluster.h b/bindings/nodejs/src/Cluster.h deleted file mode 100644 index 6f24ba48e3..0000000000 --- a/bindings/nodejs/src/Cluster.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Cluster.h - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef FDB_NODE_CLUSTER_H -#define FDB_NODE_CLUSTER_H - -#include "Version.h" - -#include -#include - -class Cluster : public node::ObjectWrap { - public: - static void Init(); - static v8::Handle NewInstance(FDBCluster *ptr); - static v8::Handle New(const v8::Arguments &args); - static v8::Handle OpenDatabase(const v8::Arguments &args); - static v8::Handle Destroy(const v8::Arguments &args); - - FDBCluster* GetCluster() { return cluster; } - - private: - Cluster(); - ~Cluster(); - static v8::Persistent constructor; - FDBCluster *cluster; -}; - -#endif diff --git a/bindings/nodejs/src/Database.cpp b/bindings/nodejs/src/Database.cpp deleted file mode 100644 index a6a2c62d40..0000000000 --- a/bindings/nodejs/src/Database.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Database.cpp - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include -#include -#include -#include - -#include "Database.h" -#include "FdbOptions.h" -#include "NodeCallback.h" - -using namespace v8; -using namespace std; - -Database::Database() { }; - -Database::~Database() { - fdb_database_destroy(db); -}; - -Persistent Database::constructor; - -void Database::Init() { - Local tpl = FunctionTemplate::New(New); - tpl->SetClassName(String::NewSymbol("Database")); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - - tpl->PrototypeTemplate()->Set(String::NewSymbol("createTransaction"), FunctionTemplate::New(CreateTransaction)->GetFunction()); - - constructor = Persistent::New(tpl->GetFunction()); -} - -Handle Database::CreateTransaction(const v8::Arguments &args) { - HandleScope scope; - - Database *dbPtr = node::ObjectWrap::Unwrap(args.Holder()); - FDBDatabase *db = dbPtr->db; - FDBTransaction *tr; - fdb_error_t err = fdb_database_create_transaction(db, &tr); - if (err) { - ThrowException(FdbError::NewInstance(err, fdb_get_error(err))); - return scope.Close(Undefined()); - } - - return scope.Close(Transaction::NewInstance(tr)); -} - -Handle Database::New(const Arguments &args) { - HandleScope scope; - - Database *db = new Database(); - db->Wrap(args.Holder()); - - return scope.Close(args.Holder()); -} - -Handle Database::NewInstance(FDBDatabase *ptr) { - HandleScope scope; - - Local instance = constructor->NewInstance(0, NULL); - Database *dbObj = ObjectWrap::Unwrap(instance); - dbObj->db = ptr; - - instance->Set(String::NewSymbol("options"), FdbOptions::CreateOptions(FdbOptions::DatabaseOption, instance)); - - return scope.Close(instance); -} diff --git a/bindings/nodejs/src/Database.h b/bindings/nodejs/src/Database.h deleted file mode 100644 index fd58ae8421..0000000000 --- a/bindings/nodejs/src/Database.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Database.h - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef FDB_NODE_DATABASE_H -#define FDB_NODE_DATABASE_H - -#include "Version.h" -#include "Transaction.h" - -#include -#include - -class Database: public node::ObjectWrap { - public: - static void Init(); - static v8::Handle NewInstance(FDBDatabase *ptr); - static v8::Handle New(const v8::Arguments &args); - - FDBDatabase* GetDatabase() { return db; } - - private: - Database(); - ~Database(); - - static v8::Handle CreateTransaction(const v8::Arguments &args); - static v8::Persistent constructor; - - FDBDatabase *db; -}; - -#endif diff --git a/bindings/nodejs/src/FdbError.cpp b/bindings/nodejs/src/FdbError.cpp deleted file mode 100644 index c37bfffbd4..0000000000 --- a/bindings/nodejs/src/FdbError.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * FdbError.cpp - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include -#include "FdbError.h" - -using namespace v8; -using namespace node; - -static Persistent module; - -void FdbError::Init( Handle module ) { - ::module = Persistent::New( module ); -} - -Handle FdbError::NewInstance(fdb_error_t code, const char *description) { - HandleScope scope; - - Local constructor = module->Get( String::NewSymbol("FDBError") ); - Local instance; - if (!constructor.IsEmpty() && constructor->IsFunction()) { - Local constructorArgs[] = { String::New(description), Integer::New(code) }; - instance = Local::Cast(constructor)->NewInstance(2, constructorArgs); - } else { - // We can't find the (javascript) FDBError class, so construct and throw *something* - instance = Exception::Error(String::New("FDBError class not found. Unable to deliver error."))->ToObject(); - } - - return scope.Close(instance); -} diff --git a/bindings/nodejs/src/FdbError.h b/bindings/nodejs/src/FdbError.h deleted file mode 100644 index 3ed7d8bc69..0000000000 --- a/bindings/nodejs/src/FdbError.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * FdbError.h - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef FDB_NODE_FDB_ERROR_H -#define FDB_NODE_FDB_ERROR_H - -#include "Version.h" - -#include -#include - -class FdbError { - public: - static v8::Handle NewInstance(fdb_error_t code, const char *description); - - static void Init( v8::Handle module ); - - private: - FdbError(); // not implemented by design -}; - -#endif diff --git a/bindings/nodejs/src/FdbOptions.cpp b/bindings/nodejs/src/FdbOptions.cpp deleted file mode 100644 index c5ba545dbb..0000000000 --- a/bindings/nodejs/src/FdbOptions.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* - * FdbOptions.cpp - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "FdbOptions.h" -#include "Cluster.h" -#include "Database.h" -#include "Transaction.h" -#include "FdbError.h" - -#include -#include - -#define INVALID_OPTION_VALUE_ERROR_CODE (fdb_error_t)2006 - -using namespace v8; -using namespace node; - -std::map> FdbOptions::optionTemplates; -std::map FdbOptions::scopeInfo; -std::map> FdbOptions::parameterTypes; - -FdbOptions::FdbOptions() { } - -void FdbOptions::InitOptionsTemplate(Persistent &tpl, const char *className) { - tpl = Persistent::New(FunctionTemplate::New(New)); - tpl->SetClassName(String::NewSymbol(className)); - tpl->InstanceTemplate()->SetInternalFieldCount(1); -} - -void FdbOptions::AddOption(Scope scope, std::string name, int value, ParameterType type) { - if(scope == NetworkOption || scope == ClusterOption || scope == DatabaseOption || scope == TransactionOption || scope == MutationType) { - bool isSetter = scope != MutationType; - optionTemplates[scope]->PrototypeTemplate()->Set(v8::String::NewSymbol(ToJavaScriptName(name, isSetter).c_str()), - v8::FunctionTemplate::New(scopeInfo[scope].optionFunction, v8::Integer::New(value))->GetFunction()); - parameterTypes[scope][value] = type; - } - else if(scope == StreamingMode) { - optionTemplates[scope]->PrototypeTemplate()->Set(v8::String::NewSymbol(ToJavaScriptName(name, false).c_str()), v8::Integer::New(value)); - } - else if(scope == ConflictRangeType) { - //Conflict range type enum is not exposed to JS code - } -} - -Handle FdbOptions::New(const Arguments &args) { - FdbOptions *options = new FdbOptions(); - options->Wrap(args.Holder()); - - return args.Holder(); -} - -void FdbOptions::WeakCallback(Persistent value, void *data) { } - -Handle FdbOptions::NewInstance(Persistent optionsTemplate, Handle source) { - HandleScope scope; - - Local instance = optionsTemplate->GetFunction()->NewInstance(); - - FdbOptions *optionsObj = ObjectWrap::Unwrap(instance); - optionsObj->source = Persistent::New(source); - optionsObj->source.MakeWeak(optionsObj, WeakCallback); - - return scope.Close(instance); -} - -Handle FdbOptions::CreateOptions(Scope scope, Handle source) { - return NewInstance(optionTemplates[scope], source); -} - -Handle FdbOptions::CreateEnum(Scope scope) { - return optionTemplates[scope]->GetFunction()->NewInstance(); -} - -Parameter GetStringParameter(const Arguments &args, int index) { - if(args.Length() <= index || (!Buffer::HasInstance(args[index]) && !args[index]->IsString())) - return INVALID_OPTION_VALUE_ERROR_CODE; - else if(args[index]->IsString()) { - String::Utf8Value val(args[index]); - return std::string(*val, val.length()); - } - else - return std::string(Buffer::Data(args[index]->ToObject()), Buffer::Length(args[index]->ToObject())); -}; - -Parameter FdbOptions::GetOptionParameter(const Arguments &args, Scope scope, int optionValue, int index) { - if(args.Length() > index) { - int64_t val; - switch(parameterTypes[scope][optionValue]) { - case FdbOptions::String: - return GetStringParameter(args, index); - - case FdbOptions::Bytes: - if(!Buffer::HasInstance(args[index])) - return INVALID_OPTION_VALUE_ERROR_CODE; - - return std::string(Buffer::Data(args[index]->ToObject()), Buffer::Length(args[index]->ToObject())); - - case FdbOptions::Int: - if(!args[index]->IsNumber()) - return INVALID_OPTION_VALUE_ERROR_CODE; - val = args[index]->IntegerValue(); - return std::string((const char*)&val, 8); - - - case FdbOptions::None: - return Parameter(); - } - } - - return Parameter(); -} - -v8::Handle SetNetworkOption(const Arguments &args) { - FDBNetworkOption op = (FDBNetworkOption)args.Data()->Uint32Value(); - - Parameter param = FdbOptions::GetOptionParameter(args, FdbOptions::NetworkOption, op); - fdb_error_t errorCode = param.errorCode; - if(errorCode == 0) - errorCode = fdb_network_set_option(op, param.getValue(), param.getLength()); - - if(errorCode) - return ThrowException(FdbError::NewInstance(errorCode, fdb_get_error(errorCode))); - - return Null(); -} - -v8::Handle SetClusterOption(const Arguments &args) { - FdbOptions *options = ObjectWrap::Unwrap(args.Holder()); - Cluster *cluster = ObjectWrap::Unwrap(options->GetSource()->ToObject()); - FDBClusterOption op = (FDBClusterOption)args.Data()->Uint32Value(); - - Parameter param = FdbOptions::GetOptionParameter(args, FdbOptions::ClusterOption, op); - fdb_error_t errorCode = param.errorCode; - if(errorCode == 0) - errorCode = fdb_cluster_set_option(cluster->GetCluster(), op, param.getValue(), param.getLength()); - - if(errorCode) - return ThrowException(FdbError::NewInstance(errorCode, fdb_get_error(errorCode))); - - return Null(); -} - -v8::Handle SetDatabaseOption(const Arguments &args) { - FdbOptions *options = ObjectWrap::Unwrap(args.Holder()); - Database *db = ObjectWrap::Unwrap(options->GetSource()->ToObject()); - FDBDatabaseOption op = (FDBDatabaseOption)args.Data()->Uint32Value(); - - Parameter param = FdbOptions::GetOptionParameter(args, FdbOptions::DatabaseOption, op); - fdb_error_t errorCode = param.errorCode; - if(errorCode == 0) - errorCode = fdb_database_set_option(db->GetDatabase(), op, param.getValue(), param.getLength()); - - if(errorCode) - return ThrowException(FdbError::NewInstance(errorCode, fdb_get_error(errorCode))); - - return Null(); -} - -v8::Handle SetTransactionOption(const Arguments &args) { - FdbOptions *options = ObjectWrap::Unwrap(args.Holder()); - Transaction *tr = ObjectWrap::Unwrap(options->GetSource()->ToObject()); - FDBTransactionOption op = (FDBTransactionOption)args.Data()->Uint32Value(); - - Parameter param = FdbOptions::GetOptionParameter(args, FdbOptions::TransactionOption, op); - fdb_error_t errorCode = param.errorCode; - if(errorCode == 0) - errorCode = fdb_transaction_set_option(tr->GetTransaction(), op, param.getValue(), param.getLength()); - - if(errorCode) - return ThrowException(FdbError::NewInstance(errorCode, fdb_get_error(errorCode))); - - return Null(); -} - -v8::Handle CallAtomicOperation(const Arguments &args) { - Transaction *tr = ObjectWrap::Unwrap(args.Holder()); - Parameter key = GetStringParameter(args, 0); - Parameter value = GetStringParameter(args, 1); - - fdb_error_t errorCode = key.errorCode > 0 ? key.errorCode : value.errorCode; - if(errorCode > 0) - return ThrowException(FdbError::NewInstance(errorCode, fdb_get_error(errorCode))); - - fdb_transaction_atomic_op(tr->GetTransaction(), key.getValue(), key.getLength(), value.getValue(), value.getLength(), (FDBMutationType)args.Data()->Uint32Value()); - - return Null(); -} - -//Converts names using underscores as word separators to camel case (but preserves existing capitalization, if present). If isSetter, prepends the word 'set' to each name -std::string FdbOptions::ToJavaScriptName(std::string optionName, bool isSetter) { - if(isSetter) - optionName = "set_" + optionName; - - size_t start = 0; - while(start < optionName.size()) { - if(start != 0) - optionName[start] = ::toupper(optionName[start]); - size_t index = optionName.find_first_of('_', start); - if(index == std::string::npos) - break; - - optionName.erase(optionName.begin() + index); - - start = index; - } - - return optionName; -} - -void FdbOptions::Init() { - scopeInfo[NetworkOption] = ScopeInfo("FdbNetworkOptions", SetNetworkOption); - scopeInfo[ClusterOption] = ScopeInfo("FdbClusterOptions", SetClusterOption); - scopeInfo[DatabaseOption] = ScopeInfo("FdbDatabaseOptions", SetDatabaseOption); - scopeInfo[TransactionOption] = ScopeInfo("FdbTransactionOptions", SetTransactionOption); - scopeInfo[StreamingMode] = ScopeInfo("FdbStreamingMode", NULL); - scopeInfo[MutationType] = ScopeInfo("AtomicOperations", CallAtomicOperation); - //scopeInfo[ConflictRangeType] = ScopeInfo("ConflictRangeType", NULL); - - for(auto itr = scopeInfo.begin(); itr != scopeInfo.end(); ++itr) - InitOptionsTemplate(optionTemplates[itr->first], itr->second.templateClassName.c_str()); - - InitOptions(); -} diff --git a/bindings/nodejs/src/FdbOptions.h b/bindings/nodejs/src/FdbOptions.h deleted file mode 100644 index 4ed4dec3f5..0000000000 --- a/bindings/nodejs/src/FdbOptions.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * FdbOptions.h - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef FDB_NODE_FDB_OPTIONS_H -#define FDB_NODE_FDB_OPTIONS_H - -#define ADD_OPTION(scope, name, value, type) AddOption(scope, name, value, type) - -#include "Version.h" - -#include -#include -#include -#include - -struct Parameter { - Parameter() : isNull(true), errorCode(0) { } - Parameter(std::string param) : param(param), isNull(false), errorCode(0) { } - Parameter(fdb_error_t errorCode) : isNull(false), errorCode(errorCode) { } - - std::string param; - bool isNull; - fdb_error_t errorCode; - - uint8_t const* getValue() { return isNull ? NULL : (uint8_t const*)param.c_str(); } - int getLength() { return isNull ? 0 : (int)param.size(); } -}; - -struct ScopeInfo { - std::string templateClassName; - v8::Handle (*optionFunction) (const v8::Arguments &args); - - ScopeInfo() { } - ScopeInfo(std::string templateClassName, v8::Handle (*optionFunction) (const v8::Arguments &args)) { - this->templateClassName = templateClassName; - this->optionFunction = optionFunction; - } -}; - -class FdbOptions : node::ObjectWrap { - public: - static void Init(); - - enum ParameterType { - None, - Int, - String, - Bytes - }; - - enum Scope { - NetworkOption, - ClusterOption, - DatabaseOption, - TransactionOption, - StreamingMode, - MutationType, - ConflictRangeType - }; - - static v8::Handle CreateOptions(Scope scope, v8::Handle source = v8::Null()); - static v8::Handle CreateEnum(Scope scope); - - static Parameter GetOptionParameter(const v8::Arguments &args, Scope scope, int optionValue, int index = 0); - - v8::Persistent GetSource() { - return source; - } - - private: - static v8::Handle New(const v8::Arguments &args); - static v8::Handle NewInstance(v8::Persistent optionsTemplate, v8::Handle source); - - FdbOptions(); - - static void InitOptionsTemplate(v8::Persistent &tpl, const char *className); - static void InitOptions(); - - static void AddOption(Scope scope, std::string name, int value, ParameterType type); - static void WeakCallback(v8::Persistent value, void *data); - - static std::string ToJavaScriptName(std::string optionName, bool isSetter); - - static std::map scopeInfo; - static std::map> optionTemplates; - static std::map> parameterTypes; - - v8::Persistent source; -}; - -#endif diff --git a/bindings/nodejs/src/FdbUtil.cpp b/bindings/nodejs/src/FdbUtil.cpp deleted file mode 100644 index 8193f8f00f..0000000000 --- a/bindings/nodejs/src/FdbUtil.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * FdbUtil.cpp - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include -#include "FdbUtil.h" - -using namespace v8; - -Handle ToFloat(const Arguments &args) { - HandleScope scope; - - if (args.Length() != 1) { - return ThrowException(Exception::TypeError(String::NewSymbol("Wrong number of arguments (must be exactly 1)"))); - } - - if (!args[0]->IsNumber()) { - return ThrowException(Exception::TypeError(String::NewSymbol("Argument is not a Number"))); - } - - float value = (float)args[0]->NumberValue(); - Handle jsValue = Number::New(value); - - return scope.Close(jsValue); -} diff --git a/bindings/nodejs/src/FdbUtil.h b/bindings/nodejs/src/FdbUtil.h deleted file mode 100644 index 4df8dda894..0000000000 --- a/bindings/nodejs/src/FdbUtil.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * FdbUtil.h - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef FDB_NODE_FDB_UTIL_H -#define FDB_NODE_FDB_UTIL_H - -#include - -v8::Handle ToFloat(const v8::Arguments &args); - -#endif diff --git a/bindings/nodejs/src/FdbV8Wrapper.cpp b/bindings/nodejs/src/FdbV8Wrapper.cpp deleted file mode 100644 index c7593b3da1..0000000000 --- a/bindings/nodejs/src/FdbV8Wrapper.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - * FdbV8Wrapper.cpp - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include -#include "node.h" -#include -#include -#include -#include -#include - -#include "Database.h" -#include "NodeCallback.h" -#include "Cluster.h" -#include "Version.h" -#include "FdbError.h" -#include "FdbOptions.h" -#include "FdbUtil.h" - -uv_thread_t fdbThread; - -using namespace v8; -using namespace std; - -bool networkStarted = false; - -Handle ApiVersion(const Arguments &args) { - int apiVersion = args[0]->Int32Value(); - fdb_error_t errorCode = fdb_select_api_version(apiVersion); - - if(errorCode != 0) { - if(errorCode == 2203) { - int maxSupportedVersion = fdb_get_max_api_version(); - - ostringstream errorStr; - if(FDB_API_VERSION > maxSupportedVersion) { - errorStr << "This version of the FoundationDB Node.js binding is not supported by the installed FoundationDB " - << "C library. The binding requires a library that supports API version " << FDB_API_VERSION - << ", but the installed library supports a maximum version of " << maxSupportedVersion << "."; - } - else { - errorStr << "API version " << apiVersion << " is not supported by the installed FoundationDB C library."; - } - - return ThrowException(FdbError::NewInstance(errorCode, errorStr.str().c_str())); - } - - return ThrowException(FdbError::NewInstance(errorCode, fdb_get_error(errorCode))); - } - - return Null(); -} - -static void networkThread(void *arg) { - fdb_error_t errorCode = fdb_run_network(); - if(errorCode != 0) - fprintf(stderr, "Unhandled error in FoundationDB network thread: %s (%d)\n", fdb_get_error(errorCode), errorCode); -} - -static Handle runNetwork() { - fdb_error_t errorCode = fdb_setup_network(); - - if(errorCode != 0) - return ThrowException(FdbError::NewInstance(errorCode, fdb_get_error(errorCode))); - - uv_thread_create(&fdbThread, networkThread, NULL); // FIXME: Return code? - - return Null(); -} - -Handle CreateCluster(const Arguments &args) { - HandleScope scope; - - FDBFuture *f = fdb_create_cluster(*String::AsciiValue(args[0]->ToString())); - fdb_error_t errorCode = fdb_future_block_until_ready(f); - - FDBCluster *cluster; - if(errorCode == 0) - errorCode = fdb_future_get_cluster(f, &cluster); - - if(errorCode != 0) - return ThrowException(FdbError::NewInstance(errorCode, fdb_get_error(errorCode))); - - Handle jsValue = Local::New(Cluster::NewInstance(cluster)); - return scope.Close(jsValue); -} - -Handle StartNetwork(const Arguments &args) { - if(!networkStarted) { - networkStarted = true; - return runNetwork(); - } - - return Null(); -} - -Handle StopNetwork(const Arguments &args) { - fdb_error_t errorCode = fdb_stop_network(); - - if(errorCode != 0) - return ThrowException(FdbError::NewInstance(errorCode, fdb_get_error(errorCode))); - - uv_thread_join(&fdbThread); - - //This line forces garbage collection. Useful for doing valgrind tests - //while(!V8::IdleNotification()); - - return Null(); -} - -void init(Handle target){ - FdbError::Init( target ); - Database::Init(); - Transaction::Init(); - Cluster::Init(); - FdbOptions::Init(); - Watch::Init(); - - target->Set(String::NewSymbol("apiVersion"), FunctionTemplate::New(ApiVersion)->GetFunction()); - target->Set(String::NewSymbol("createCluster"), FunctionTemplate::New(CreateCluster)->GetFunction()); - target->Set(String::NewSymbol("startNetwork"), FunctionTemplate::New(StartNetwork)->GetFunction()); - target->Set(String::NewSymbol("stopNetwork"), FunctionTemplate::New(StopNetwork)->GetFunction()); - target->Set(String::NewSymbol("options"), FdbOptions::CreateOptions(FdbOptions::NetworkOption)); - target->Set(String::NewSymbol("streamingMode"), FdbOptions::CreateEnum(FdbOptions::StreamingMode)); - target->Set(String::NewSymbol("atomic"), FdbOptions::CreateOptions(FdbOptions::MutationType)); - target->Set(String::NewSymbol("toFloat"), FunctionTemplate::New(ToFloat)->GetFunction()); -} - -#if NODE_VERSION_AT_LEAST(0, 8, 0) -NODE_MODULE(fdblib, init); -#else -#error "Node.js versions before v0.8.0 are not supported" -#endif diff --git a/bindings/nodejs/src/NodeCallback.h b/bindings/nodejs/src/NodeCallback.h deleted file mode 100644 index 493835e712..0000000000 --- a/bindings/nodejs/src/NodeCallback.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * NodeCallback.h - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef FDB_NODE_NODE_CALLBACK_H -#define FDB_NODE_NODE_CALLBACK_H - -#include "FdbError.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#if NODE_VERSION_AT_LEAST(0, 7, 9) -#else -#error Node version too old -#endif - -using namespace std; -using namespace v8; -using namespace node; - -struct NodeCallback { - -public: - NodeCallback(FDBFuture *future, Persistent cbFunc) : future(future), cbFunc(cbFunc), refCount(1) { - uv_async_init(uv_default_loop(), &handle, &NodeCallback::nodeThreadCallback); - uv_ref((uv_handle_t*)&handle); - handle.data = this; - } - - void start() { - if (fdb_future_set_callback(future, &NodeCallback::futureReadyCallback, this)) { - fprintf(stderr, "fdb_future_set_callback failed.\n"); - abort(); - } - } - - virtual ~NodeCallback() { - cbFunc.Dispose(); - fdb_future_destroy(future); - } - - void addRef() { - ++refCount; - } - - void delRef() { - if(--refCount == 0) { - delete this; - } - } - - FDBFuture* getFuture() { - return future; - } - -private: - void close() { - uv_close((uv_handle_t*)&handle, &NodeCallback::closeCallback); - } - - static void closeCallback(uv_handle_s *handle) { - NodeCallback *nc = (NodeCallback*)((uv_async_t*)handle)->data; - nc->delRef(); - } - - static void futureReadyCallback(FDBFuture *f, void *ptr) { - NodeCallback *nc = (NodeCallback*)ptr; - uv_async_send(&nc->handle); - } - - static void nodeThreadCallback(uv_async_t *handle, int status) { - HandleScope scope; - - NodeCallback *nc = (NodeCallback*)handle->data; - FDBFuture *future = nc->future; - - uv_unref((uv_handle_t*)handle); - - Handle jsError; - Handle jsValue; - - fdb_error_t errorCode; - jsValue = nc->extractValue(future, errorCode); - if (errorCode == 0) - jsError = Null(); - else - jsError = FdbError::NewInstance(errorCode, fdb_get_error(errorCode)); - - Handle args[2] = { jsError, jsValue }; - - v8::TryCatch ex; - nc->cbFunc->Call(Context::GetCurrent()->Global(), 2, args); - - if(ex.HasCaught()) - fprintf(stderr, "\n%s\n", *String::AsciiValue(ex.StackTrace()->ToString())); - - nc->close(); - } - - FDBFuture* future; - uv_async_t handle; - Persistent cbFunc; - int refCount; - -protected: - virtual Handle extractValue(FDBFuture* future, fdb_error_t& outErr) = 0; - - static Handle makeBuffer(const char *arr, int length) { - HandleScope scope; - - Buffer *buf = Buffer::New(length); - Local slowBufferHandle = Local::New( buf->handle_ ); // Else the buffer, which has only a weak handle to itself, could be freed by GC in one of the below calls... - memcpy(Buffer::Data(buf), (const char*)arr, length); - - Local globalObj = Context::GetCurrent()->Global(); - Local bufferConstructor = Local::Cast(globalObj->Get(String::NewSymbol("Buffer"))); - - Handle constructorArgs[3] = { slowBufferHandle, Integer::New(length), Integer::New(0) }; - Handle actualBuffer = bufferConstructor->NewInstance(3, constructorArgs); - - return scope.Close(actualBuffer); - } -}; - -#endif diff --git a/bindings/nodejs/src/Transaction.cpp b/bindings/nodejs/src/Transaction.cpp deleted file mode 100644 index 54d75f8142..0000000000 --- a/bindings/nodejs/src/Transaction.cpp +++ /dev/null @@ -1,485 +0,0 @@ -/* - * Transaction.cpp - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include "Transaction.h" -#include "NodeCallback.h" -#include "FdbError.h" -#include "FdbOptions.h" - -using namespace v8; -using namespace std; -using namespace node; - -// Transaction Implementation -Transaction::Transaction() { }; - -Transaction::~Transaction() { - fdb_transaction_destroy(tr); -}; - -Persistent Transaction::constructor; - -struct NodeValueCallback : NodeCallback { - - NodeValueCallback(FDBFuture *future, Persistent cbFunc) : NodeCallback(future, cbFunc) { } - - virtual Handle extractValue(FDBFuture* future, fdb_error_t& outErr) { - HandleScope scope; - - const char *value; - int valueLength; - int valuePresent; - - outErr = fdb_future_get_value(future, &valuePresent, (const uint8_t**)&value, &valueLength); - if (outErr) return scope.Close(Undefined()); - - Handle jsValue; - - if(!valuePresent) - jsValue = Null(); - else - jsValue = makeBuffer(value, valueLength); - - return scope.Close(jsValue); - } -}; - -struct NodeKeyCallback : NodeCallback { - - NodeKeyCallback(FDBFuture *future, Persistent cbFunc) : NodeCallback(future, cbFunc) { } - - virtual Handle extractValue(FDBFuture* future, fdb_error_t& outErr) { - HandleScope scope; - - const char *key; - int keyLength; - - outErr = fdb_future_get_key(future, (const uint8_t**)&key, &keyLength); - if (outErr) return scope.Close(Undefined()); - - Handle jsValue = makeBuffer(key, keyLength); - - return scope.Close(jsValue); - } -}; - -struct NodeVoidCallback : NodeCallback { - - NodeVoidCallback(FDBFuture *future, Persistent cbFunc) : NodeCallback(future, cbFunc) { } - - virtual Handle extractValue(FDBFuture* future, fdb_error_t& outErr) { - outErr = fdb_future_get_error(future); - return Undefined(); - } -}; - -struct NodeKeyValueCallback : NodeCallback { - - NodeKeyValueCallback(FDBFuture *future, Persistent cbFunc) : NodeCallback(future, cbFunc) { } - - virtual Handle extractValue(FDBFuture* future, fdb_error_t& outErr) { - HandleScope scope; - - const FDBKeyValue *kv; - int len; - fdb_bool_t more; - - outErr = fdb_future_get_keyvalue_array(future, &kv, &len, &more); - if (outErr) return scope.Close(Undefined()); - - /* - * Constructing a JavaScript array of KeyValue objects: - * { - * key: "some key", - * value: "some value" - * } - * - */ - - Handle returnObj = Object::New(); - Handle jsValueArray = Array::New(len); - - Handle keySymbol = String::NewSymbol("key"); - Handle valueSymbol = String::NewSymbol("value"); - - for(int i = 0; i < len; i++) { - Local jsKeyValue = Object::New(); - - Handle jsKeyBuffer = makeBuffer((const char*)kv[i].key, kv[i].key_length); - Handle jsValueBuffer = makeBuffer((const char*)kv[i].value, kv[i].value_length); - - jsKeyValue->Set(keySymbol, jsKeyBuffer); - jsKeyValue->Set(valueSymbol, jsValueBuffer); - jsValueArray->Set(Number::New(i), jsKeyValue); - } - - returnObj->Set(String::NewSymbol("array"), jsValueArray); - if(more) - returnObj->Set(String::NewSymbol("more"), Number::New(1)); - - return scope.Close(returnObj); - } -}; - -struct NodeVersionCallback : NodeCallback { - - NodeVersionCallback(FDBFuture *future, Persistent cbFunc) : NodeCallback(future, cbFunc) { } - - virtual Handle extractValue(FDBFuture* future, fdb_error_t& outErr) { - HandleScope scope; - - int64_t version; - - outErr = fdb_future_get_version(future, &version); - if (outErr) return scope.Close(Undefined()); - - //SOMEDAY: This limits the version to 53-bits. Do something different here? - Handle jsValue = Number::New((double)version); - - return scope.Close(jsValue); - } -}; - -struct NodeStringArrayCallback : NodeCallback { - - NodeStringArrayCallback(FDBFuture *future, Persistent cbFunc) : NodeCallback(future, cbFunc) { } - - virtual Handle extractValue(FDBFuture *future, fdb_error_t& outErr) { - HandleScope scope; - - const char **strings; - int stringCount; - - outErr = fdb_future_get_string_array(future, &strings, &stringCount); - if (outErr) return scope.Close(Undefined()); - - Handle jsArray = Array::New(stringCount); - for(int i = 0; i < stringCount; i++) - jsArray->Set(Number::New(i), makeBuffer(strings[i], (int)strlen(strings[i]))); - - return scope.Close(jsArray); - } -}; - -struct StringParams { - uint8_t *str; - int len; - - /* - * String arguments always have to be buffers to - * preserve bytes. Otherwise, stuff gets converted - * to UTF-8. - */ - StringParams(Handle keyVal) { - str = (uint8_t*)(Buffer::Data(keyVal->ToObject())); - len = (int)Buffer::Length(keyVal->ToObject()); - } -}; - -FDBTransaction* Transaction::GetTransactionFromArgs(const Arguments &args) { - return node::ObjectWrap::Unwrap(args.Holder())->tr; -} - -Persistent Transaction::GetCallback(Handle funcVal) { - return Persistent::New(Handle(Function::Cast(*funcVal))); -} - -Handle Transaction::Set(const Arguments &args){ - StringParams key(args[0]); - StringParams val(args[1]); - fdb_transaction_set(GetTransactionFromArgs(args), key.str, key.len, val.str, val.len); - - return Null(); -} - -Handle Transaction::Commit(const Arguments &args) { - FDBFuture *f = fdb_transaction_commit(GetTransactionFromArgs(args)); - (new NodeVoidCallback(f, GetCallback(args[0])))->start(); - return Null(); -} - -Handle Transaction::Clear(const Arguments &args) { - StringParams key(args[0]); - fdb_transaction_clear(GetTransactionFromArgs(args), key.str, key.len); - - return Null(); -} - -/* - * ClearRange takes two key strings. - */ -Handle Transaction::ClearRange(const Arguments &args) { - StringParams begin(args[0]); - StringParams end(args[1]); - fdb_transaction_clear_range(GetTransactionFromArgs(args), begin.str, begin.len, end.str, end.len); - - return Null(); -} - -/* - * This function takes a KeySelector and returns a future. - */ -Handle Transaction::GetKey(const Arguments &args) { - StringParams key(args[0]); - int selectorOrEqual = args[1]->Int32Value(); - int selectorOffset = args[2]->Int32Value(); - bool snapshot = args[3]->BooleanValue(); - - FDBFuture *f = fdb_transaction_get_key(GetTransactionFromArgs(args), key.str, key.len, (fdb_bool_t)selectorOrEqual, selectorOffset, snapshot); - (new NodeKeyCallback(f, GetCallback(args[4])))->start(); - return Null(); -} - -Handle Transaction::Get(const Arguments &args) { - StringParams key(args[0]); - bool snapshot = args[1]->BooleanValue(); - - FDBFuture *f = fdb_transaction_get(GetTransactionFromArgs(args), key.str, key.len, snapshot); - (new NodeValueCallback(f, GetCallback(args[2])))->start(); - return Null(); -} - -Handle Transaction::GetRange(const Arguments &args) { - StringParams start(args[0]); - int startOrEqual = args[1]->Int32Value(); - int startOffset = args[2]->Int32Value(); - - StringParams end(args[3]); - int endOrEqual = args[4]->Int32Value(); - int endOffset = args[5]->Int32Value(); - - int limit = args[6]->Int32Value(); - FDBStreamingMode mode = (FDBStreamingMode)args[7]->Int32Value(); - int iteration = args[8]->Int32Value(); - bool snapshot = args[9]->BooleanValue(); - bool reverse = args[10]->BooleanValue(); - - FDBFuture *f = fdb_transaction_get_range(GetTransactionFromArgs(args), start.str, start.len, (fdb_bool_t)startOrEqual, startOffset, - end.str, end.len, (fdb_bool_t)endOrEqual, endOffset, limit, 0, mode, iteration, snapshot, reverse); - - (new NodeKeyValueCallback(f, GetCallback(args[11])))->start(); - return Null(); -} - -Handle Transaction::Watch(const Arguments &args) { - HandleScope scope; - - Transaction *trPtr = node::ObjectWrap::Unwrap(args.Holder()); - - uint8_t *keyStr = (uint8_t*)(Buffer::Data(args[0]->ToObject())); - int keyLen = (int)Buffer::Length(args[0]->ToObject()); - - Persistent cb = Persistent::New(Handle(Function::Cast(*args[1]))); - - FDBFuture *f = fdb_transaction_watch(trPtr->tr, keyStr, keyLen); - NodeVoidCallback *callback = new NodeVoidCallback(f, cb); - Handle watch = Watch::NewInstance(callback); - - callback->start(); - return scope.Close(watch); -} - -Handle Transaction::AddConflictRange(const Arguments &args, FDBConflictRangeType type) { - StringParams start(args[0]); - StringParams end(args[1]); - - fdb_error_t errorCode = fdb_transaction_add_conflict_range(GetTransactionFromArgs(args), start.str, start.len, end.str, end.len, type); - - if(errorCode != 0) { - ThrowException(FdbError::NewInstance(errorCode, fdb_get_error(errorCode))); - return Undefined(); - } - - return Null(); -} - -Handle Transaction::AddReadConflictRange(const Arguments &args) { - return AddConflictRange(args, FDB_CONFLICT_RANGE_TYPE_READ); -} - -Handle Transaction::AddWriteConflictRange(const Arguments &args) { - return AddConflictRange(args, FDB_CONFLICT_RANGE_TYPE_WRITE); -} - -Handle Transaction::OnError(const Arguments &args) { - fdb_error_t errorCode = args[0]->Int32Value(); - FDBFuture *f = fdb_transaction_on_error(GetTransactionFromArgs(args), errorCode); - (new NodeVoidCallback(f, GetCallback(args[1])))->start(); - return Null(); -} - -Handle Transaction::Reset(const Arguments &args) { - fdb_transaction_reset(GetTransactionFromArgs(args)); - return Null(); -} - -Handle Transaction::SetReadVersion(const Arguments &args) { - int64_t version = args[0]->IntegerValue(); - fdb_transaction_set_read_version(GetTransactionFromArgs(args), version); - return Null(); -} - -Handle Transaction::GetReadVersion(const Arguments &args) { - FDBFuture *f = fdb_transaction_get_read_version(GetTransactionFromArgs(args)); - (new NodeVersionCallback(f, GetCallback(args[0])))->start(); - return Null(); -} - -Handle Transaction::GetCommittedVersion(const Arguments &args) { - HandleScope scope; - - int64_t version; - fdb_error_t errorCode = fdb_transaction_get_committed_version(GetTransactionFromArgs(args), &version); - - if(errorCode != 0) { - ThrowException(FdbError::NewInstance(errorCode, fdb_get_error(errorCode))); - return scope.Close(Undefined()); - } - - return scope.Close(Number::New((double)version)); -} - -Handle Transaction::GetVersionstamp(const Arguments &args) { - FDBFuture *f = fdb_transaction_get_versionstamp(GetTransactionFromArgs(args)); - (new NodeKeyCallback(f, GetCallback(args[0])))->start(); - return Null(); -} - -Handle Transaction::Cancel(const Arguments &args) { - fdb_transaction_cancel(GetTransactionFromArgs(args)); - return Null(); -} - -Handle Transaction::GetAddressesForKey(const Arguments &args) { - StringParams key(args[0]); - - FDBFuture *f = fdb_transaction_get_addresses_for_key(GetTransactionFromArgs(args), key.str, key.len); - (new NodeStringArrayCallback(f, GetCallback(args[1])))->start(); - return Null(); -} - -Handle Transaction::New(const Arguments &args) { - Transaction *tr = new Transaction(); - tr->Wrap(args.Holder()); - - return args.Holder(); -} - -Handle Transaction::NewInstance(FDBTransaction *ptr) { - HandleScope scope; - - Local instance = constructor->NewInstance(); - - Transaction *trObj = ObjectWrap::Unwrap(instance); - trObj->tr = ptr; - - instance->Set(String::NewSymbol("options"), FdbOptions::CreateOptions(FdbOptions::TransactionOption, instance)); - - return scope.Close(instance); -} - -void Transaction::Init() { - Local tpl = FunctionTemplate::New(New); - - tpl->SetClassName(String::NewSymbol("Transaction")); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - - tpl->PrototypeTemplate()->Set(String::NewSymbol("get"), FunctionTemplate::New(Get)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("getRange"), FunctionTemplate::New(GetRange)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("getKey"), FunctionTemplate::New(GetKey)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("watch"), FunctionTemplate::New(Watch)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("set"), FunctionTemplate::New(Set)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("commit"), FunctionTemplate::New(Commit)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("clear"), FunctionTemplate::New(Clear)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("clearRange"), FunctionTemplate::New(ClearRange)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("addReadConflictRange"), FunctionTemplate::New(AddReadConflictRange)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("addWriteConflictRange"), FunctionTemplate::New(AddWriteConflictRange)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("onError"), FunctionTemplate::New(OnError)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("reset"), FunctionTemplate::New(Reset)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("getReadVersion"), FunctionTemplate::New(GetReadVersion)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("setReadVersion"), FunctionTemplate::New(SetReadVersion)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("getCommittedVersion"), FunctionTemplate::New(GetCommittedVersion)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("getVersionstamp"), FunctionTemplate::New(GetVersionstamp)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("cancel"), FunctionTemplate::New(Cancel)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("getAddressesForKey"), FunctionTemplate::New(GetAddressesForKey)->GetFunction()); - - constructor = Persistent::New(tpl->GetFunction()); -} - -// Watch implementation -Watch::Watch() : callback(NULL) { }; - -Watch::~Watch() { - if(callback) { - if(callback->getFuture()) - fdb_future_cancel(callback->getFuture()); - - callback->delRef(); - } -}; - -Persistent Watch::constructor; - -Handle Watch::NewInstance(NodeCallback *callback) { - HandleScope scope; - - Local instance = constructor->NewInstance(); - - Watch *watchObj = ObjectWrap::Unwrap(instance); - watchObj->callback = callback; - callback->addRef(); - - return scope.Close(instance); -} - -Handle Watch::New(const Arguments &args) { - Watch *c = new Watch(); - c->Wrap(args.Holder()); - - return args.Holder(); -} - -Handle Watch::Cancel(const Arguments &args) { - NodeCallback *callback = node::ObjectWrap::Unwrap(args.Holder())->callback; - - if(callback && callback->getFuture()) - fdb_future_cancel(callback->getFuture()); - - return Null(); -} - -void Watch::Init() { - Local tpl = FunctionTemplate::New(New); - tpl->SetClassName(String::NewSymbol("Watch")); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - - tpl->PrototypeTemplate()->Set(String::NewSymbol("cancel"), FunctionTemplate::New(Cancel)->GetFunction()); - - constructor = Persistent::New(tpl->GetFunction()); -} diff --git a/bindings/nodejs/src/Transaction.h b/bindings/nodejs/src/Transaction.h deleted file mode 100644 index 43762ec1d4..0000000000 --- a/bindings/nodejs/src/Transaction.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Transaction.h - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef FDB_NODE_TRANSACTION_H -#define FDB_NODE_TRANSACTION_H - -#include "Version.h" - -#include -#include - -#include "NodeCallback.h" - -class Transaction: public node::ObjectWrap { - public: - static void Init(); - static v8::Handle NewInstance(FDBTransaction *ptr); - static v8::Handle New(const v8::Arguments &args); - - static v8::Handle Get(const v8::Arguments &args); - static v8::Handle GetKey(const v8::Arguments &args); - static v8::Handle Set(const v8::Arguments &args); - static v8::Handle Commit(const v8::Arguments &args); - static v8::Handle Clear(const v8::Arguments &args); - static v8::Handle ClearRange(const v8::Arguments &args); - static v8::Handle GetRange(const v8::Arguments &args); - static v8::Handle Watch(const v8::Arguments &args); - - static v8::Handle AddConflictRange(const v8::Arguments &args, FDBConflictRangeType type); - static v8::Handle AddReadConflictRange(const v8::Arguments &args); - static v8::Handle AddWriteConflictRange(const v8::Arguments &args); - - static v8::Handle OnError(const v8::Arguments &args); - static v8::Handle Reset(const v8::Arguments &args); - - static v8::Handle SetReadVersion(const v8::Arguments &args); - static v8::Handle GetReadVersion(const v8::Arguments &args); - static v8::Handle GetCommittedVersion(const v8::Arguments &args); - static v8::Handle GetVersionstamp(const v8::Arguments &args); - - static v8::Handle Cancel(const v8::Arguments &args); - - static v8::Handle GetAddressesForKey(const v8::Arguments &args); - - FDBTransaction* GetTransaction() { return tr; } - private: - Transaction(); - ~Transaction(); - - static v8::Persistent constructor; - FDBTransaction *tr; - - static FDBTransaction* GetTransactionFromArgs(const v8::Arguments &args); - static v8::Persistent GetCallback(const v8::Handle funcVal); -}; - -class Watch : public node::ObjectWrap { - public: - static void Init(); - - static v8::Handle NewInstance(NodeCallback *callback); - static v8::Handle New(const v8::Arguments &args); - - static v8::Handle Cancel(const v8::Arguments &args); - - private: - Watch(); - ~Watch(); - - static v8::Persistent constructor; - NodeCallback *callback; -}; - -#endif diff --git a/bindings/nodejs/src/Version.h b/bindings/nodejs/src/Version.h deleted file mode 100644 index adcc23662f..0000000000 --- a/bindings/nodejs/src/Version.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Version.h - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef FDB_NODE_VERSION_H -#define FDB_NODE_VERSION_H - -#define FDB_API_VERSION 510 - -#endif diff --git a/bindings/nodejs/tests/async_test.js b/bindings/nodejs/tests/async_test.js deleted file mode 100755 index 11356b5ccc..0000000000 --- a/bindings/nodejs/tests/async_test.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * async_test.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var fdb = require('../lib/fdb').apiVersion(200); - -fdb.open(null, null, function(dbErr, dbVal) { - fdb.open(null, null, function(dbErr, dbVal) { - if(dbVal == null) - console.log("database is null"); - console.log("created database", dbErr); - console.log(JSON.stringify(dbVal)); - var tr = dbVal.createTransaction(); - console.log("created transaction"); - - tr.get('foo', function(err, val) { - console.log("get called", val, err); - tr.set('foo', 'bar'); - tr.commit(function(err) { - console.log("commit called", err); - var x = tr.get('foo'); - x(function(err, val) { - console.log("get called", val.toString(), err); - tr.clear('foo') - tr.commit(function(err) { - console.log("commit called", err); - tr.get('foo', function(err, val) { - console.log("get called", val, err); - }); - }); - }); - }); - }); - }); -}); diff --git a/bindings/nodejs/tests/directory_extension.js b/bindings/nodejs/tests/directory_extension.js deleted file mode 100644 index 2c81eb4dad..0000000000 --- a/bindings/nodejs/tests/directory_extension.js +++ /dev/null @@ -1,304 +0,0 @@ -/* - * directory_extension.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -"use strict"; - -var util = require('util'); -var fdb = require('../lib/fdb.js').apiVersion(parseInt(process.argv[3])); -var fdbUtil = require('../lib/fdbUtil.js'); -var dirUtil = require('./directory_util.js'); - -var logAll = false; - -var logInstructions = false; -var logOps = false; -var logDirs = false; -var logErrors = false; - -var logOp = function(message, force) { - if(logOps || logAll || force) - console.log(message); -}; - -var DirectoryExtension = function() { - this.dirList = [fdb.directory]; - this.dirIndex = 0; - this.errorIndex = 0; -}; - -DirectoryExtension.prototype.processInstruction = function(inst, cb) { - var self = this; - var directory = this.dirList[this.dirIndex]; - - var promiseCb = function(err) { - if(err && (logErrors || logAll)) { - console.log(err); - //console.log(err.stack); - } - - dirUtil.pushError(self, inst, err); - cb(); - }; - - var appendDir = function(dir) { - if(logDirs || logAll) - console.log(util.format('pushed at %d (op=%s)', self.dirList.length, inst.op)); - - self.dirList.push(dir); - }; - - if(logAll || logInstructions) - console.log(inst.context.instructionIndex, inst.tokens[0].toString()); - - if(inst.op === 'DIRECTORY_CREATE_SUBSPACE') { - dirUtil.popTuples(inst) - .then(function(path) { - return inst.pop() - .then(function(rawPrefix) { - logOp(util.format('created subspace at (%s): %s', path, fdb.buffer.printable(rawPrefix))); - appendDir(new fdb.Subspace(path, rawPrefix)); - }); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_CREATE_LAYER') { - inst.pop({count: 3}) - .then(function(params) { - var index1 = params[0]; - var index2 = params[1]; - var allowManualPrefixes = params[2]; - - var dir1 = self.dirList[params[0]]; - var dir2 = self.dirList[params[1]]; - if(dir1 === null || dir2 === null) { - logOp('create directory layer: None'); - appendDir(null); - } - else { - logOp(util.format('create directory layer: node_subspace (%d) = %s, content_subspace (%d) = %s, allow_manual_prefixes = %d', index1, fdb.buffer.printable(dir1.rawPrefix), index2, fdb.buffer.printable(dir2.rawPrefix), allowManualPrefixes)); - appendDir(new fdb.DirectoryLayer({ nodeSubspace: dir1, - contentSubspace: dir2, - allowManualPrefixes: allowManualPrefixes === 1 })); - } - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_CHANGE') { - inst.pop() - .then(function(index) { - if(self.dirList[index] === null) - self.dirIndex = self.errorIndex; - else - self.dirIndex = index; - - if(logDirs || logAll) { - var dir = self.dirList[self.dirIndex]; - console.log(util.format('changed directory to %d ((%s))', self.dirIndex, dir._path)); - } - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_SET_ERROR_INDEX') { - inst.pop() - .then(function(errorIndex) { - self.errorIndex = errorIndex; - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_CREATE_OR_OPEN') { - dirUtil.popTuples(inst) - .then(function(path) { - return inst.pop() - .then(function(layer) { - logOp(util.format('create_or_open (%s): layer=%s', directory._path + path, fdb.buffer.printable(layer) || '')); - return directory.createOrOpen(inst.tr, path, {'layer': layer || undefined}); - }) - .then(function(dir) { - appendDir(dir); - }); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_CREATE') { - dirUtil.popTuples(inst) - .then(function(path) { - return inst.pop({count: 2}) - .then(function(params) { - logOp(util.format('create (%s): layer=%s, prefix=%s', directory._path + path, fdb.buffer.printable(params[0]) || '', fdb.buffer.printable(params[1] || ''))); - return directory.create(inst.tr, path, {'layer': params[0] || undefined, 'prefix': params[1] || undefined}); - }) - .then(function(dir) { - appendDir(dir); - }); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_OPEN') { - dirUtil.popTuples(inst) - .then(function(path) { - return inst.pop() - .then(function(layer) { - logOp(util.format('open (%s): layer=%s', directory._path + path, fdb.buffer.printable(layer) || '')); - return directory.open(inst.tr, path, {'layer': layer}); - }) - .then(function(dir) { - appendDir(dir); - }); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_MOVE') { - dirUtil.popTuples(inst, 2) - .then(function(paths) { - logOp(util.format('move (%s) to (%s)', directory._path + paths[0], directory._path + paths[1])); - return directory.move(inst.tr, paths[0], paths[1]) - .then(function(dir) { - appendDir(dir); - }); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_MOVE_TO') { - dirUtil.popTuples(inst) - .then(function(newAbsolutePath) { - logOp(util.format('move (%s) to (%s)', directory._path, newAbsolutePath)); - return directory.moveTo(inst.tr, newAbsolutePath) - .then(function(dir) { - appendDir(dir); - }); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_REMOVE') { - inst.pop() - .then(function(count) { - return dirUtil.popTuples(inst, count) - .then(function(path) { - logOp(util.format('remove (%s)', directory._path + (path ? path : ''))); - return directory.remove(inst.tr, path); - }); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_REMOVE_IF_EXISTS') { - inst.pop() - .then(function(count) { - return dirUtil.popTuples(inst, count) - .then(function(path) { - logOp(util.format('remove_if_exists (%s)', directory._path + (path ? path : ''))); - return directory.removeIfExists(inst.tr, path); - }); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_LIST') { - inst.pop() - .then(function(count) { - return dirUtil.popTuples(inst, count) - .then(function(path) { - return directory.list(inst.tr, path); - }) - .then(function(children) { - inst.push(fdb.tuple.pack(children)); - }); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_EXISTS') { - var path; - inst.pop() - .then(function(count) { - return dirUtil.popTuples(inst, count) - .then(function(p) { - path = p; - return directory.exists(inst.tr, path); - }) - .then(function(exists) { - logOp(util.format('exists (%s): %d', directory._path + (path ? path : ''), exists ? 1 : 0)); - inst.push(exists ? 1 : 0); - }); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_PACK_KEY') { - dirUtil.popTuples(inst) - .then(function(keyTuple) { - inst.push(directory.pack(keyTuple)); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_UNPACK_KEY') { - inst.pop() - .then(function(key) { - logOp(util.format('unpack %s in subspace with prefix %s', fdb.buffer.printable(key), fdb.buffer.printable(directory.rawPrefix))); - var tup = directory.unpack(key); - for(var i = 0; i < tup.length; ++i) - inst.push(tup[i]); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_RANGE') { - dirUtil.popTuples(inst) - .then(function(tup) { - var rng = directory.range(tup); - inst.push(rng.begin); - inst.push(rng.end); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_CONTAINS') { - inst.pop() - .then(function(key) { - inst.push(directory.contains(key) ? 1 : 0); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_OPEN_SUBSPACE') { - dirUtil.popTuples(inst) - .then(function(path) { - logOp(util.format('open_subspace (%s)', path)); - appendDir(directory.subspace(path)); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_LOG_SUBSPACE') { - inst.pop() - .then(function(prefix) { - inst.tr.set(Buffer.concat([prefix, fdb.tuple.pack([self.dirIndex])]), directory.key()); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_LOG_DIRECTORY') { - inst.pop() - .then(function(prefix) { - var exists; - return directory.exists(inst.tr) - .then(function(e) { - exists = e; - if(exists) - return directory.list(inst.tr); - else - return []; - }) - .then(function(children) { - var logSubspace = new fdb.Subspace([self.dirIndex], prefix); - inst.tr.set(logSubspace.get('path'), fdb.tuple.pack(directory.getPath())); - inst.tr.set(logSubspace.get('layer'), fdb.tuple.pack([directory.getLayer()])); - inst.tr.set(logSubspace.get('exists'), fdb.tuple.pack([exists ? 1 : 0])); - inst.tr.set(logSubspace.get('children'), fdb.tuple.pack(children)); - }); - })(promiseCb); - } - else if(inst.op === 'DIRECTORY_STRIP_PREFIX') { - inst.pop() - .then(function(str) { - if(!fdbUtil.buffersEqual(fdb.buffer(str).slice(0, directory.key().length), directory.key())) - throw new Error('String ' + str + ' does not start with raw prefix ' + directory.key()); - - inst.push(str.slice(directory.key().length)); - })(promiseCb); - } - else { - throw new Error('Unknown op: ' + inst.op); - } -}; - -module.exports = DirectoryExtension; diff --git a/bindings/nodejs/tests/directory_util.js b/bindings/nodejs/tests/directory_util.js deleted file mode 100644 index cceed31232..0000000000 --- a/bindings/nodejs/tests/directory_util.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * directory_util.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -"use strict"; -var fdb = require('../lib/fdb.js').apiVersion(parseInt(process.argv[3])); -var util = require('../lib/fdbUtil.js'); - -var opsThatCreateDirs = [ - 'DIRECTORY_CREATE_SUBSPACE', - 'DIRECTORY_CREATE_LAYER', - 'DIRECTORY_CREATE_OR_OPEN', - 'DIRECTORY_CREATE', - 'DIRECTORY_OPEN', - 'DIRECTORY_MOVE', - 'DIRECTORY_MOVE_TO', - 'DIRECTORY_OPEN_SUBSPACE' -]; - -var popTuples = function(inst, num, cb) { - if(typeof num === 'undefined') - num = 1; - return fdb.future.create(function(futureCb) { - var tuples = []; - if(num === 0) return futureCb(); - util.whileLoop(function(loopCb) { - inst.pop() - .then(function(count) { - return inst.pop({count: count}) - .then(function(tuple) { - tuples.push(tuple); - if(--num === 0) - return null; - }); - })(loopCb); - }, function() { - if(tuples.length == 1) - futureCb(undefined, tuples[0]); - else - futureCb(undefined, tuples); - }); - })(cb); -}; - -var pushError = function(self, inst, err) { - if(err) { - //console.log(err.toString()); - //console.log(err.stack); - inst.push(fdb.buffer('DIRECTORY_ERROR')); - - if(opsThatCreateDirs.indexOf(inst.op) >= 0) - self.dirList.push(null); - } - - return err; -}; - -module.exports = { - popTuples: popTuples, - pushError: pushError -}; diff --git a/bindings/nodejs/tests/get_range.js b/bindings/nodejs/tests/get_range.js deleted file mode 100755 index f79a46e13a..0000000000 --- a/bindings/nodejs/tests/get_range.js +++ /dev/null @@ -1,62 +0,0 @@ -/* - * get_range.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var fdb = require('../lib/fdb').apiVersion(200); - -var db = fdb.open(null, null) - -var tr = db.createTransaction(); - -for(var i = 0; i < 10000; i++) - tr.set('foo' + i, 'bar' + i) - -tr.commit(function(err) { - if(err) - console.log('commit error', err); - - console.log('get range: foo-fooa'); - var itr = tr.getRange('foo', 'fooa', null); - - itr.forEach( - function(val, cb) { - console.log(val.key.toString(), val.value.toString()); - cb(); - }, - function(err, res) { - if(err) - console.log(err); - else { - itr.forEach( - function(val, cb) { - console.log('pass2: ' + val.key.toString(), val.value.toString()); - cb(); - }, - function(err, res) { - if(err) - console.log(err); - else { } - } - ); - } - } - ); -}); - - diff --git a/bindings/nodejs/tests/get_versionstamp.js b/bindings/nodejs/tests/get_versionstamp.js deleted file mode 100644 index 3d18690f19..0000000000 --- a/bindings/nodejs/tests/get_versionstamp.js +++ /dev/null @@ -1,59 +0,0 @@ -/* - * get_versionstamp.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var bufferEqual = function (a, b) { - if (!Buffer.isBuffer(a)) return undefined; - if (!Buffer.isBuffer(b)) return undefined; - if (typeof a.equals === 'function') return a.equals(b); - if (a.length !== b.length) return false; - - for (var i = 0; i < a.length; i++) { - if (a[i] !== b[i]) return false; - } - - return true; -}; - -var fdb = require('../lib/fdb').apiVersion(410); - -var db = fdb.open(null, null) - -var tr = db.createTransaction(); - -tr.getVersionstamp(function(error, vs) { - db.get('foo', function(error, val) { - if(bufferEqual(val, vs)) - console.log('versionstamps match!') - else { - console.log("versionstamps don't match!") - console.log("database verionstamp: " + val) - console.log("transaction versionstamp: " + vs) - } - }); -}); - -tr.setVersionstampedValue('foo', 'blahblahbl') - -tr.commit(function(err) { - if(err) - console.log('commit error', err); - - console.log(tr.getCommittedVersion()) -}); diff --git a/bindings/nodejs/tests/promise_aplus_test.js b/bindings/nodejs/tests/promise_aplus_test.js deleted file mode 100644 index 367c771d2b..0000000000 --- a/bindings/nodejs/tests/promise_aplus_test.js +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env node - -/* - * promise_aplus_test.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -"use strict"; - -var promisesAplusTests = require('promises-aplus-tests'); -var future = require('../lib/future.js'); - -var adapter = { - resolved: function(value) { - var f = future.create(); - f._state.fulfill(value); - return f; - }, - - rejected: function(reason) { - var f = future.create(); - f._state.reject(reason); - return f; - }, - - deferred: function() { - var f = future.create(); - - return { - promise: f, - resolve: function(value) { - f._state.fulfill(value); - }, - reject: function(reason) { - f._state.reject(reason); - }, - }; - } -}; - -promisesAplusTests(adapter, function(err) { - console.log('Finished tests:', err); -}); diff --git a/bindings/nodejs/tests/retry_test.js b/bindings/nodejs/tests/retry_test.js deleted file mode 100755 index 67257dbd63..0000000000 --- a/bindings/nodejs/tests/retry_test.js +++ /dev/null @@ -1,58 +0,0 @@ -/* - * retry_test.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var fdb = require('../lib/fdb').apiVersion(200); - -function set(db, key, value, cb) { - db.doTransaction(function(tr, cb2) { - console.log("setting key"); - tr.set(new Buffer(key), new Buffer(value)); - cb2(null); - }, cb); -}; - -function setTxn(tr, key, value, cb) { - console.log('calling set'); - tr.set(new Buffer(key), new Buffer(value)); - cb(); -}; -setTxn = fdb.transactional(setTxn); - -function getAndClear(db, key, cb) { - db.doTransaction(function(tr, cb2) { - console.log("getting key"); - tr.get(new Buffer(key), function(err, res) { - tr.clear(new Buffer(key)); - //setTimeout(function() { cb2(err, res); }, 6000); - cb2(err, res); - }); - }, cb); -}; - -fdb.open(null, null, function(dbErr, db) { - console.log("created database", dbErr); - setTxn(db, 'foo', 'bar', function(err) { - console.log("Called transactional function", err); - getAndClear(db, 'foo', function(err, res) { - console.log("Called get and clear", err, res.toString()); - }); - }); -}); - diff --git a/bindings/nodejs/tests/streamline_async_test._js b/bindings/nodejs/tests/streamline_async_test._js deleted file mode 100755 index 6299769de3..0000000000 --- a/bindings/nodejs/tests/streamline_async_test._js +++ /dev/null @@ -1,33 +0,0 @@ -var fdb = require('../lib/fdb').apiVersion(200); - -function doSomething(_){ - console.log("start"); - db = fdb.open(null, null); - db = db(_); - db = fdb.open(null, null); - db = db(_); - - a = db.get('foo'); - console.log('foo = ', a(_)); - db.clear('foo', 'bar', _); - console.log('foo = ', db.get('foo', _)); - b = db.set('foo', 'bar'); - b(_); - console.log('foo = ', db.get('foo', _)); - - /*var tr = db.createTransaction(); - tr.set(new Buffer('foo'), new Buffer('bar')); - tr.commit(_); - - var a = tr.get(new Buffer('foo')) - var b = tr.get(new Buffer('bar')) - - console.log(a(_)); - console.log(b(_)); - - var c = tr.get(new Buffer('a')); - console.log(c(_));*/ -} - -doSomething(_); -console.log("after"); diff --git a/bindings/nodejs/tests/streamline_directory_extension._js b/bindings/nodejs/tests/streamline_directory_extension._js deleted file mode 100644 index 9c3356fcef..0000000000 --- a/bindings/nodejs/tests/streamline_directory_extension._js +++ /dev/null @@ -1,148 +0,0 @@ -"use strict"; - -var fdb = require('../lib/fdb.js').apiVersion(parseInt(process.argv[3])); -var fdbUtil = require('../lib/fdbUtil.js'); -var dirUtil = require('./directory_util.js'); - -var StreamlineDirectoryExtension = function() { - this.dirList = [fdb.directory]; - this.dirIndex = 0; - this.errorIndex = 0; -}; - -StreamlineDirectoryExtension.prototype.processInstruction = function(inst, _) { - var directory = this.dirList[this.dirIndex]; - - try { - //console.log(inst.op); - - if(inst.op === 'DIRECTORY_CREATE_SUBSPACE') { - var path = dirUtil.popTuples(inst)(_); - var rawPrefix = inst.pop()(_); - this.dirList.push(new fdb.Subspace(path, rawPrefix)); - } - else if(inst.op === 'DIRECTORY_CREATE_LAYER') { - var params = inst.pop({count: 3})(_); - if(this.dirList[params[0]] === null || this.dirList[params[1]] === null) - this.dirList.push(null); - else { - this.dirList.push(new fdb.DirectoryLayer({ nodeSubspace: this.dirList[params[0]], - contentSubspace: this.dirList[params[1]], - allowManualPrefixes: params[2] })); - } - } - else if(inst.op === 'DIRECTORY_CHANGE') { - var index = inst.pop()(_); - if(this.dirList[index] === null) - this.dirIndex = this.errorIndex; - else - this.dirIndex = index; - } - else if(inst.op === 'DIRECTORY_SET_ERROR_INDEX') { - this.errorIndex = inst.pop()(_); - } - else if(inst.op === 'DIRECTORY_CREATE_OR_OPEN') { - var path = dirUtil.popTuples(inst)(_); - var layer = inst.pop()(_); - var dir = directory.createOrOpen(inst.tr, path, {'layer': layer || undefined})(_); - this.dirList.push(dir); - } - else if(inst.op === 'DIRECTORY_CREATE') { - var path = dirUtil.popTuples(inst)(_); - var params = inst.pop({count: 2})(_); - var dir = directory.create(inst.tr, path, {'layer': params[0] || undefined, 'prefix': params[1] || undefined})(_); - this.dirList.push(dir); - } - else if(inst.op === 'DIRECTORY_OPEN') { - var path = dirUtil.popTuples(inst)(_); - var layer = inst.pop()(_); - var dir = directory.open(inst.tr, path, {'layer': layer || undefined})(_); - this.dirList.push(dir); - } - else if(inst.op === 'DIRECTORY_MOVE') { - var paths = dirUtil.popTuples(inst, 2)(_); - var movedDir = directory.move(inst.tr, paths[0], paths[1])(_); - this.dirList.push(movedDir); - } - else if(inst.op === 'DIRECTORY_MOVE_TO') { - var newAbsolutePath = dirUtil.popTuples(inst)(_); - var movedDir = directory.moveTo(inst.tr, newAbsolutePath)(_); - this.dirList.push(movedDir); - } - else if(inst.op === 'DIRECTORY_REMOVE') { - var count = inst.pop()(_); - var path = dirUtil.popTuples(inst, count)(_); - directory.remove(inst.tr, path)(_); - } - else if(inst.op === 'DIRECTORY_REMOVE_IF_EXISTS') { - var count = inst.pop()(_); - var path = dirUtil.popTuples(inst, count)(_); - directory.removeIfExists(inst.tr, path)(_); - } - else if(inst.op === 'DIRECTORY_LIST') { - var count = inst.pop()(_); - var path = dirUtil.popTuples(inst, count)(_); - var children = directory.list(inst.tr, path)(_); - inst.push(fdb.tuple.pack(children)); - } - else if(inst.op === 'DIRECTORY_EXISTS') { - var count = inst.pop()(_); - var path = dirUtil.popTuples(inst, count)(_); - var exists = directory.exists(inst.tr, path)(_); - inst.push(exists ? 1 : 0); - } - else if(inst.op === 'DIRECTORY_PACK_KEY') { - var keyTuple = dirUtil.popTuples(inst)(_); - inst.push(directory.pack(keyTuple)); - } - else if(inst.op === 'DIRECTORY_UNPACK_KEY') { - var key = inst.pop()(_); - var tup = directory.unpack(key); - for(var i = 0; i < tup.length; ++i) - inst.push(tup[i]); - } - else if(inst.op === 'DIRECTORY_RANGE') { - var tup = dirUtil.popTuples(inst)(_); - var rng = directory.range(tup); - inst.push(rng.begin); - inst.push(rng.end); - } - else if(inst.op === 'DIRECTORY_CONTAINS') { - var key = inst.pop()(_); - inst.push(directory.contains(key) ? 1 : 0); - } - else if(inst.op === 'DIRECTORY_OPEN_SUBSPACE') { - var path = dirUtil.popTuples(inst)(_); - this.dirList.push(directory.subspace(path)); - } - else if(inst.op === 'DIRECTORY_LOG_SUBSPACE') { - var prefix = inst.pop()(_); - inst.tr.set(Buffer.concat([prefix, fdb.tuple.pack([this.dirIndex])]), directory.key()); - } - else if(inst.op === 'DIRECTORY_LOG_DIRECTORY') { - var prefix = inst.pop()(_); - var exists = directory.exists(inst.tr)(_); - var children = exists ? directory.list(inst.tr)(_) : []; - var logSubspace = new fdb.Subspace([this.dirIndex], prefix); - inst.tr.set(logSubspace.get('path'), fdb.tuple.pack(directory.getPath())); - inst.tr.set(logSubspace.get('layer'), fdb.tuple.pack([directory.getLayer()])); - inst.tr.set(logSubspace.get('exists'), fdb.tuple.pack([exists ? 1 : 0])); - inst.tr.set(logSubspace.get('children'), fdb.tuple.pack(children)); - } - else if(inst.op === 'DIRECTORY_STRIP_PREFIX') { - var str = inst.pop()(_); - if(!fdbUtil.buffersEqual(fdb.buffer(str).slice(0, directory.key().length), directory.key())) - throw new Error('String ' + str + ' does not start with raw prefix ' + directory.key()); - - inst.push(str.slice(directory.key().length)); - } - else { - throw new Error('Unknown op: ' + inst.op); - } - } - catch(err) { - dirUtil.pushError(this, inst, err); - } -}; - -module.exports = StreamlineDirectoryExtension; diff --git a/bindings/nodejs/tests/streamline_get_range._js b/bindings/nodejs/tests/streamline_get_range._js deleted file mode 100755 index de9c64cbc3..0000000000 --- a/bindings/nodejs/tests/streamline_get_range._js +++ /dev/null @@ -1,41 +0,0 @@ -var fdb = require('../lib/fdb').apiVersion(200); - -db = fdb.open(null, null, _); - -var tr = db.createTransaction(); - -tr.set('foo1', 'bar1'); -tr.set('foo2', 'bar2'); -tr.set('foo3', 'bar3'); -tr.set('foo4', 'bar4'); -tr.set('foo5', 'bar5'); -tr.set('bar1', 'foo1'); -tr.set('bar2', 'foo2'); - -tr.commit(_); - -console.log('get range: foo1-foo4'); -var itr = tr.getRange('foo1', 'foo4', null); - -a = itr.forEach(function(val, cb) { - console.log(val.key.toString(), val.value.toString()); - cb(null, null); -}); - -console.log('get range starts with: foo'); -itr = tr.getRangeStartsWith('foo'); - -b = itr.forEachBatch(function(arr, cb) { - console.log('processing array', arr.length); - for(var i in arr) - console.log(arr[i].key.toString(), arr[i].value.toString()); - cb(null, null); -}); -c = itr.forEachBatch(function(arr, cb) { - console.log('processing array concurrent', arr.length); - for(var i in arr) - console.log(arr[i].key.toString(), arr[i].value.toString()); - cb(null, null); -}); - -console.log(a(_) + b(_) + c(_)); diff --git a/bindings/nodejs/tests/streamline_retry._js b/bindings/nodejs/tests/streamline_retry._js deleted file mode 100755 index 99126a46f5..0000000000 --- a/bindings/nodejs/tests/streamline_retry._js +++ /dev/null @@ -1,48 +0,0 @@ -var fdb = require('../lib/fdb').apiVersion(200); - -function set(db, key, value, _) { - db.doTransaction(function(tr, _) { - console.log("setting key"); - tr.set(key, value); - return; - }, _); -}; - -function getAndClear(db, key, _) { - a = db.doTransaction(function(tr, _) { - console.log("getting key"); - res = tr.get(key, _); - tr.clear(key); - return res; - }); - - b = db.doTransaction(function(tr, _) { - console.log("getting key"); - res = tr.get(key, _); - tr.clear(key); - return res; - }); - - return a(_) + b(_); -}; - -getAndClearTxn = fdb.transactional(function(tr, key, _) { - console.log("getting key"); - tr.getKey(fdb.KeySelector.firstGreaterOrEqual(key)); - res = tr.get(key, _); - tr.clear(key); - return res; -}); - -db = fdb.open(null, null, _); -set(db, 'foo', 'bar', _); - -//res = getAndClear(db, 'foo'); -//console.log("Called get and clear", res(_).toString()); - -a = getAndClearTxn(db, 'foo'); -b = getAndClearTxn(db, 'foo'); - -res = a(_) + b(_); -console.log("Result:", res.toString()); - diff --git a/bindings/nodejs/tests/streamline_tester._js b/bindings/nodejs/tests/streamline_tester._js deleted file mode 100755 index 1a23134fbd..0000000000 --- a/bindings/nodejs/tests/streamline_tester._js +++ /dev/null @@ -1,464 +0,0 @@ -#!/usr/bin/env _node - -"use strict"; - -//cmd line: _node streamline_tester._js -var startTestPrefix = process.argv[2]; - -var assert = require('assert'); -var fdb = require('../lib/fdb.js').apiVersion(parseInt(process.argv[3])); -var fdbUtil = require('../lib/fdbUtil.js'); -var testerUtil = require('./util.js'); -var DirectoryExtension = require('./streamline_directory_extension._js'); - -var db = fdb.open(process.argv[4]); - -function pushError(inst, err) { - if(err) { - if(!err.code) - throw err; - - inst.push(fdb.tuple.pack([fdb.buffer('ERROR'), fdb.buffer(err.code.toString())])); - } - - return err; -} - -var rangeChoice = 0; -function pushRange(itr, inst, prefixFilter, _) { - var outArray = []; - - function pushKV(kv) { - if(typeof prefixFilter === 'undefined' || prefixFilter === null || fdbUtil.buffersEqual(kv.key.slice(0, prefixFilter.length), prefixFilter)) { - outArray.push(kv.key); - outArray.push(kv.value); - } - } - - //Test the different methods for getting data from a range - if(inst.isDatabase) { - for(var i = 0; i < itr.length; ++i) - pushKV(itr[i]); - } - else if(rangeChoice % 4 === 0) { - itr.forEachBatch(function(res, _) { - for(var i = 0; i < res.length; ++i) - pushKV(res[i]); - - if(rangeChoice % 8 === 0) - setTimeout(_, 0); - }, _); - } - else if(rangeChoice % 4 === 1) { - itr.forEach(function(res, _) { - pushKV(res); - if(rangeChoice % 8 === 1) - setTimeout(_, 0); - }, _); - } - else if(rangeChoice % 4 === 2) { - var arr = itr.toArray(_); - for(var i = 0; i < arr.length; ++i) - pushKV(arr[i]); - } - else { - fdbUtil.whileLoop(function(_) { - var kv = itr.next(_); - if(!kv) - return null; - else - pushKV(kv); - }, _); - } - - rangeChoice++; - inst.push(fdb.tuple.pack(outArray)); -} - -var waitEmpty = fdb.transactional(function(tr, prefix, _) { - var itr = tr.getRangeStartsWith(prefix, { limit: 1 }); - var arr = itr.toArray(_); - - if(arr.length > 0) - throw new fdb.FDBError('', 1020); -}); - -var testWatches = function(db, _) { - db.set('w0', '0', _); - db.set('w3', '3', _); - - var ready = [ false, false, false, false ]; - - var watches = []; - watches[0] = db.doTransaction(function(tr, _) { - return tr.watch('w0'); - }, _); - - watches[1] = db.clearAndWatch('w1', _).watch; - watches[2] = db.setAndWatch('w2', '2', _).watch; - watches[3] = db.getAndWatch('w3', _); - - assert.strictEqual(watches[3].value.toString(), '3', 'get and watch'); - watches[3] = watches[3].watch; - - for(var i = 0; i < watches.length; ++i) { - (function(i) { - watches[i](function(err) { if(!err) ready[i] = true; }); - })(i); - } - - function checkWatches(expected, testName) { - for(var i = 0; i < watches.length; ++i) - assert.strictEqual(ready[i], expected, 'testName' + i); - } - - setTimeout(_, 1000); - checkWatches(false, 'test 1'); - - db.set('w0', '0', _); - db.clear('w1', _); - - setTimeout(_, 5000); - checkWatches(false, 'test 2'); - - db.set('w0', 'a', _); - db.set('w1', 'b', _); - db.clear('w2', _); - db.xor('w3', fdb.buffer.fromByteLiteral('\xff\xff'), _); - - setTimeout(_, 2000); - checkWatches(true, 'test 3'); -}; - -var testLocality = function(_) { - db.doTransaction(function(tr, _) { - tr.options.setTimeout(60*1000); - tr.options.setReadSystemKeys(); - - var boundaryKeys = fdb.locality.getBoundaryKeys(tr, '', fdb.buffer.fromByteLiteral('\xff\xff'), _).toArray(_); - var success = true; - - for(var i = 0; i < boundaryKeys.length-1; ++i) { - var start = boundaryKeys[i]; - var end = tr.getKey(fdb.KeySelector.lastLessThan(boundaryKeys[i+1]), _); - var startAddresses = fdb.locality.getAddressesForKey(tr, start, _); - var endAddresses = fdb.locality.getAddressesForKey(tr, end, _); - for(var j = 0; j < startAddresses.length; ++j) { - var found = false; - for(var k = 0; k < endAddresses.length; ++k) { - if(startAddresses[j].toString() === endAddresses[k].toString()) { - found = true; - break; - } - } - - if(!found) { - success = false; - break; - } - } - - if(!success) - break; - } - - if(!success) - throw(new Error('Locality not internally consistent')); - }, _); -} - -var numOperations = 0; -function processOperation(context, inst, _) { - //if(inst.op !== 'SWAP' && inst.op !== 'PUSH') - //console.log(context.prefix + ':', context.instructionIndex + '.', inst.op); - - var params, numParams, res, itr; - - try { - if(inst.op === 'PUSH') - inst.push(inst.tokens[1]); - else if(inst.op === 'POP') - inst.pop()(_); - else if(inst.op === 'DUP') - context.stack.pushEntry(context.stack.get(context.stack.length()-1)); - else if(inst.op === 'EMPTY_STACK') - context.stack = new testerUtil.Stack(); - else if(inst.op === 'SWAP') { - var index = inst.pop()(_); - assert.strictEqual(context.stack.length() > index, true, 'Cannot swap; stack too small'); - index = context.stack.length() - index - 1; - if(context.stack.length() > index + 1) { - var tmp = context.stack.get(index); - context.stack.set(index, context.stack.popEntry()); - context.stack.pushEntry(tmp); - } - } - else if(inst.op === 'WAIT_FUTURE') { - var stackEntry = inst.pop({withMetadata: true})(_); - context.stack.pushEntry(stackEntry); - } - else if(inst.op === 'WAIT_EMPTY') { - var waitKey = inst.pop()(_); - waitEmpty(db, waitKey, _); - inst.push('WAITED_FOR_EMPTY'); - } - else if(inst.op === 'START_THREAD') { - var prefix = inst.pop()(_); - processTest(prefix, function(err, res) { - if(err) { - console.error('ERROR in Thread', prefix + ':'); - console.error(err.stack); - process.exit(1); - } - }); - } - else if(inst.op === 'NEW_TRANSACTION') { - context.newTransaction(); - } - else if(inst.op === 'USE_TRANSACTION') { - var name = inst.pop()(_); - context.switchTransaction(name); - } - else if(inst.op === 'SET') { - params = inst.pop({count: 2})(_); - - res = inst.tr.set(params[0], params[1]); - if(inst.isDatabase) - inst.push(res, true); - } - else if(inst.op === 'CLEAR') { - var key = inst.pop()(_); - - res = inst.tr.clear(key); - if(inst.isDatabase) - inst.push(res, true); - } - else if(inst.op === 'CLEAR_RANGE') { - params = inst.pop({count: 2})(_); - - res = inst.tr.clearRange(params[0], params[1]); - if(inst.isDatabase) - inst.push(res, true); - } - else if(inst.op === 'CLEAR_RANGE_STARTS_WITH') { - var prefix = inst.pop()(_); - - res = inst.tr.clearRangeStartsWith(prefix); - if(inst.isDatabase) - inst.push(res, true); - } - else if(inst.op === 'ATOMIC_OP') { - params = inst.pop({count: 3})(_); - - res = inst.tr[testerUtil.toJavaScriptName(params[0])](params[1], params[2]); - if(inst.isDatabase) - inst.push(res, true); - } - else if(inst.op === 'COMMIT') { - inst.push(inst.tr.commit(), true); - } - else if(inst.op === 'RESET') - inst.tr.reset(); - else if(inst.op === 'CANCEL') - inst.tr.cancel(); - else if(inst.op === 'GET') { - var key = inst.pop()(_); - inst.push(inst.tr.get(key), true); - } - else if(inst.op === 'GET_RANGE') { - params = inst.pop({count: 5})(_); - - if(inst.isDatabase) - itr = inst.tr.getRange(params[0], params[1], { limit: params[2], reverse: params[3], streamingMode: params[4] }, _); - else - itr = inst.tr.getRange(params[0], params[1], { limit: params[2], reverse: params[3], streamingMode: params[4] }); - - pushRange(itr, inst, undefined, _); - } - else if(inst.op === 'GET_RANGE_SELECTOR') { - params = inst.pop({count: 10})(_); - - var start = new fdb.KeySelector(params[0], params[1], params[2]); - var end = new fdb.KeySelector(params[3], params[4], params[5]); - - if(inst.isDatabase) - itr = inst.tr.getRange(start, end, { limit: params[6], reverse: params[7], streamingMode: params[8] }, _); - else - itr = inst.tr.getRange(start, end, { limit: params[6], reverse: params[7], streamingMode: params[8] }); - - pushRange(itr, inst, params[9], _); - } - else if(inst.op === 'GET_RANGE_STARTS_WITH') { - params = inst.pop({count: 4})(_); - - if(inst.isDatabase) - itr = inst.tr.getRangeStartsWith(params[0], { limit: params[1], reverse: params[2], streamingMode: params[3] }, _); - else - itr = inst.tr.getRangeStartsWith(params[0], { limit: params[1], reverse: params[2], streamingMode: params[3] }); - - pushRange(itr, inst, undefined, _); - } - else if(inst.op === 'GET_KEY') { - params = inst.pop({count: 4})(_); - var key = inst.tr.getKey(new fdb.KeySelector(params[0], params[1], params[2]), _); - - if(fdbUtil.buffersEqual(key.slice(0, params[3].length), params[3])) { - inst.push(key); - } - else if(fdb.buffer.toByteLiteral(key) < fdb.buffer.toByteLiteral(params[3])) { - inst.push(params[3]); - } - else { - inst.push(fdbUtil.strinc(params[3])); - } - } - else if(inst.op === 'READ_CONFLICT_RANGE') { - params = inst.pop({count: 2})(_); - inst.tr.addReadConflictRange(params[0], params[1]); - inst.push(fdb.buffer('SET_CONFLICT_RANGE')); - } - else if(inst.op === 'WRITE_CONFLICT_RANGE') { - params = inst.pop({count: 2})(_); - inst.tr.addWriteConflictRange(params[0], params[1]); - inst.push(fdb.buffer('SET_CONFLICT_RANGE')); - } - else if(inst.op === 'READ_CONFLICT_KEY') { - var key = inst.pop()(_); - inst.tr.addReadConflictKey(key); - inst.push(fdb.buffer('SET_CONFLICT_KEY')); - } - else if(inst.op === 'WRITE_CONFLICT_KEY') { - var key = inst.pop()(_); - inst.tr.addWriteConflictKey(key); - inst.push(fdb.buffer('SET_CONFLICT_KEY')); - } - else if(inst.op === 'DISABLE_WRITE_CONFLICT') { - inst.tr.options.setNextWriteNoWriteConflictRange(); - } - else if(inst.op === 'GET_READ_VERSION') { - context.lastVersion = inst.tr.getReadVersion(_); - inst.push(fdb.buffer('GOT_READ_VERSION')); - } - else if(inst.op === 'GET_COMMITTED_VERSION') { - context.lastVersion = inst.tr.getCommittedVersion(); - inst.push(fdb.buffer('GOT_COMMITTED_VERSION')); - } - else if(inst.op === 'GET_VERSIONSTAMP') { - inst.push(inst.tr.getVersionstamp(), true); - } - else if(inst.op === 'SET_READ_VERSION') { - assert.notStrictEqual(typeof context.lastVersion, 'undefined', 'Cannot set read version; version has never been read'); - inst.tr.setReadVersion(context.lastVersion); - } - else if(inst.op === 'ON_ERROR') { - var errorCode = inst.pop()(_); - var testErr = new fdb.FDBError('', errorCode); - - inst.push(inst.tr.onError(testErr), true); - } - else if(inst.op === 'TUPLE_PACK') { - numParams = inst.pop()(_); - params = inst.pop({count: numParams})(_); - inst.push(fdb.tuple.pack(params)); - } - else if(inst.op === 'TUPLE_UNPACK') { - var packedTuple = inst.pop()(_); - var arr = fdb.tuple.unpack(packedTuple); - for(var i = 0; i < arr.length; ++i) - inst.push(fdb.tuple.pack([arr[i]])); - } - else if(inst.op === 'TUPLE_RANGE') { - numParams = inst.pop()(_); - params = inst.pop({count: numParams})(_); - var range = fdb.tuple.range(params); - inst.push(range.begin); - inst.push(range.end); - } - else if(inst.op === 'SUB') { - params = inst.pop({count: 2})(_); - inst.push(params[0] - params[1]); - } - else if(inst.op === 'CONCAT') { - params = inst.pop({count: 2})(_); - if(Buffer.isBuffer(params[0])) { - inst.push(Buffer.concat([params[0], params[1]])) - } - else { - inst.push(params[0] + params[1]); - } - } - else if(inst.op === 'LOG_STACK') { - var prefix = inst.pop()(_); - var items = inst.pop({count: context.stack.length(), withMetadata: true})(_); - - for(var i = 0; i < items.length; ++i) { - if(i % 100 === 0) - inst.tr.commit(_); - inst.tr.reset(); - - var entry = items[items.length - i -1]; - var packedSubKey = fdb.tuple.pack([i, entry.instructionIndex]); - - var packedValue = fdb.tuple.pack([entry.item]); - if(packedValue.length > 40000) - packedValue = packedValue.slice(0, 40000); - - inst.tr.set(Buffer.concat([prefix, packedSubKey], prefix.length + packedSubKey.length), packedValue); - } - - inst.tr.commit(_); - inst.tr.reset(); - } - else if(inst.op === 'UNIT_TESTS') { - try { - db.options.setLocationCacheSize(100001); - db.doTransaction(function(tr, _) { - tr.options.setPrioritySystemImmediate(); - tr.options.setPriorityBatch(); - tr.options.setCausalReadRisky(); - tr.options.setCausalWriteRisky(); - tr.options.setReadYourWritesDisable(); - tr.options.setReadAheadDisable(); - tr.options.setReadSystemKeys(); - tr.options.setAccessSystemKeys(); - tr.options.setDurabilityDevNullIsWebScale(); - tr.options.setTimeout(1000); - tr.options.setRetryLimit(5); - tr.options.setMaxRetryDelay(100); - tr.options.setUsedDuringCommitProtectionDisable(); - tr.options.setTransactionLoggingEnable('my_transaction'); - - tr.get(fdb.buffer.fromByteLiteral('\xff'), _); - }, _); - - testWatches(db, _); - testLocality(_); - } - catch(err) { - throw('Unit tests failed: ' + err); - } - } - else if(testerUtil.startsWith(inst.op, 'DIRECTORY_')) { - context.directoryExtension.processInstruction(inst, _); - } - else - throw new Error('Unrecognized operation'); - } - catch(err) { - pushError(inst, err); - } -} - -function processTest(prefix, _) { - var context = new testerUtil.Context(db, prefix, processOperation, new DirectoryExtension()); - try { - context.run(_); - } - catch(err) { - console.error('ERROR during operation \'' + context.ops[context.current].value.toString() + '\':'); - console.error(err.stack); - process.exit(1); - } -} - -processTest(startTestPrefix, _); diff --git a/bindings/nodejs/tests/tester.js b/bindings/nodejs/tests/tester.js deleted file mode 100755 index cde82f4174..0000000000 --- a/bindings/nodejs/tests/tester.js +++ /dev/null @@ -1,754 +0,0 @@ -#!/usr/bin/env node - -/* - * tester.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -"use strict"; - -//cmd line: node tester.js -var startTestPrefix = process.argv[2]; -if(process.argv.length === 5) - var clusterFile = process.argv[4]; -else - var clusterFile = ''; - -var assert = require('assert'); -var fdb = require('../lib/fdb.js').apiVersion(parseInt(process.argv[3])); -var fdbUtil = require('../lib/fdbUtil.js'); -var testerUtil = require('./util.js'); -var DirectoryExtension = require('./directory_extension.js'); -//fdb.options.setTraceEnable() - -var db = fdb.open(clusterFile); - -function pushError(inst, err) { - if(err) { - if(!err.code) { - console.error('ERROR during operation \'' + inst.op + '\':'); - console.error(err.stack); - context.cb(err); - } - - inst.push(fdb.tuple.pack([fdb.buffer('ERROR'), fdb.buffer(err.code.toString())])); - } - - return err; -} - -var rangeChoice = 0; -function pushRange(itr, inst, prefixFilter, cb) { - return fdb.future.create(function(futureCb) { - var outArray = []; - - function pushKV(kv) { - if(typeof prefixFilter === 'undefined' || prefixFilter === null || fdbUtil.buffersEqual(kv.key.slice(0, prefixFilter.length), prefixFilter)) { - outArray.push(kv.key); - outArray.push(kv.value); - } - } - - function finish(err) { - if(!pushError(inst, err)) - inst.push(fdb.tuple.pack(outArray)); - - futureCb(); - } - - //Test different methods for getting a range - if(inst.isDatabase) { - for(var i = 0; i < itr.length; ++i) - pushKV(itr[i]); - - finish(); - } - else if(rangeChoice % 4 === 0) { - itr.forEachBatch(function(res, itrCb) { - for(var i = 0 ; i < res.length; ++i) - pushKV(res[i]); - - if(rangeChoice % 8 === 0) - setTimeout(itrCb, 0); - else - itrCb(); - }, function(err, res) { - finish(err); - }); - } - else if(rangeChoice % 4 === 1) { - itr.forEach(function(res, itrCb) { - pushKV(res); - - if(rangeChoice % 8 === 1) - setTimeout(itrCb, 0); - else - itrCb(); - }, function(err, res) { - finish(err); - }); - } - else if(rangeChoice % 4 === 2) { - itr.toArray(function(err, arr) { - if(!err) { - for(var i = 0; i < arr.length; ++i) - pushKV(arr[i]); - } - - finish(err); - }); - } - else { - fdbUtil.whileLoop(function(loopCb) { - itr.next(function(err, res) { - if(err) - loopCb(err); - else if(!res) - loopCb(undefined, null); - else { - pushKV(res); - loopCb(); - } - }); - }, finish); - } - - rangeChoice++; - })(cb); -} - -var waitEmpty = fdb.transactional(function(tr, prefix, cb) { - var itr = tr.getRangeStartsWith(prefix, { limit: 1 }); - itr.toArray(function(err, res) { - if(err) - cb(err, null); - else if(res.length > 0) - cb(new fdb.FDBError('', 1020), null); - else - cb(null, null); - }); -}); - -var timeoutFuture = function(time) { - return fdb.future.create(function(futureCb) { - setTimeout(futureCb, time); - }); -}; - -var checkWatches = function(db, watches, ready, error, expected, cb) { - var i = 0; - return fdbUtil.whileLoop(function(loopCb) { - if(i == watches.length) return loopCb(undefined, true); // terminate loop - if(!ready[i] && expected) { - return watches[i] - .then(function() { - loopCb(); // Recheck this watch when it finishes - }) - .catch(function() { - loopCb(); // Check the error - }); - } - assert.strictEqual(!ready[i] || expected, true, 'watch shouldnt be ready: ' + i); - if(typeof error[i] !== 'undefined') { - var tr = db.createTransaction(); - return tr.onError(error[i]) - .then(function() { - return false; - })(loopCb); - } - - i++; - loopCb(); - })(cb); -} - -var testWatches = function(db, cb) { - return fdbUtil.whileLoop(function(loopCb) { - var ready = [ false, false, false, false ]; - var error = [ undefined, undefined, undefined, undefined ]; - var watches = []; - - db.doTransaction(function(tr, innerCb) { - tr.set('w0', '0') - tr.set('w3', '3'); - innerCb(); - }) - .then(function() { - return db.doTransaction(function(tr, innerCb) { - watches[0] = tr.watch('w0'); - innerCb(); - }); - }) - .then(function() { - return db.clearAndWatch('w1'); - }) - .then(function(w) { - watches[1] = w.watch; - return db.setAndWatch('w2', '2'); - }) - .then(function(w) { - watches[2] = w.watch; - return db.getAndWatch('w3'); - }) - .then(function(w) { - assert.strictEqual(w.value.toString(), '3', 'get and watch'); - watches[3] = w.watch; - - for(var i = 0; i < watches.length; ++i) { - (function(i) { - watches[i](function(err) { - if(!err) ready[i] = true; - else error[i] = err; - }); - })(i); - } - - return timeoutFuture(1000); - }) - .then(function() { - return checkWatches(db, watches, ready, error, false); - }) - .then(function(result) { - if(!result) return; // go around the loop again - return db.doTransaction(function(tr, innerCb) { - tr.set('w0', '0'); - innerCb(); - }) - .then(function() { - return db.clear('w1'); - }) - .then(function() { - return timeoutFuture(5000); - }) - .then(function() { - return checkWatches(db, watches, ready, error, false); - }) - .then(function(result) { - if(!result) return; // go around the loop again - return db.set('w0', 'a') - .then(function() { - return db.set('w1', 'b'); - }) - .then(function() { - return db.clear('w2'); - }) - .then(function() { - return db.xor('w3', fdb.buffer.fromByteLiteral('\xff\xff')); - }) - .then(function() { - return timeoutFuture(2000); - }) - .then(function() { - return checkWatches(db, watches, ready, error, true); - }) - .then(function(result) { - if(result) return null; //terminate loop - return; - }); - }); - })(loopCb); - })(cb); -}; - -var testLocality = function(db, cb) { - return db.doTransaction(function(tr, innerCb) { - tr.options.setTimeout(60*1000); - tr.options.setReadSystemKeys(); - - fdb.locality.getBoundaryKeys(tr, '', fdb.buffer.fromByteLiteral('\xff\xff'), function(err, itr) { - if(err) return innerCb(err); - - var index = 0; - var start; - var end; - itr.forEach(function(boundaryKey, loopCb) { - if(err) return loopCb(err); - - start = end; - end = boundaryKey; - if(index++ == 0) - return loopCb(); - - tr.getKey(fdb.KeySelector.lastLessThan(end), function(err, end) { - if(err) return loopCb(err); - - fdb.locality.getAddressesForKey(tr, start, function(err, startAddresses) { - if(err) return loopCb(err); - - fdb.locality.getAddressesForKey(tr, end, function(err, endAddresses) { - if(err) return loopCb(err); - - for(var j = 0; j < startAddresses.length; ++j) { - var found = false; - for(var k = 0; k < endAddresses.length; ++k) { - if(startAddresses[j].toString() === endAddresses[k].toString()) { - found = true; - break; - } - } - - if(!found) { - return loopCb(new Error('Locality not internally consistent')); - } - } - - loopCb(); - }); - }); - }); - }, innerCb); - }); - }, cb); -}; - -var numOperations = 0; -function processOperation(context, inst, cb) { - //if(inst.op !== 'SWAP' && inst.op !== 'PUSH') - //console.log(context.prefix + ':', context.instructionIndex + '.', inst.op); - - var promiseCb = function(err) { - pushError(inst, err); - cb(); - }; - - if(inst.op === 'PUSH') { - inst.push(inst.tokens[1]); - cb(); - } - else if(inst.op === 'POP') { - inst.pop()(promiseCb); - } - else if(inst.op === 'DUP') { - context.stack.pushEntry(context.stack.get(context.stack.length()-1)); - cb(); - } - else if(inst.op === 'EMPTY_STACK') { - context.stack = new testerUtil.Stack(); - cb(); - } - else if(inst.op === 'SWAP') { - inst.pop() - .then(function(index) { - assert.strictEqual(context.stack.length() > index, true, 'Cannot swap; stack too small'); - index = context.stack.length() - index - 1; - if(context.stack.length() > index + 1) { - var tmp = context.stack.get(index); - context.stack.set(index, context.stack.popEntry()); - context.stack.pushEntry(tmp); - } - })(promiseCb); - } - else if(inst.op === 'WAIT_FUTURE') { - inst.pop({withMetadata: true}) - .then(function(stackEntry) { - context.stack.pushEntry(stackEntry); - })(promiseCb); - } - else if(inst.op === 'WAIT_EMPTY') { - inst.pop() - .then(function(waitKey) { - return waitEmpty(db, waitKey) - .then(function() { - inst.push('WAITED_FOR_EMPTY'); - }); - })(promiseCb); - } - else if(inst.op === 'START_THREAD') { - inst.pop() - .then(function(prefix) { - processTest(prefix, function(err, res) { - if(err) { - console.error('ERROR in Thread', prefix + ':'); - console.error(err.stack); - process.exit(1); - } - }); - })(promiseCb); - } - else if(inst.op === 'NEW_TRANSACTION') { - context.newTransaction(); - cb(); - } - else if(inst.op === 'USE_TRANSACTION') { - inst.pop() - .then(function(name) { - context.switchTransaction(name); - })(promiseCb); - } - else if(inst.op === 'SET') { - inst.pop({count: 2}) - .then(function(params) { - var res = inst.tr.set(params[0], params[1]); - - if(inst.isDatabase) - inst.push(res, true); - })(promiseCb); - } - else if(inst.op === 'CLEAR') { - inst.pop() - .then(function(key) { - var res = inst.tr.clear(key); - - if(inst.isDatabase) - inst.push(res, true); - })(promiseCb); - } - else if(inst.op === 'CLEAR_RANGE') { - inst.pop({count: 2}) - .then(function(params) { - var res = inst.tr.clearRange(params[0], params[1]); - - if(inst.isDatabase) - inst.push(res, true); - })(promiseCb); - } - else if(inst.op === 'CLEAR_RANGE_STARTS_WITH') { - inst.pop() - .then(function(prefix) { - var res = inst.tr.clearRangeStartsWith(prefix); - - if(inst.isDatabase) - inst.push(res, true); - })(promiseCb); - } - else if(inst.op === 'ATOMIC_OP') { - inst.pop({count: 3}) - .then(function(params) { - var res = inst.tr[testerUtil.toJavaScriptName(params[0])](params[1], params[2]); - - if(inst.isDatabase) - inst.push(res, true); - })(promiseCb); - } - else if(inst.op === 'COMMIT') { - inst.push(inst.tr.commit(), true); - cb(); - } - else if(inst.op === 'RESET') { - inst.tr.reset(); - cb(); - } - else if(inst.op === 'CANCEL') { - inst.tr.cancel(); - cb(); - } - else if(inst.op === 'GET') { - inst.pop() - .then(function(key) { - inst.push(inst.tr.get(key), true); - })(promiseCb); - } - else if(inst.op === 'GET_RANGE') { - inst.pop({count: 5}) - .then(function(params) { - var itr = inst.tr.getRange(params[0], params[1], { limit: params[2], reverse: params[3], streamingMode: params[4] }); - if(inst.isDatabase) { - return itr.then(function(arr) { - return pushRange(arr, inst); - }); - } - else { - return pushRange(itr, inst); - } - })(promiseCb); - } - else if(inst.op === 'GET_RANGE_SELECTOR') { - inst.pop({count: 10}) - .then(function(params) { - var start = new fdb.KeySelector(params[0], params[1], params[2]); - var end = new fdb.KeySelector(params[3], params[4], params[5]); - var itr = inst.tr.getRange(start, end, { limit: params[6], reverse: params[7], streamingMode: params[8] }); - if(inst.isDatabase) { - return itr.then(function(arr) { - return pushRange(arr, inst, params[9]); - }); - } - else { - return pushRange(itr, inst, params[9]); - } - })(promiseCb); - } - else if(inst.op === 'GET_RANGE_STARTS_WITH') { - inst.pop({count: 4}) - .then(function(params) { - var itr = inst.tr.getRangeStartsWith(params[0], { limit: params[1], reverse: params[2], streamingMode: params[3] }); - if(inst.isDatabase) { - return itr.then(function(arr) { - return pushRange(arr, inst); - }); - } - else { - return pushRange(itr, inst); - } - })(promiseCb); - } - else if(inst.op === 'GET_KEY') { - inst.pop({count: 4}) - .then(function(params) { - var result = inst.tr.getKey(new fdb.KeySelector(params[0], params[1], params[2])) - .then(function(key) { - if(fdbUtil.buffersEqual(key.slice(0, params[3].length), params[3])) { - return key; - } - else if(fdb.buffer.toByteLiteral(key) < fdb.buffer.toByteLiteral(params[3])) { - return params[3]; - } - else { - return fdbUtil.strinc(params[3]); - } - }); - - inst.push(result, true); - })(promiseCb); - } - else if(inst.op === 'READ_CONFLICT_RANGE') { - inst.pop({count: 2}) - .then(function(params) { - inst.tr.addReadConflictRange(params[0], params[1]); - inst.push(fdb.buffer('SET_CONFLICT_RANGE')); - })(promiseCb); - } - else if(inst.op === 'WRITE_CONFLICT_RANGE') { - inst.pop({count: 2}) - .then(function(params) { - inst.tr.addWriteConflictRange(params[0], params[1]); - inst.push(fdb.buffer('SET_CONFLICT_RANGE')); - })(promiseCb); - } - else if(inst.op === 'READ_CONFLICT_KEY') { - inst.pop() - .then(function(key) { - inst.tr.addReadConflictKey(key); - inst.push(fdb.buffer('SET_CONFLICT_KEY')); - })(promiseCb); - } - else if(inst.op === 'WRITE_CONFLICT_KEY') { - inst.pop() - .then(function(key) { - inst.tr.addWriteConflictKey(key); - inst.push(fdb.buffer('SET_CONFLICT_KEY')); - })(promiseCb); - } - else if(inst.op === 'DISABLE_WRITE_CONFLICT') { - inst.tr.options.setNextWriteNoWriteConflictRange(); - cb(); - } - else if(inst.op === 'GET_READ_VERSION') { - inst.tr.getReadVersion(function(err, res) { - if(!pushError(inst, err)) { - context.lastVersion = res; - inst.push(fdb.buffer('GOT_READ_VERSION')); - } - cb(); - }); - } - else if(inst.op === 'GET_COMMITTED_VERSION') { - try { - context.lastVersion = inst.tr.getCommittedVersion(); - - inst.push(fdb.buffer('GOT_COMMITTED_VERSION')); - cb(); - } - catch(err) { - pushError(inst, err); - cb(); - } - } - else if(inst.op === 'GET_VERSIONSTAMP') { - try { - inst.push(inst.tr.getVersionstamp(), true) - cb(); - } - catch(err) { - pushError(inst, err); - cb(); - } - } - else if(inst.op === 'SET_READ_VERSION') { - assert.notStrictEqual(typeof context.lastVersion, 'undefined', 'Cannot set read version; version has never been read'); - inst.tr.setReadVersion(context.lastVersion); - cb(); - } - else if(inst.op === 'ON_ERROR') { - inst.pop() - .then(function(errorCode) { - var testErr = new fdb.FDBError('', errorCode); - - inst.push(inst.tr.onError(testErr), true); - })(promiseCb); - } - else if(inst.op === 'TUPLE_PACK') { - inst.pop() - .then(function(numParams) { - return inst.pop({count: numParams}) - .then(function(params) { - inst.push(fdb.tuple.pack(params)); - }); - })(promiseCb); - } - else if(inst.op === 'TUPLE_UNPACK') { - inst.pop() - .then(function(packedTuple) { - var arr = fdb.tuple.unpack(packedTuple); - for(var i = 0; i < arr.length; ++i) - inst.push(fdb.tuple.pack([arr[i]])); - })(promiseCb); - } - else if(inst.op === 'TUPLE_RANGE') { - inst.pop() - .then(function(numParams) { - return inst.pop({count: numParams}) - .then(function(params) { - var range = fdb.tuple.range(params); - inst.push(range.begin); - inst.push(range.end); - }); - })(promiseCb); - } - else if(inst.op === 'TUPLE_SORT') { - inst.pop() - .then(function(numParams) { - return inst.pop({count: numParams}) - .then(function(params) { - var tuples = []; - for(var i = 0; i < params.length; ++i) - tuples.push(fdb.tuple.unpack(params[i])); - tuples.sort(fdb.tuple.compare); - for(var i = 0; i < tuples.length; ++i) - inst.push(fdb.tuple.pack(tuples[i])); - }); - })(promiseCb); - } - else if(inst.op === 'SUB') { - inst.pop({count: 2}) - .then(function(params) { - inst.push(params[0] - params[1]); - })(promiseCb); - } - else if(inst.op === 'ENCODE_FLOAT') { - inst.pop() - .then(function(fBytes) { - inst.push(fdb.tuple.Float.fromBytes(fBytes)); - })(promiseCb); - } - else if(inst.op === 'ENCODE_DOUBLE') { - inst.pop() - .then(function(dBytes) { - inst.push(fdb.tuple.Double.fromBytes(dBytes)); - })(promiseCb); - } - else if(inst.op === 'DECODE_FLOAT') { - inst.pop() - .then(function(fVal) { - inst.push(fVal.toBytes()); - })(promiseCb); - } - else if(inst.op === 'DECODE_DOUBLE') { - inst.pop() - .then(function(dVal) { - inst.push(dVal.toBytes()); - })(promiseCb); - } - else if(inst.op === 'CONCAT') { - inst.pop({count: 2}) - .then(function(params) { - if(Buffer.isBuffer(params[0])) { - inst.push(Buffer.concat([params[0], params[1]])) - } - else { - inst.push(params[0] + params[1]); - } - })(promiseCb); - } - else if(inst.op === 'LOG_STACK') { - inst.pop() - .then(function(prefix) { - return fdbUtil.whileLoop(function(loopCb) { - inst.pop({count: 100, withMetadata: true}) - .then(function(items) { - if(items.length == 0) { - return null - } - return db.doTransaction(function(tr, innerCb) { - for(var index = 0; index < items.length; ++index) { - var entry = items[items.length - index - 1]; - var packedSubKey = fdb.tuple.pack([context.stack.length() + index, entry.instructionIndex]); - - var packedValue = fdb.tuple.pack([entry.item]); - if(packedValue.length > 40000) - packedValue = packedValue.slice(0, 40000); - - tr.set(Buffer.concat([prefix, packedSubKey], prefix.length + packedSubKey.length), packedValue); - } - - innerCb(); - }); - })(loopCb); - }); - })(promiseCb); - } - else if(inst.op === 'UNIT_TESTS') { - db.options.setLocationCacheSize(100001); - db.doTransaction(function(tr, innerCb) { - tr.options.setPrioritySystemImmediate(); - tr.options.setPriorityBatch(); - tr.options.setCausalReadRisky(); - tr.options.setCausalWriteRisky(); - tr.options.setReadYourWritesDisable(); - tr.options.setReadAheadDisable(); - tr.options.setReadSystemKeys(); - tr.options.setAccessSystemKeys(); - tr.options.setDurabilityDevNullIsWebScale(); - tr.options.setTimeout(60*1000); - tr.options.setRetryLimit(50); - tr.options.setMaxRetryDelay(100); - tr.options.setUsedDuringCommitProtectionDisable(); - tr.options.setTransactionLoggingEnable('my_transaction'); - tr.options.setReadLockAware() - tr.options.setLockAware() - - tr.get(fdb.buffer.fromByteLiteral('\xff'), innerCb); - }) - .then(function() { - return testWatches(db); - }) - .then(function() { - return testLocality(db); - }) - .then(cb) - .catch(function(err) { - cb('Unit tests failed: ' + err + "\n" + err.stack); - }); - } - else if(testerUtil.startsWith(inst.op, 'DIRECTORY_')) { - context.directoryExtension.processInstruction(inst, cb); - } - else { - cb('Unrecognized operation'); - } -} - -function processTest(prefix, cb) { - var context = new testerUtil.Context(db, prefix, processOperation, new DirectoryExtension()); - context.run(cb); -} - -processTest(startTestPrefix, function(err, res) { - if(err) - process.exit(1); -}); diff --git a/bindings/nodejs/tests/tuple_test.js b/bindings/nodejs/tests/tuple_test.js deleted file mode 100755 index dc59733623..0000000000 --- a/bindings/nodejs/tests/tuple_test.js +++ /dev/null @@ -1,101 +0,0 @@ -/* - * tuple_test.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var fdb = require('../lib/fdb.js').apiVersion(510); -var fdbModule = require('../lib/fdbModule.js'); - -console.log(fdb.tuple.pack([-Math.pow(2,53)])); -console.log(fdb.tuple.pack([-Math.pow(2,53)+1])); - -console.log(fdb.tuple.unpack(fdb.tuple.pack([-Math.pow(2,53)]))); -console.log(fdb.tuple.unpack(fdb.tuple.pack([-Math.pow(2,53)+1]))); - -try { - console.log(fdb.tuple.unpack(fdb.buffer.fromByteLiteral('\x0d\xdf\xff\xff\xff\xff\xff\xfe'))); -} -catch(err) { - console.log(err); -} - -console.log(fdb.tuple.pack([0xff * 0xff])); -console.log(fdb.tuple.pack([0xffffffff + 100 ])); -console.log(fdb.buffer.printable(fdb.tuple.pack(['begin', [true, null, false], 'end']))) -console.log(fdb.tuple.unpack(fdb.buffer.fromByteLiteral('\x1a\xff\xff\xff\xff\xff\xff'))); -console.log(fdb.tuple.unpack(fdb.tuple.pack(['TEST', 'herp', 1, -10, 393493, '\u0000abc', 0xffffffff + 100, true, false, [new Boolean(true), null, new Boolean(false), 0, 'asdf'], null]))); -console.log(fdb.buffer.printable(fdb.tuple.pack([[[[['three']]], 'two'], 'one']))) -console.log(fdb.tuple.range(['TEST', 1])); -console.log(fdb.buffer.printable(fdb.tuple.pack([fdb.tuple.Float.fromBytes(new Buffer('402df854', 'hex')), fdb.tuple.Double.fromBytes(new Buffer('4005BF0A8B145769', 'hex')), new fdb.tuple.UUID(new Buffer('deadc0deba5eba115ca1ab1edeadc0de', 'hex'))]))) -console.log(fdb.tuple.unpack(fdb.tuple.pack([fdb.tuple.Float.fromBytes(new Buffer('2734236f', 'hex'))]))) - -tuples = [ - [1,2], - [1], - [2], - [true], - [false], - [1,true], - [1,false], - [1, []], - [1, [null]], - [1, [0]], - [1, [1]], - [1, [0,1,2]], - [null], - [] -]; -tuples.sort(fdb.tuple.compare); -console.log(tuples); - -tuples = [ - [fdb.tuple.Float.fromBytes(new Buffer('2734236f', 'hex'))], // A really small value. - [fdb.tuple.Float.fromBytes(new Buffer('80000000', 'hex'))], // -0.0 - [new fdb.tuple.Float(0.0)], - [new fdb.tuple.Float(3.14)], - [new fdb.tuple.Float(-3.14)], - [new fdb.tuple.Float(2.7182818)], - [new fdb.tuple.Float(-2.7182818)], - [fdb.tuple.Float.fromBytes(new Buffer('7f800000', 'hex'))], // Infinity - [fdb.tuple.Float.fromBytes(new Buffer('7fffffff', 'hex'))], // NaN - [fdb.tuple.Float.fromBytes(new Buffer('ffffffff', 'hex'))], // -NaN -]; -tuples.sort(fdb.tuple.compare); -console.log(tuples); - -// Float overruns. -const floats = [ 2.037036e90, -2.037036e90, 4.9090935e-91, -4.9090935e-91, 2.345624805922133125e14, -2.345624805922133125e14 ]; -for (var i = 0; i < floats.length; i++) { - var f = floats[i]; - console.log(f + " -> " + fdb.tuple.Float.fromBytes((new fdb.tuple.Float(f)).toBytes()).value); -} - -// Float type errors. -try { - console.log((new fdb.tuple.Float("asdf")).toBytes()); -} catch (e) { - console.log("Caught!"); - console.log(e); -} - -try { - console.log(fdbModule.toFloat(3.14, 2.718)); -} catch (e) { - console.log("Caught!"); - console.log(e); -} diff --git a/bindings/nodejs/tests/util.js b/bindings/nodejs/tests/util.js deleted file mode 100644 index fa0654d4e3..0000000000 --- a/bindings/nodejs/tests/util.js +++ /dev/null @@ -1,276 +0,0 @@ -/* - * util.js - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -"use strict"; - -var fdb = require('../lib/fdb.js').apiVersion(parseInt(process.argv[3])); -var util = require('../lib/fdbUtil.js'); - -function Stack() { - this.stack = []; -} - -Stack.prototype.length = function() { - return this.stack.length; -}; - -Stack.prototype.get = function(index) { - return this.stack[index]; -}; - -Stack.prototype.set = function(index, val) { - this.stack[index] = val; -}; - -Stack.prototype.push = function(instructionIndex, item, isFuture) { - if(typeof isFuture === 'undefined') - isFuture = false; - - this.pushEntry({ instructionIndex: instructionIndex, item: item, isFuture: isFuture }); -}; - -Stack.prototype.pushEntry = function(entry) { - this.stack.push(entry); -}; - -Stack.prototype.pop = function(options, callback) { - var self = this; - return fdb.future.create(function(futureCb) { - if(typeof options === 'undefined') - options = {}; - - var count = options.count; - if(typeof count === 'undefined') - count = 1; - - var params = self.stack.slice(self.stack.length-count).reverse(); - self.stack = self.stack.slice(0, self.stack.length-count); - - var index = 0; - - var itemCallback = function(err, val) { - if(err) { - //console.log(err); - params[index].item = fdb.tuple.pack([fdb.buffer('ERROR'), fdb.buffer(err.code.toString())]); - } - else if(val) - params[index].item = val; - else - params[index].item = fdb.buffer('RESULT_NOT_PRESENT'); - - params[index].isFuture = false; - - if(!options.withMetadata) - params[index] = params[index].item; - - index++; - processNext(); - }; - - var processNext = function() { - while(true) { - if(index >= params.length) { - if(typeof options.count === 'undefined') - futureCb(undefined, params[0]); - else - futureCb(undefined, params); - - return; - } - - if(params[index].isFuture) { - params[index].item(itemCallback); - return; - } - - if(!options.withMetadata) - params[index] = params[index].item; - - index++; - } - }; - - processNext(); - })(callback); -}; - -Stack.prototype.popEntry = function() { - return this.stack.pop(); -}; - -function Context(db, prefix, processInstruction, directoryExtension) { - var range = fdb.tuple.range([fdb.buffer(prefix)]); - - this.prefix = prefix; - this.stack = new Stack(); - this.db = db; - this.next = range.begin; - this.end = range.end; - this.processInstruction = processInstruction; - this.instructionIndex = -1; - this.directoryExtension = directoryExtension; - this.trName = prefix; -} - -Context.trMap = {} - -Context.prototype.newTransaction = function() { - Context.trMap[this.trName] = this.db.createTransaction(); -}; - -Context.prototype.switchTransaction = function(name) { - this.trName = name; - if(typeof Context.trMap[this.trName] === 'undefined') { - this.newTransaction(); - } -}; - -Context.prototype.updateResults = function(results) { - this.ops = results; - this.current = 0; - this.next = fdb.KeySelector.firstGreaterThan(results[results.length-1].key); -}; - -var issueInstruction = function(context, cb) { - try { - var tokens = fdb.tuple.unpack(context.ops[context.current].value); - var op = tokens[0].toString(); - - var snapshotStr = '_SNAPSHOT'; - var databaseStr = '_DATABASE'; - - var isSnapshot = endsWith(op, snapshotStr); - var isDatabase = endsWith(op, databaseStr); - - var tr = Context.trMap[context.trName]; - if(isSnapshot) { - op = op.substr(0, op.length - snapshotStr.length); - tr = tr.snapshot; - } - else if(isDatabase) { - op = op.substr(0, op.length - databaseStr.length); - tr = context.db; - } - - var inst = new Instruction(context, tr, op, tokens, isDatabase, isSnapshot); - context.processInstruction(context, inst, cb); - } - catch(e) { - cb(e); - } -}; - -Context.prototype.run = function(cb) { - var self = this; - - function getInstructions(instCb) { - self.db.doTransaction(function(tr, trCb) { - tr.getRange(self.next, self.end, { limit: 1000 } ).toArray(function(rangeErr, rangeRes) { - if(rangeErr) return trCb(rangeErr); - - trCb(undefined, rangeRes); - }); - }, function(err, rangeRes) { - if(err) return instCb(err); - if(rangeRes.length > 0) - self.updateResults(rangeRes); - instCb(); - }); - } - - function readAndExecuteInstructions(loopCb) { - ++self.instructionIndex; - if(!self.ops || ++self.current === self.ops.length) { - getInstructions(function(err) { - if(err) return loopCb(err); - if(self.current < self.ops.length) - issueInstruction(self, loopCb); - else - loopCb(undefined, null); // terminate the loop - }); - } - else - issueInstruction(self, loopCb); - } - - util.whileLoop(readAndExecuteInstructions, function(err) { - if(err) { - if(self.ops && self.current < self.ops.length) - console.error('ERROR during operation \'' + self.ops[self.current].value.toString() + '\':'); - else - console.error('ERROR getting operations:'); - - if(err.stack) - console.error(err.stack); - else - console.error(err); - } - - cb(err); - }); -}; - -function Instruction(context, tr, op, tokens, isDatabase, isSnapshot) { - this.context = context; - this.tr = tr; - this.op = op; - this.tokens = tokens; - this.isDatabase = isDatabase; - this.isSnapshot = isSnapshot; -} - -Instruction.prototype.pop = function(options, callback) { - return this.context.stack.pop(options, callback); -}; - -Instruction.prototype.push = function(item, isFuture) { - this.context.stack.push(this.context.instructionIndex, item, isFuture); -}; - -function toJavaScriptName(name) { - name = name.toString().toLowerCase(); - var start = 0; - while(start < name.length) { - start = name.indexOf('_', start); - if(start === -1) - break; - - name = name.slice(0, start) + name[start+1].toUpperCase() + name.slice(start+2); - } - - return name.replace(/_/g, ''); -} - -function startsWith(str, prefixStr) { - return str.length >= prefixStr.length && str.substr(0, prefixStr.length) === prefixStr; -} - -function endsWith(str, endStr) { - return str.length >= endStr.length && str.substr(str.length - endStr.length) === endStr; -} - -module.exports = { - Stack: Stack, - Context: Context, - Instruction: Instruction, - toJavaScriptName: toJavaScriptName, - startsWith: startsWith, - endsWith: endsWith -}; diff --git a/bindings/ruby/lib/fdbdirectory.rb b/bindings/ruby/lib/fdbdirectory.rb index e760cfe433..5c411fe91e 100644 --- a/bindings/ruby/lib/fdbdirectory.rb +++ b/bindings/ruby/lib/fdbdirectory.rb @@ -472,7 +472,7 @@ module FDB prefix && prefix.length > 0 && !node_containing_key(tr, prefix) && - tr.get_range(@node_subspace.pack([prefix]), @node_subspace.pack([tr.send(:strinc, prefix)]), + tr.get_range(@node_subspace.pack([prefix]), @node_subspace.pack([FDB.strinc(prefix)]), { :limit => 1 }).to_a.empty? end diff --git a/build/Dockerfile b/build/Dockerfile index 652aa6ac60..feed88dda5 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,53 +1,17 @@ FROM ubuntu:15.04 -RUN sed -i -e 's/archive.ubuntu.com\|security.ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list && apt-get clean && apt-get update +RUN sed -i -e 's/archive.ubuntu.com\|security.ubuntu.com/old-releases.ubuntu.com/g' -e 's/us\.old/old/g' /etc/apt/sources.list && apt-get clean && apt-get update -RUN apt-get --no-install-recommends install -y libffi6:amd64=3.2.1-2 libgmp10:amd64=2:6.0.0+dfsg-6ubuntu1 libnettle4:amd64=2.7.1-5 libhogweed2:amd64=2.7.1-5 libp11-kit0:amd64=0.20.7-1 libtasn1-6:amd64=4.2-2ubuntu1 libgnutls-deb0-28:amd64=3.3.8-3ubuntu3 libsqlite3-0:amd64=3.8.7.4-1 libroken18-heimdal:amd64=1.6~rc2+dfsg-9 libasn1-8-heimdal:amd64=1.6~rc2+dfsg-9 libkrb5support0:amd64=1.12.1+dfsg-18 libk5crypto3:amd64=1.12.1+dfsg-18 libkeyutils1:amd64=1.5.9-5ubuntu1 libkrb5-3:amd64=1.12.1+dfsg-18 libgssapi-krb5-2:amd64=1.12.1+dfsg-18 libidn11:amd64=1.28-1ubuntu2 libhcrypto4-heimdal:amd64=1.6~rc2+dfsg-9 libheimbase1-heimdal:amd64=1.6~rc2+dfsg-9 libwind0-heimdal:amd64=1.6~rc2+dfsg-9 libhx509-5-heimdal:amd64=1.6~rc2+dfsg-9 libkrb5-26-heimdal:amd64=1.6~rc2+dfsg-9 libheimntlm0-heimdal:amd64=1.6~rc2+dfsg-9 libgssapi3-heimdal:amd64=1.6~rc2+dfsg-9 libsasl2-modules-db:amd64=2.1.26.dfsg1-13 libsasl2-2:amd64=2.1.26.dfsg1-13 libldap-2.4-2:amd64=2.4.31-1+nmu2ubuntu12 librtmp1:amd64=2.4+20131018.git79459a2-5 libcurl3-gnutls:amd64=7.38.0-3ubuntu2 apt-transport-https:amd64=1.0.9.7ubuntu4 bzip2=1.0.6-7 ca-certificates=20141019 && apt-get clean +RUN apt-get --no-install-recommends install -y --force-yes bzip2 ca-certificates=20141019 adduser apt base-files base-passwd bash binutils build-essential cpp cpp-4.9 dpkg dos2unix fakeroot findutils g++=4:4.9.2-2ubuntu2 g++-4.9=4.9.2-10ubuntu13 gawk=1:4.1.1+dfsg-1 gcc-5-base gcc=4:4.9.2-2ubuntu2 gcc-4.9=4.9.2-10ubuntu13 gcc-4.9-base:amd64=4.9.2-10ubuntu13 gcc-5-base:amd64=5.1~rc1-0ubuntu1 gdb git golang golang-go golang-go-linux-amd64 golang-src grep gzip hostname java-common libasan1 liblsan0 libtsan0 libubsan0 libcilkrts5 libgcc-4.9-dev libstdc++-4.9-dev libgl1-mesa-dri libgl1-mesa-glx libmono-system-xml-linq4.0-cil libmono-system-data-datasetextensions4.0-cil libstdc++-4.9-pic locales login m4 make makedev mawk mono-dmcs npm openjdk-8-jdk passwd python-distlib python-gevent python-greenlet python-html5lib python-minimal python-pip python-pkg-resources python-requests python-setuptools python-six python-urllib3 python-yaml python2.7 python2.7-minimal rpm rpm2cpio ruby ruby2.1 rubygems-integration sed tar texinfo tzdata-java udev unzip util-linux valgrind vim wget golang-go.tools curl sphinx-common -RUN echo "Acquire::CompressionTypes::Order \"bz2\";" > /etc/apt/apt.conf - -RUN apt-get clean && apt-get update - -RUN apt-get --no-install-recommends install -y --force-yes sudo=1.8.9p5-1ubuntu5 adduser=3.113+nmu3ubuntu3 apt=1.0.9.7ubuntu4 autoconf=2.69-8 automake=1:1.14.1-3ubuntu1 autotools-dev=20140911.1 base-files=7.2ubuntu9 base-passwd=3.5.37 bash=4.3-11ubuntu2 binutils=2.25-5ubuntu7 bison=2:3.0.2.dfsg-2 bsdutils=1:2.25.2-4ubuntu2 build-essential=11.6ubuntu6 ca-certificates-java=20140324 ccache=3.1.10-1 coreutils=8.23-3ubuntu1 cpp=4:4.9.2-2ubuntu2 cpp-4.9=4.9.2-10ubuntu13 dash=0.5.7-4ubuntu1 debconf=1.5.55ubuntu2 debianutils=4.4 debugedit=4.11.3-1.1 diffutils=1:3.3-1 dmsetup=2:1.02.90-2ubuntu1 dos2unix=6.0.4-1 dpkg=1.17.25ubuntu1 dpkg-dev=1.17.25ubuntu1 e2fslibs:amd64=1.42.12-1ubuntu2 e2fsprogs=1.42.12-1ubuntu2 fakeroot=1.20.2-1ubuntu1 file=1:5.20-1ubuntu2 findutils=4.4.2-9build1 flex=2.5.39-8 fontconfig=2.11.1-0ubuntu6 fontconfig-config=2.11.1-0ubuntu6 fonts-dejavu-core=2.34-1ubuntu1 g++=4:4.9.2-2ubuntu2 g++-4.9=4.9.2-10ubuntu13 gawk=1:4.1.1+dfsg-1 gcc=4:4.9.2-2ubuntu2 gcc-4.9=4.9.2-10ubuntu13 gcc-4.9-base:amd64=4.9.2-10ubuntu13 gcc-5-base:amd64=5.1~rc1-0ubuntu1 gdb=7.9-1ubuntu1 git=1:2.1.4-2.1 git-man=1:2.1.4-2.1 gnupg=1.4.18-7ubuntu1 golang=2:1.3.3-1ubuntu4 golang-doc=2:1.3.3-1ubuntu4 golang-go=2:1.3.3-1ubuntu4 golang-go-linux-amd64=2:1.3.3-1ubuntu4 golang-src=2:1.3.3-1ubuntu4 gperf=3.0.4-1 gpgv=1.4.18-7ubuntu1 grep=2.20-4.1 gyp=0.1~svn1729-3ubuntu1 gzip=1.6-4ubuntu1 hostname=3.15ubuntu2 init=1.22ubuntu11 init-system-helpers=1.22ubuntu11 initscripts=2.88dsf-53.2ubuntu12 insserv=1.14.0-5ubuntu3 java-common=0.52 libacl1:amd64=2.2.52-2 libapparmor1:amd64=2.9.1-0ubuntu9 libapt-pkg4.12:amd64=1.0.9.7ubuntu4 libasan1:amd64=4.9.2-10ubuntu13 libasn1-8-heimdal:amd64=1.6~rc2+dfsg-9 libasound2:amd64=1.0.28-1 libasound2-data=1.0.28-1 libasyncns0:amd64=0.8-5build1 libatk-wrapper-java=0.30.5-1 libatk-wrapper-java-jni:amd64=0.30.5-1 libatk1.0-0:amd64=2.14.0-1ubuntu1 libatk1.0-data=2.14.0-1ubuntu1 libatomic1:amd64=4.9.2-10ubuntu13 libattr1:amd64=1:2.4.47-2 libaudit-common=1:2.3.7-1ubuntu2 libaudit1:amd64=1:2.3.7-1ubuntu2 libavahi-client3:amd64=0.6.31-4ubuntu4 libavahi-common-data:amd64=0.6.31-4ubuntu4 libavahi-common3:amd64=0.6.31-4ubuntu4 libbison-dev:amd64=2:3.0.2.dfsg-2 libblkid1:amd64=2.25.2-4ubuntu2 libbsd-dev:amd64=0.7.0-2 libbsd0:amd64=0.7.0-2 libbz2-1.0:amd64=1.0.6-7 libc-ares-dev:amd64=1.10.0-2 libc-ares2:amd64=1.10.0-2 libc-bin=2.21-0ubuntu4 libc-dev-bin=2.21-0ubuntu4 libc6:amd64=2.21-0ubuntu4 libc6-dbg:amd64=2.21-0ubuntu4 libc6-dev:amd64=2.21-0ubuntu4 libcairo2:amd64=1.14.2-1ubuntu1 libcap2:amd64=1:2.24-6 libcap2-bin=1:2.24-6 libcilkrts5:amd64=4.9.2-10ubuntu13 libck-connector0:amd64=0.4.6-5 libcloog-isl4:amd64=0.18.2-3 libcomerr2:amd64=1.42.12-1ubuntu2 libcryptsetup4=2:1.6.1-1ubuntu7 libcups2:amd64=2.0.2-1ubuntu3 libcurl3-gnutls:amd64=7.38.0-3ubuntu2 libdatrie1:amd64=0.2.8-1 libdb5.3:amd64=5.3.28-9 libdbus-1-3:amd64=1.8.12-1ubuntu5 libdebconfclient0:amd64=0.192ubuntu1 libdevmapper1.02.1:amd64=2:1.02.90-2ubuntu1 libdpkg-perl=1.17.25ubuntu1 libdrm-intel1:amd64=2.4.60-2 libdrm-nouveau2:amd64=2.4.60-2 libdrm-radeon1:amd64=2.4.60-2 libdrm2:amd64=2.4.60-2 libedit-dev:amd64=3.1-20140620-2 libedit2:amd64=3.1-20140620-2 libelf1:amd64=0.160-0ubuntu3 liberror-perl=0.17-1.1 libexpat1:amd64=2.1.0-6ubuntu1 libfakeroot:amd64=1.20.2-1ubuntu1 libffi6:amd64=3.2.1-2 libfl-dev:amd64=2.5.39-8 libflac8:amd64=1.3.1-1ubuntu1 libfontconfig1:amd64=2.11.1-0ubuntu6 libfreetype6:amd64=2.5.2-2ubuntu3 libgcc-4.9-dev:amd64=4.9.2-10ubuntu13 libgcc1:amd64=1:5.1~rc1-0ubuntu1 libgcrypt20:amd64=1.6.2-4ubuntu2 libgdbm3:amd64=1.8.3-13.1 libgdk-pixbuf2.0-0:amd64=2.31.3-1 libgdk-pixbuf2.0-common=2.31.3-1 libgif4:amd64=4.1.6-11 libgl1-mesa-dri:amd64=10.5.2-0ubuntu1 libgl1-mesa-glx:amd64=10.5.2-0ubuntu1 libglapi-mesa:amd64=10.5.2-0ubuntu1 libglib2.0-0:amd64=2.44.0-1ubuntu3 libgmp10:amd64=2:6.0.0+dfsg-6ubuntu1 libgnutls-deb0-28:amd64=3.3.8-3ubuntu3 libgomp1:amd64=4.9.2-10ubuntu13 libgpg-error0:amd64=1.17-3ubuntu1 libgraphite2-3:amd64=1.2.4-3ubuntu1 libgssapi-krb5-2:amd64=1.12.1+dfsg-18 libgssapi3-heimdal:amd64=1.6~rc2+dfsg-9 libgtk2.0-0:amd64=2.24.27-0ubuntu1 libgtk2.0-common=2.24.27-0ubuntu1 libharfbuzz0b:amd64=0.9.37-1 libhcrypto4-heimdal:amd64=1.6~rc2+dfsg-9 libheimbase1-heimdal:amd64=1.6~rc2+dfsg-9 libheimntlm0-heimdal:amd64=1.6~rc2+dfsg-9 libhogweed2:amd64=2.7.1-5 libhx509-5-heimdal:amd64=1.6~rc2+dfsg-9 libicu52:amd64=52.1-8 libidn11:amd64=1.28-1ubuntu2 libintl-perl=1.23-1build2 libisl13:amd64=0.14-1 libitm1:amd64=4.9.2-10ubuntu13 libjasper1:amd64=1.900.1-debian1-2.4 libjbig0:amd64=2.1-3.1 libjpeg-turbo8:amd64=1.3.0-0ubuntu2 libjpeg8:amd64=8c-2ubuntu8 libjs-excanvas=0.r3-4 libjs-jquery=1.7.2+dfsg-3ubuntu2 libjs-node-uuid=1.4.0-1 libjs-underscore=1.7.0~dfsg-1ubuntu1 libjson-c2:amd64=0.11-4ubuntu2 libk5crypto3:amd64=1.12.1+dfsg-18 libkeyutils1:amd64=1.5.9-5ubuntu1 libkmod2:amd64=18-3ubuntu1 libkrb5-26-heimdal:amd64=1.6~rc2+dfsg-9 libkrb5-3:amd64=1.12.1+dfsg-18 libkrb5support0:amd64=1.12.1+dfsg-18 liblcms2-2:amd64=2.6-3ubuntu2 libldap-2.4-2:amd64=2.4.31-1+nmu2ubuntu12.3 libllvm3.6:amd64=1:3.6-2ubuntu1 liblsan0:amd64=4.9.2-10ubuntu13 liblua5.2-0:amd64=5.2.3-1.1 liblzma5:amd64=5.1.1alpha+20120614-2ubuntu2 libmagic1:amd64=1:5.20-1ubuntu2 libmono-corlib4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-corlib4.5-cil=3.2.8+dfsg-4ubuntu4 libmono-csharp4.0c-cil=3.2.8+dfsg-4ubuntu4 libmono-data-tds4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-microsoft-csharp4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-posix4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-security4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-system-configuration4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-system-core4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-system-data-datasetextensions4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-system-data-linq4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-system-data4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-system-enterpriseservices4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-system-runtime-serialization4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-system-security4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-system-transactions4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-system-xml-linq4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-system-xml4.0-cil=3.2.8+dfsg-4ubuntu4 libmono-system4.0-cil=3.2.8+dfsg-4ubuntu4 libmount1:amd64=2.25.2-4ubuntu2 libmpc3:amd64=1.0.3-1 libmpfr4:amd64=3.1.2-3 libncurses5:amd64=5.9+20140712-2ubuntu2 libncurses5-dev:amd64=5.9+20140712-2ubuntu2 libncursesw5:amd64=5.9+20140712-2ubuntu2 libnettle4:amd64=2.7.1-5 libnspr4:amd64=2:4.10.7-1ubuntu1 libnss3:amd64=2:3.17.4-0ubuntu1 libnss3-nssdb=2:3.17.4-0ubuntu1 libogg0:amd64=1.3.2-1 libp11-kit0:amd64=0.20.7-1 libpam-modules:amd64=1.1.8-3.1ubuntu3 libpam-modules-bin=1.1.8-3.1ubuntu3 libpam-runtime=1.1.8-3.1ubuntu3 libpam0g:amd64=1.1.8-3.1ubuntu3 libpango-1.0-0:amd64=1.36.8-3 libpangocairo-1.0-0:amd64=1.36.8-3 libpangoft2-1.0-0:amd64=1.36.8-3 libpciaccess0:amd64=0.13.2-3build1 libpcre3:amd64=2:8.35-3.3ubuntu1 libpcre3-dev:amd64=2:8.35-3.3ubuntu1 libpcrecpp0:amd64=2:8.35-3.3ubuntu1 libpcsclite1:amd64=1.8.11-3ubuntu1 libpixman-1-0:amd64=0.32.6-3 libpng12-0:amd64=1.2.51-0ubuntu3 libpopt0:amd64=1.16-10 libprocps3:amd64=1:3.3.9-1ubuntu8 libpulse0:amd64=1:6.0-0ubuntu6 libpython-stdlib:amd64=2.7.9-1 libpython2.7-minimal:amd64=2.7.9-2ubuntu3 libpython2.7-stdlib:amd64=2.7.9-2ubuntu3 libquadmath0:amd64=4.9.2-10ubuntu13 libreadline6:amd64=6.3-8ubuntu1 libroken18-heimdal:amd64=1.6~rc2+dfsg-9 librpm3=4.11.3-1.1 librpmbuild3=4.11.3-1.1 librpmio3=4.11.3-1.1 librpmsign1=4.11.3-1.1 librtmp1:amd64=2.4+20131018.git79459a2-5 libruby2.1:amd64=2.1.2-2ubuntu3 libsasl2-2:amd64=2.1.26.dfsg1-13ubuntu0.1 libsasl2-modules-db:amd64=2.1.26.dfsg1-13ubuntu0.1 libselinux1:amd64=2.3-2 libsemanage-common=2.3-1build1 libsemanage1:amd64=2.3-1build1 libsepol1:amd64=2.3-2 libsigsegv2:amd64=2.10-4 libslang2:amd64=2.3.0-2ubuntu1 libsmartcols1:amd64=2.25.2-4ubuntu2 libsndfile1:amd64=1.0.25-9.1 libsqlite3-0:amd64=3.8.7.4-1 libss2:amd64=1.42.12-1ubuntu2 libssl-dev:amd64=1.0.1f-1ubuntu11 libssl1.0.0:amd64=1.0.1f-1ubuntu11 libstdc++-4.9-dev:amd64=4.9.2-10ubuntu13 libstdc++-4.9-pic:amd64=4.9.2-10ubuntu13 libstdc++6:amd64=4.9.2-10ubuntu13 libsystemd0:amd64=219-7ubuntu3 libtasn1-6:amd64=4.2-2ubuntu1 libtext-unidecode-perl=1.22-1 libthai-data=0.1.21-1 libthai0:amd64=0.1.21-1 libtiff5:amd64=4.0.3-12.3ubuntu2 libtimedate-perl=2.3000-2 libtinfo-dev:amd64=5.9+20140712-2ubuntu2 libtinfo5:amd64=5.9+20140712-2ubuntu2 libtool=2.4.2-1.11 libtool-bin=2.4.2-1.11 libtsan0:amd64=4.9.2-10ubuntu13 libubsan0:amd64=4.9.2-10ubuntu13 libudev1:amd64=219-7ubuntu3 libusb-0.1-4:amd64=2:0.1.12-25 libustr-1.0-1:amd64=1.0.4-3ubuntu2 libuuid1:amd64=2.25.2-4ubuntu2 libv8-3.14-dev=3.14.5.8-5ubuntu2 libv8-3.14.5=3.14.5.8-5ubuntu2 libvorbis0a:amd64=1.3.4-2 libvorbisenc2:amd64=1.3.4-2 libwind0-heimdal:amd64=1.6~rc2+dfsg-9 libwrap0:amd64=7.6.q-25 libx11-6:amd64=2:1.6.2-2ubuntu2 libx11-data=2:1.6.2-2ubuntu2 libx11-xcb1:amd64=2:1.6.2-2ubuntu2 libxau6:amd64=1:1.0.8-1 libxcb-dri2-0:amd64=1.10-2ubuntu1 libxcb-dri3-0:amd64=1.10-2ubuntu1 libxcb-glx0:amd64=1.10-2ubuntu1 libxcb-present0:amd64=1.10-2ubuntu1 libxcb-render0:amd64=1.10-2ubuntu1 libxcb-shm0:amd64=1.10-2ubuntu1 libxcb-sync1:amd64=1.10-2ubuntu1 libxcb1:amd64=1.10-2ubuntu1 libxcomposite1:amd64=1:0.4.4-1 libxcursor1:amd64=1:1.1.14-1 libxdamage1:amd64=1:1.1.4-2 libxdmcp6:amd64=1:1.1.1-1build1 libxext6:amd64=2:1.3.3-1 libxfixes3:amd64=1:5.0.1-2 libxi6:amd64=2:1.7.4-1 libxinerama1:amd64=2:1.1.3-1 libxml-libxml-perl=2.0116+dfsg-1ubuntu0.15.04.1 libxml-namespacesupport-perl=1.11-1 libxml-sax-base-perl=1.07-1 libxml-sax-perl=0.99+dfsg-2ubuntu1 libxml2:amd64=2.9.2+dfsg1-3 libxrandr2:amd64=2:1.4.2-1 libxrender1:amd64=1:0.9.8-1build1 libxshmfence1:amd64=1.1-4 libxtst6:amd64=2:1.2.2-1 libxxf86vm1:amd64=1:1.1.3-1 libyaml-0-2:amd64=0.1.6-3 linux-libc-dev:amd64=3.19.0-15.15 locales=2.13+git20120306-19 login=1:4.1.5.1-1.1ubuntu4 lsb-base=4.1+Debian11ubuntu8 lsof=4.86+dfsg-1ubuntu2 m4=1.4.17-4 make=4.0-8.1 makedev=2.3.1-93ubuntu1 mawk=1.3.3-17ubuntu2 mercurial=3.1.2-2 mercurial-common=3.1.2-2 mime-support=3.58ubuntu1 mono-4.0-gac=3.2.8+dfsg-4ubuntu4 mono-dmcs=3.2.8+dfsg-4ubuntu4 mono-gac=3.2.8+dfsg-4ubuntu4 mono-mcs=3.2.8+dfsg-4ubuntu4 mono-runtime=3.2.8+dfsg-4ubuntu4 mono-runtime-common=3.2.8+dfsg-4ubuntu4 mono-runtime-sgen=3.2.8+dfsg-4ubuntu4 mount=2.25.2-4ubuntu2 multiarch-support=2.21-0ubuntu4 ncurses-base=5.9+20140712-2ubuntu2 ncurses-bin=5.9+20140712-2ubuntu2 node-abbrev=1.0.5-2 node-ansi=0.3.0-2 node-ansi-color-table=1.0.0-1 node-archy=0.0.2-1 node-async=0.8.0-1 node-block-stream=0.0.7-1 node-combined-stream=0.0.5-1 node-cookie-jar=0.3.1-1 node-delayed-stream=0.0.5-1 node-forever-agent=0.5.1-1 node-form-data=0.1.0-1 node-fstream=0.1.24-1 node-fstream-ignore=0.0.6-2 node-github-url-from-git=1.1.1-1 node-glob=4.0.5-1 node-graceful-fs=3.0.2-1 node-gyp=0.12.2+ds-1 node-inherits=2.0.1-1 node-ini=1.1.0-1 node-json-stringify-safe=5.0.0-1 node-lockfile=0.4.1-1 node-lru-cache=2.3.1-1 node-mime=1.2.11-1 node-minimatch=1.0.0-1 node-mkdirp=0.5.0-1 node-mute-stream=0.0.4-1 node-node-uuid=1.4.0-1 node-nopt=3.0.1-1 node-normalize-package-data=0.2.2-1 node-npmlog=0.0.4-1 node-once=1.1.1-1 node-osenv=0.1.0-1 node-qs=2.2.4-1 node-read=1.0.5-1 node-read-package-json=1.2.4-1 node-request=2.26.1-1 node-retry=0.6.0-1 node-rimraf=2.2.8-1 node-semver=2.1.0-2 node-sha=1.2.3-1 node-sigmund=1.0.0-1 node-slide=1.1.4-1 node-tar=0.1.18-1 node-tunnel-agent=0.3.1-1 node-underscore=1.7.0~dfsg-1ubuntu1 node-which=1.0.5-2 nodejs=0.10.25~dfsg2-2ubuntu1 nodejs-dev=0.10.25~dfsg2-2ubuntu1 npm=1.4.21+ds-2 openjdk-8-jdk:amd64=8u45-b14-1 openjdk-8-jre:amd64=8u45-b14-1 openjdk-8-jre-headless:amd64=8u45-b14-1 openssh-client=1:6.7p1-5ubuntu1 openssh-server=1:6.7p1-5ubuntu1 openssh-sftp-server=1:6.7p1-5ubuntu1 openssl=1.0.1f-1ubuntu11 passwd=1:4.1.5.1-1.1ubuntu4 patch=2.7.5-1 perl=5.20.2-2 perl-base=5.20.2-2 perl-modules=5.20.2-2 php-pear=5.6.4+dfsg-4ubuntu6 php5-cli=5.6.4+dfsg-4ubuntu6 php5-common=5.6.4+dfsg-4ubuntu6 php5-dev=5.6.4+dfsg-4ubuntu6 php5-json=1.3.6-1build1 procps=1:3.3.9-1ubuntu8 psmisc=22.21-2build1 python=2.7.9-1 python-chardet=2.3.0-1 python-colorama=0.3.2-1 python-distlib=0.1.9-1 python-gevent=1.0.1-2 python-greenlet=0.4.5-1ubuntu1 python-html5lib=0.999-3 python-minimal=2.7.9-1 python-pip=1.5.6-5ubuntu2 python-pkg-resources=12.2-1 python-requests=2.4.3-6 python-setuptools=12.2-1 python-six=1.9.0-1 python-urllib3=1.9.1-3 python-yaml=3.11-2 python2.7=2.7.9-2ubuntu3 python2.7-minimal=2.7.9-2ubuntu3 readline-common=6.3-8ubuntu1 rpm=4.11.3-1.1 rpm-common=4.11.3-1.1 rpm2cpio=4.11.3-1.1 rsync=3.1.1-3 ruby=1:2.1.0.4ubuntu1 ruby2.1=2.1.2-2ubuntu3 rubygems-integration=1.8 sed=4.2.2-4ubuntu1 sensible-utils=0.0.9 shared-mime-info=1.3-1 shtool=2.0.8-6 ssh=1:6.7p1-5ubuntu1 systemd=219-7ubuntu3 systemd-sysv=219-7ubuntu3 sysv-rc=2.88dsf-53.2ubuntu12 sysvinit-utils=2.88dsf-53.2ubuntu12 tar=1.27.1-2 texinfo=5.2.0.dfsg.1-6 tzdata=2015c-1 tzdata-java=2015c-1 ubuntu-keyring=2012.05.19 ucf=3.0030 udev=219-7ubuntu3 unzip=6.0-13ubuntu3 util-linux=2.25.2-4ubuntu2 valgrind=1:3.10.1-1ubuntu2 wget=1.16.1-1ubuntu1 x11-common=1:7.7+7ubuntu4 xz-utils=5.1.1alpha+20120614-2ubuntu2 zlib1g:amd64=1:1.2.8.dfsg-2ubuntu1 zlib1g-dev:amd64=1:1.2.8.dfsg-2ubuntu1 golang-go.tools=0.0~hg20140703-4 curl=7.38.0-3ubuntu2.3 sphinx-common=1.2.3+dfsg-1ubuntu2 distcc=3.1-6.1 clang=1:3.6-26ubuntu1 && apt-get clean - -RUN adduser --disabled-password --gecos '' fdb - -RUN chown -R fdb /opt - -RUN chmod -R 0777 /opt +RUN adduser --disabled-password --gecos '' fdb && chown -R fdb /opt && chmod -R 0777 /opt USER fdb RUN cd /opt/ && wget http://downloads.sourceforge.net/project/boost/boost/1.52.0/boost_1_52_0.tar.bz2 -qO - | tar -xj -RUN mkdir -p /home/fdb/.ssh /opt/ct /opt/cross-build /opt/x-toolchain - -RUN cd /opt/ && wget http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.21.0.tar.bz2 -qO - | tar -xj - -RUN cd /opt/crosstool-ng-1.21.0 && ./configure --prefix=/opt/ct && make && make install - -RUN mkdir -p /opt/cross-build/samples/x86_64-nptl-linux-gnu/ - -ADD ct.config.fdb /opt/cross-build/samples/x86_64-nptl-linux-gnu/crosstool.config - -RUN touch /opt/cross-build/samples/x86_64-nptl-linux-gnu/reported.by - -RUN cd /opt/cross-build && /opt/ct/bin/ct-ng x86_64-nptl-linux-gnu - -RUN mkdir -p /opt/cross-build/.tarballs - -RUN ((cd /opt/cross-build && /opt/ct/bin/ct-ng build && rm -rf /opt/cross-build /opt/crosstool-ng-1.21.0 /opt/ct) || (cat /opt/cross-build/build.log && false)) - -RUN cd /opt/ && wget http://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.9.tar.gz -qO - | tar -xz && cd /opt/ncurses-5.9 && ./configure CC=/opt/x-toolchain/bin/x86_64-nptl-linux-gnu-gcc CFLAGS=-fPIC --prefix=/opt/libncurses && make && make install && cd /opt && rm -rf ncurses-5.9 - -RUN cd /opt/ && wget http://thrysoee.dk/editline/libedit-20150325-3.1.tar.gz -qO - | tar -xz && cd /opt/libedit-20150325-3.1 && ./configure CC=/opt/x-toolchain/bin/x86_64-nptl-linux-gnu-cc CFLAGS=-fPIC LDFLAGS="-L/opt/libncurses/lib" --prefix=/opt/libedit && make && make install && cd /opt && rm -rf libedit-20150325-3.1 - -RUN ln -s /opt/libncurses/lib/libncurses.a /opt/libncurses/lib/libtinfo.a - USER root -RUN ln -s /opt/x-toolchain/lib/gcc/x86_64-nptl-linux-gnu/4.9.1/../../../../x86_64-nptl-linux-gnu/lib/../lib64/libstdc++.a /opt/x-toolchain/lib/gcc/x86_64-nptl-linux-gnu/4.9.1/../../../../x86_64-nptl-linux-gnu/lib/../lib64/libstdc++_pic.a - RUN pip install boto3==1.1.1 RUN npm install -g npm@3.4.1 @@ -57,3 +21,9 @@ RUN ln -s /usr/bin/nodejs /usr/bin/node RUN LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 locale-gen en_US.UTF-8 RUN dpkg-reconfigure locales + +ARG TARGET_LIBC_VERSION=2.17 +ENV TARGET_LIBC_VERSION=$TARGET_LIBC_VERSION + +ARG CC=/usr/bin/gcc +ENV CC=$CC diff --git a/build/tarball.py b/build/tarball.py deleted file mode 100644 index e440cfe9d8..0000000000 --- a/build/tarball.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/python -# -# tarball.py -# -# This source file is part of the FoundationDB open source project -# -# Copyright 2013-2018 Apple Inc. and the FoundationDB project authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -import tarfile -import argparse -import glob - - -def createTarball(outFile, rootDir, inFiles): - tar = tarfile.open(outFile, 'w:gz') - for fStr in inFiles: - for f in glob.glob(fStr): - if rootDir is None: - tar.add(f) - else: - tar.add(f, rootDir + "/" + f) - - tar.close() - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Python tar utility') - parser.add_argument('-r', dest='rootDir', type=str, help='The root directory for files in the tarball') - parser.add_argument('outFile', type=str, help='The output tarball') - parser.add_argument('inFile', type=str, nargs='+', help='The files to put into the tarball') - - args = parser.parse_args() - createTarball(args.outFile, args.rootDir, args.inFile) diff --git a/documentation/sphinx/source/administration.rst b/documentation/sphinx/source/administration.rst index 0f165ace0d..46f297fd0f 100644 --- a/documentation/sphinx/source/administration.rst +++ b/documentation/sphinx/source/administration.rst @@ -611,7 +611,7 @@ For **RHEL/CentOS**, perform the upgrade using the rpm command: user@host$ sudo rpm -Uvh |package-rpm-clients| \\ |package-rpm-server| -The ``foundationdb-clients`` package also installs the :doc:`Python ` and :doc:`C ` APIs. If your clients use :doc:`Ruby `, `Java `_, :doc:`Node.js `, or `Go `_, follow the instructions in the corresponding language documentation to install the APIs. +The ``foundationdb-clients`` package also installs the :doc:`Python ` and :doc:`C ` APIs. If your clients use :doc:`Ruby `, `Java `_, or `Go `_, follow the instructions in the corresponding language documentation to install the APIs. Test the database ----------------- diff --git a/documentation/sphinx/source/api-common.rst.inc b/documentation/sphinx/source/api-common.rst.inc index 1574c6c3d1..71dbbb2561 100644 --- a/documentation/sphinx/source/api-common.rst.inc +++ b/documentation/sphinx/source/api-common.rst.inc @@ -443,7 +443,6 @@ .. |directory-create-or-open-blurb| replace:: Opens the directory with ``path`` specified as |dir-path-type| of strings. ``path`` can also be a string, in which case it will be automatically wrapped in |dir-path-type|. All string values in a path will be converted to unicode. If the directory does not exist, it is created (creating parent directories if necessary). -.. **NOTE** this blurb is not used in api-node .. |directory-create-or-open-return-blurb| replace:: Returns the directory and its contents as a |directory-subspace|. @@ -456,7 +455,6 @@ .. |directory-move-blurb| replace:: Moves the directory at ``old_path`` to ``new_path``. There is no effect on the physical prefix of the given directory or on clients that already have the directory open. The method will |error-raise-type| an |error-type| if a directory does not exist at ``old_path``, a directory already exists at ``new_path``, or the parent directory of ``new_path`` does not exist. -.. **NOTE** this blurb is not used in api-node .. |directory-move-return-blurb| replace:: Returns the directory at its new location as a |directory-subspace|. diff --git a/documentation/sphinx/source/api-node.rst b/documentation/sphinx/source/api-node.rst deleted file mode 100644 index a668f3e098..0000000000 --- a/documentation/sphinx/source/api-node.rst +++ /dev/null @@ -1,1555 +0,0 @@ -.. default-domain:: js -.. highlight:: javascript - -.. Required substitutions for api-common.rst.inc - -.. |database-type| replace:: ``Database`` -.. |database-class| replace:: :class:`Database` -.. |database-auto| replace:: :func:`Database.doTransaction` -.. |transaction-class| replace:: :class:`Transaction` -.. |get-key-func| replace:: :func:`Transaction.getKey` -.. |get-range-func| replace:: :func:`Transaction.getRange` -.. |commit-func| replace:: :func:`Transaction.commit` -.. |reset-func-name| replace:: :func:`reset ` -.. |reset-func| replace:: :func:`Transaction.reset` -.. |cancel-func| replace:: :func:`Transaction.cancel` -.. |init-func| replace:: :func:`fdb.init` -.. |open-func| replace:: :func:`fdb.open` -.. |on-error-func| replace:: :func:`Transaction.onError` -.. |null-type| replace:: ``null`` or ``undefined`` -.. |error-type| replace:: error -.. |error-raise-type| replace:: respond with -.. |future-cancel| replace:: :func:`Future.cancel` -.. |max-watches-database-option| replace:: :func:`Database.options.setMaxWatches` -.. |future-type-string| replace:: a :ref:`future ` -.. |read-your-writes-disable-option| replace:: :func:`Transaction.options.setReadYourWritesDisable` -.. |lazy-iterator-object| replace:: :class:`LazyIterator` -.. |key-meth| replace:: :func:`Subspace.key` -.. |directory-subspace| replace:: :ref:`DirectorySubspace ` -.. |directory-layer| replace:: :class:`DirectoryLayer ` -.. |subspace| replace:: :class:`Subspace ` -.. |subspace-api| replace:: :ref:`subspaces ` -.. |as-foundationdb-key| replace:: :func:`asFoundationDBKey` -.. |as-foundationdb-value| replace:: :func:`asFoundationDBValue` -.. |tuple-layer| replace:: :ref:`tuple layer ` -.. |dir-path-type| replace:: an array -.. |node-subspace| replace:: ``nodeSubspace`` -.. |content-subspace| replace:: ``contentSubspace`` -.. |allow-manual-prefixes| replace:: ``allowManualPrefixes`` - -.. include:: api-common.rst.inc - -########### -Node.js API -########### - -.. |infrequent| replace:: *Infrequently used*. -.. |asynchronous-function| replace:: This function is asynchronous -.. |callback| replace:: |asynchronous-function|. When complete, :ref:`callback ` will be called -.. |callback-when| replace:: |asynchronous-function|. :ref:`callback ` will be called -.. |if-no-callback| replace:: If the :ref:`callback ` argument is omitted, then the function will return a :class:`Future` object that can be used to access the result. -.. |if-no-callback-no-result| replace:: If the :ref:`callback ` argument is omitted, then the function will return a :class:`Future` object that can be used to wait for completion. - -Installation -============ - -You can download the FoundationDB Node.js API directly from :doc:`downloads`. - -.. note:: |separately-installed-bindings| -.. note:: |project-dependency| - -API versioning -============== - -When you require the ``fdb`` module, it exposes only one useful symbol: - -.. function:: apiVersion(version) - - Returns the FoundationDB module corresponding with a particular API version. This allows future versions of FoundationDB to make API changes without breaking existing programs. The current version of the API is |api-version|. - - For example:: - - var fdb = require('fdb').apiVersion(510) - - | **Throws** an error if the specified version is not supported. - | **Throws** an error if ``apiVersion`` has been called previously with a different version. - -.. note:: You must call ``apiVersion(...)`` to get access to the fdb module. - -.. note:: |api-version-rationale| - -.. warning:: |api-version-multi-version-warning| - -For API changes between version 14 and |api-version| (for the purpose of porting older programs), see :doc:`release-notes`. - -Opening a database -================== - -After importing the ``fdb`` module and selecting an API version, you probably want to open a :class:`Database`. The simplest way of doing this is using |open-func| :: - - var fdb = require('fdb').apiVersion(510) - var db = fdb.open(); - -.. function:: fdb.open( [clusterFile, dbName] ) - - |fdb-open-blurb| - - Returns a :class:`Database` object. - - .. note:: In this release, dbName must be "DB". - - .. note:: ``fdb.open()`` combines the effect of :func:`fdb.init`, :func:`fdb.createCluster`, and :func:`Cluster.openDatabase`. - - **Throws** an error if the network was unable to be initialized, the cluster could not be created, or the database could not be opened. However, a database that is unavailable does *not* cause an error to be thrown. - -.. function:: fdb.init() - - Initializes the FoundationDB API, creating a thread for the FoundationDB client and initializing the client's networking engine. |init-func| can only be called once. If called subsequently or after |open-func| , it will raise a ``client_invalid_operation`` error. - - **Throws** an error if the network was unable to be initialized. - -.. function:: fdb.createCluster( [clusterFile] ) - - Connects to the cluster specified by :ref:`clusterFile `, or by a :ref:`default cluster file ` if ``clusterFile`` is null or undefined. - - Returns a :class:`Cluster` object. - - **Throws** an error if the cluster could not be created. - -.. attribute:: fdb.options - - |network-options-blurb| - - .. note:: |network-options-warning| - - .. function:: fdb.options.setTraceEnable(outputDirectory) - - |option-trace-enable-blurb| - - .. warning:: |option-trace-enable-warning| - - .. function:: fdb.options.setTraceMaxLogsSize(bytes) - - |option-trace-max-logs-size-blurb| - - .. function:: fdb.options.setTraceRollSize(bytes) - - |option-trace-roll-size-blurb| - - .. function :: fdb.options.setDisableMultiVersionClientApi() - - |option-disable-multi-version-client-api| - - .. function :: fdb.options.setCallbacksOnExternalThreads() - - |option-callbacks-on-external-threads| - - .. function :: fdb.options.setExternalClientLibrary(pathToLib) - - |option-external-client-library| - - .. function :: fdb.options.setExternalClientDirectory(pathToLibDirectory) - - |option-external-client-directory| - -Cluster objects -=============== - -.. class:: Cluster - -.. function:: Cluster.openDatabase( [name="DB"] ) - - Opens a database with the given name. - - Returns a :class:`Database` object. - - .. note:: In this release, name **must** be "DB". - - **Throws** an error if the database could not be opened. - -.. _api-node-keys: -.. _dataTypes: - -Keys and values -=============== - -Keys and values in FoundationDB are byte arrays stored in `Node.js Buffers `_. Functions which take keys and values as arguments can also accept JavaScript strings, which will be encoded using the UTF-8 encoding, or ArrayBuffers. The ``fdb`` module also provides some convenience methods for converting to and from Buffers in :attr:`fdb.buffer`. - -|keys-values-other-types-blurb| - -``asFoundationDBKey`` and ``asFoundationDBValue`` -------------------------------------------------- - -|as-foundationdb-blurb| - -.. warning :: |as-foundationdb-warning| - -Buffer conversion -================= - -FoundationDB uses Node.js Buffers for all :ref:`keys and values `. The ``fdb.buffer`` functions provide some utilities for converting other data types to and from Node.js Buffers. - -.. function:: fdb.buffer(obj) - - Converts ``obj`` to a Node.js Buffer, assuming it is of an appropriate type. This is called automatically for any key or value passed to the :class:`Transaction` functions. The supported types are: - - * ``Buffer`` - ``obj`` is returned unchanged - * ``ArrayBuffer`` - ``obj`` is copied to a new ``Buffer`` - * ``Uint8Array`` - ``obj`` is copied to a new ``Buffer`` - * ``string`` - ``obj`` is encoded using UTF-8 and returned as a ``Buffer`` - -.. function:: fdb.buffer.fromByteLiteral(str) - - Attempts to interpret the string ``str`` as a byte-literal string by converting each character to its one-byte character code using ``str.charCodeAt()``. Returns the result as a Node.js ``Buffer``. - - **Throws** an error if ``str`` contains any multi-byte characters. - - .. note :: This should not be used for encoding unicode strings. Instead, use ``new Buffer(str)`` or consider using the :attr:`fdb.tuple` layer. - -.. function:: fdb.buffer.toByteLiteral(buffer) - - Converts a Node.js ``Buffer`` to a byte-literal string by converting each byte to a character using ``String.fromCharCode()``. - - .. note :: This should not be used for decoding unicode strings. Instead, use ``buffer.toString()`` or consider using the :attr:`fdb.tuple` layer. - -.. _keyValuePairs: - -Key-value pairs -=============== - -.. class:: KeyValuePair - -A class that holds the key and value of a single entry in the database. Each of the :class:`Transaction` range query function returns a :class:`LazyIterator` of key-value pairs. - -.. attribute:: key - - A :ref:`Buffer ` containing the key. - -.. attribute:: value - - A :ref:`Buffer ` containing the value. - -Key selectors -============= - -|keysel-blurb1| - -|keysel-blurb2| - -.. class:: fdb.KeySelector(key, orEqual, offset) - - Creates a key selector with the given reference :ref:`key `, equality flag, and offset. It is usually more convenient to obtain a key selector with one of the following methods: - - .. function:: fdb.KeySelector.lastLessThan(key) - - Returns a key selector referencing the last (greatest) key in the database less than the specified :ref:`key `. - - .. function:: fdb.KeySelector.lastLessOrEqual(key) - - Returns a key selector referencing the last (greatest) key less than or equal to the specified :ref:`key `. - - .. function:: fdb.KeySelector.firstGreaterThan(key) - - Returns a key selector referencing the first (least) key greater than the specified :ref:`key `. - - .. function:: fdb.KeySelector.firstGreaterOrEqual(key) - - Returns a key selector referencing the first key greater than or equal to the specified :ref:`key `. - -``KeySelector`` objects have the following members: - -.. function:: KeySelector.next() - - Returns a key selector referencing the key after the one referenced by this key selector. - -.. function:: KeySelector.prev() - - Returns a key selector referencing the key before the one referenced by this key selector. - -.. function:: KeySelector.add(addOffset) - - Returns a key selector referencing the key with offset ``addOffset`` relative to this one. - -Database objects -================ - -.. class:: Database - -A |database-blurb1| |database-blurb2| - -.. function:: Database.doTransaction( func[, callback] ) - - Executes the provided function ``func`` with a new transaction, commits the transaction, retries the function as necessary in response to retryable database errors, and calls ``callback`` with the result produced by ``func``. This is the recommended way to do operations transactionally. - - ``func`` must take a :class:`Transaction` as its first argument and an inner :ref:`callback ` as its second argument. - - .. note:: Note that the ``callback`` passed to :func:`doTransaction` and the inner callback passed to ``func`` are distinct. - - ``Database.doTransaction`` is asynchronous. When the transaction has been committed, :ref:`callback ` will be called with the result produced by ``func``. |if-no-callback| Without suppling a ``callback`` to :func:`doTransaction` or its resulting future, the calling code cannot determine if the transaction resulted in an error or even finished. - - The inner callback passed to ``func`` must be called for the transaction to commit or retry on errors. In particular, this inner callback requires the following: - - * Any FoundationDB API error encountered within ``func`` must be passed to the inner callback as its first argument. Calling the inner callback with any other error will cancel the transaction and pass the error to the outer level. - * If no errors are encountered, then any result produced by ``func`` must be passed to the inner callback as its second argument. If ``func`` is not intended to produce a result, the inner callback must be called with no arguments. - - .. note:: |fdb-transactional-unknown-result-note| - - Here is an example of the use of :func:`doTransaction`, where ``db`` is a :class:`Database`:: - - db.doTransaction(function(tr, innerCallback) { - tr.get('a', function(err, val) { - - //Errors must be passed back to the callback for retry logic to work! - if(err) return innerCallback(err); - - tr.set('b', val); - innerCallback(null, val); - }); - }, function(err, val) { - if(err) - console.log('transaction failed: ', err) - else - console.log('finished transaction: ', val); - }); - - The above will get the value at key ``'a'`` and set it at key ``'b'`` in the database. Once the transaction has committed, it will print 'finished transaction: '. - - Functions can be made to automatically invoke :func:`doTransaction` by using the :func:`fdb.transactional` function. - -.. function:: Database.createTransaction() - - Returns a new :class:`Transaction` object. Consider using the :func:`Database.doTransaction` or :func:`fdb.transactional` functions to create transactions instead, since they will automatically provide you with appropriate retry behavior. - - **Throws** an error if the transaction could not be created. - -.. function:: Database.get( key[, callback] ) - - Gets a value associated with the specified :ref:`key ` in the database. This operation will be executed in a :func:`Database.doTransaction` error retry loop. - - |callback| with a Buffer containing the requested value or ``null`` if the key does not exist. |if-no-callback| - -.. function:: Database.getKey( keySelector[, callback] ) - - Gets the key referenced by the specified :class:`KeySelector() `. This operation will be executed in a :func:`Database.doTransaction` error retry loop. - - |database-get-key-caching-blurb| - - |callback| with a Buffer containing the requested key. |if-no-callback| - -.. function:: Database.getRange( begin, end[, options, callback] ) - - Gets all keys ``k`` such that ``begin <= k < end`` and their associated values as an array of :ref:`key-value pairs `. Note the exclusion of ``end`` from the range. This operation will be executed in a :func:`Database.doTransaction` error retry loop. - - Each of ``begin`` and ``end`` may be a :ref:`key ` or a :class:`KeySelector() `. Note that in the case of a :class:`KeySelector`, the exclusion of ``end`` from the range still applies. - - If the ``options`` object is specified, it can have the following optional parameters: - - ``options.limit`` - Only the first ``limit`` keys (and their values) in the range will be returned. If unspecified, defaults to having no limit. - - ``options.reverse`` - If ``true``, then the keys in the range will be returned in reverse order. If unspecified, defaults to ``false``. - - ``options.streamingMode`` - A value from :attr:`fdb.streamingMode` which provides a hint to FoundationDB about how to retrieve the specified range. This option should generally not be specified, allowing FoundationDB to retrieve the full range very efficiently. - - |callback| with an array containing the requested :ref:`key-value pairs `. |if-no-callback| - -.. function:: Database.getRangeStartsWith( prefix[, options, callback] ) - - Gets all keys ``k`` such that ``k`` begins with :ref:`keyPrefix `, and their associated values, as an array of :ref:`key-value pairs `. This operation will be executed in a :func:`Database.doTransaction` error retry loop. - - If the ``options`` object is specified, it can have the following optional parameters: - - ``options.limit`` - Only the first ``limit`` keys (and their values) in the range will be returned. If unspecified, defaults to having no limit. - - ``options.reverse`` - If ``true``, then the keys in the range will be returned in reverse order. If unspecified, defaults to ``false``. - - ``options.streamingMode`` - A value from :attr:`fdb.streamingMode` which provides a hint to FoundationDB about how to retrieve the specified range. This option should generally not be specified, allowing FoundationDB to retrieve the full range very efficiently. - - |callback| with an array containing the requested :ref:`key-value pairs `. |if-no-callback| - -.. function:: Database.set( key, value[, callback] ) - - Associates the given :ref:`key ` and :ref:`value ` and commits the result. Overwrites any prior value associated with ``key``. This operation will be executed in a :func:`Database.doTransaction` error retry loop. - - |callback-when| once the transaction has been committed. |if-no-callback-no-result| - -.. function:: Database.clear( key[, callback] ) - - Removes the specified :ref:`key ` (and any associated value) if it exists and commits the result. This operation will be executed in a :func:`Database.doTransaction` error retry loop. - - |callback-when| once the transaction has been committed. |if-no-callback-no-result| - -.. function:: Database.clearRange( begin, end[, callback] ) - - Removes all keys ``k`` such that :ref:`begin ` <= k < :ref:`end `, and their associated values, and commits the result. This operation will be executed in a :func:`Database.doTransaction` error retry loop. - - .. note :: Unlike in the case of :func:`Database.getRange`, ``begin`` and ``end`` must be :ref:`keys `, not :class:`KeySelector()s`. - - |callback-when| once the transaction has been committed. |if-no-callback-no-result| - -.. function:: Database.clearRangeStartsWith( prefix[, callback] ) - - Removes all the keys ``k`` such that ``k`` begins with :ref:`keyPrefix `, and their associated values, and commits the result. This operation will be executed in a :func:`Database.doTransaction` error retry loop. - - |callback-when| once the transaction has been committed. |if-no-callback-no-result| - -.. function:: Database.getAndWatch( key[, callback] ) - - Returns an object ``{value, watch}``, where ``value`` is the value associated with ``key`` or ``null`` if the key does not exist, and ``watch`` is a :ref:`future ` that will become ready after ``value`` changes. - - See :func:`Transaction.watch` for a general description of watches and their limitations. - - |asynchronous-function|. When the watch has been committed, :ref:`callback ` will be called with an object ``{value, watch}`` containing the value stored at ``key`` along with the watch :ref:`future `. |if-no-callback| - -.. _api-node-setAndWatch: - -.. function:: Database.setAndWatch( key, value[, callback] ) - - Sets ``key`` to ``value`` and returns an object ``{watch}``, where ``watch`` is a :ref:`future ` that will become ready after a subsequent change to ``value``. - - See :func:`Transaction.watch` for a general description of watches and their limitations. - - |asynchronous-function|. When the watch has been committed, :ref:`callback ` will be called with an object ``{watch}`` containing the watch :ref:`future `. |if-no-callback| - -.. function:: Database.clearAndWatch( key[, callback] ) - - Removes ``key`` (and any associated value) if it exists and returns an object ``{watch}``, where ``watch`` is a :ref:`future ` that will become ready after the value is subsequently set. - - See :func:`Transaction.watch` for a general description of watches and their limitations. - - |asynchronous-function|. When the watch has been committed, :ref:`callback ` will be called with an object ``{watch}`` containing the watch :ref:`future `. |if-no-callback| - -.. function:: Database.add(key, param, callback) -.. function:: Database.bit_and(key, param, callback) -.. function:: Database.bit_or(key, param, callback) -.. function:: Database.bit_xor(key, param, callback) - - Executes the :ref:`associated atomic operation ` on a :class:`Transaction` and commits the result. These operations are each executed in a :func:`Database.doTransaction` error retry loop. - - |callback-when| once the transaction has been committed. |if-no-callback-no-result| - - .. note :: |database-atomic-ops-idempotency-note| - -Database options ----------------- - -|database-options-blurb| - -.. function:: Database.options.setLocationCacheSize( size ) - - |option-location-cache-size-blurb| - -.. function:: Database.options.setMaxWatches( maxWatches ) - - |option-max-watches-blurb| - -.. function:: Database.options.setMachineId( id ) - - |option-machine-id-blurb| - -.. function:: Database.options.setDatacenterId( id ) - - |option-datacenter-id-blurb| - -Transactional decoration -======================== - -.. function:: fdb.transactional( func ) - - The ``fdb.transactional`` decorator wraps a function ``func`` with logic to automatically create a transaction and retry until success, producing a transactional function. - - Here is an example use:: - - //Gets the value at key1 and sets it at key2. Returns the value that was set - var transactionalFunction = fdb.transactional( - function(tr, key1, key2, callback) { - tr.get(key1, function(err, val) { - - //Errors must be passed back to the callback for retry logic to work! - if(err) return callback(err); - - tr.set(key2, val); - callback(null, val); - }); - }); - - Any function ``func`` decorated by ``fdb.transactional`` must take a :class:`Transaction` as its first argument and a :ref:`callback ` as its last. The callback must be called for the transaction to commit or retry on errors. In particular, this callback requires that: - - * Any FoundationDB API error encountered within ``func`` must be passed to the callback as its first argument. Calling the callback with any other error will cancel the transaction and pass the error to the outer level. - * If no errors are encountered, then any result produced by ``func`` must be passed to the callback as its second argument. If ``func`` is not intended to produce a result, the callback must be called with no arguments. - - There are several options for invoking the transactional function produced by ``fdb.transactional``. - - * The transactional function can be passed a :class:`Database` as its first argument. In this case, a :class:`Transaction` will be created, passed to ``func``, and be committed before returning to the caller. Any :func:`retryable error ` must be passed to the callback by ``func`` as described above, allowing ``func`` to be retried until the transaction successfully commits. - * The transactional function can be passed a :class:`Transaction` as its first argument. In this case, the transactional function will not attempt to commit or retry the transaction on error. Rather, commit and retry are the responsibility of the caller that owns the transaction. This option allows transactional functions to be freely composed. - * The transactional function can be invoked without a callback argument. In this case, it will return a :ref:`Future `. - - .. note:: |fdb-transactional-unknown-result-note| - -Transaction objects -=================== - -.. class:: Transaction - -A ``Transaction`` object represents a FoundationDB database transaction. All operations on FoundationDB take place, explicitly or implicitly, through a ``Transaction``. - -|transaction-blurb1| - -|transaction-blurb2| - -|transaction-blurb3| - -The most convenient way to use transactions is to use either the :func:`Database.doTransaction` function or the :func:`fdb.transactional` decorator function. - -Attributes ----------- - -.. attribute:: Transaction.db - - |db-attribute-blurb| - -Reading data ------------- - -.. function:: Transaction.get(key[, callback]) - - Gets a value associated with the specified :ref:`key ` in the database. - - |callback| with a Buffer containing the requested value or ``null`` if the key does not exist. |if-no-callback| - -.. function:: Transaction.getKey(keySelector[, callback]) - - Gets the key referenced by the specified :class:`KeySelector() `. - - |transaction-get-key-caching-blurb| - - |callback| with a Buffer containing the requested key. |if-no-callback| - -.. function:: Transaction.getRange(begin, end[, options]) - - Returns all keys ``k`` such that ``begin <= k < end`` and their associated values as a :class:`LazyIterator` of :ref:`key-value pairs `. Note the exclusion of ``end`` from the range. - - Each of ``begin`` and ``end`` may be a :ref:`key ` or a :class:`KeySelector() `. Note that in the case of a :class:`KeySelector`, the exclusion of ``end`` from the range still applies. - - If the ``options`` object is specified, it can have the following optional parameters: - - ``options.limit`` - Only the first ``limit`` keys (and their values) in the range will be returned. If unspecified, defaults to having no limit. - - ``options.reverse`` - If ``true``, then the keys in the range will be returned in reverse order. If unspecified, defaults to ``false``. - - ``options.streamingMode`` - A value from :attr:`fdb.streamingMode` which provides a hint to FoundationDB about how the returned iterator is likely to be used. If unspecified, defaults to :attr:`fdb.streamingMode.iterator`. - -.. function:: Transaction.getRangeStartsWith(keyPrefix[, options]) - - Returns all keys ``k`` such that ``k`` begins with :ref:`keyPrefix `, and their associated values, as a :class:`LazyIterator` of :ref:`key-value pairs `. - - If the ``options`` object is specified, it can have the following optional parameters: - - ``options.limit`` - Only the first ``limit`` keys (and their values) in the range will be returned. If unspecified, defaults to having no limit. - - ``options.reverse`` - If ``true``, then the keys in the range will be returned in reverse order. If unspecified, defaults to ``false``. - - ``options.streamingMode`` - A value from :attr:`fdb.streamingMode` which provides a hint to FoundationDB about how the returned iterator is likely to be used. If unspecified, defaults to :attr:`fdb.streamingMode.iterator`. - -Snapshot reads --------------- - -.. attribute:: Transaction.snapshot - - |snapshot-blurb1| - - |snapshot-blurb2| - - |snapshot-blurb3| - - |snapshot-blurb4| - -.. attribute:: Transaction.snapshot.db - - |db-attribute-blurb| - -.. function:: Transaction.snapshot.get(key[, callback]) - - Like :func:`Transaction.get`, but as a snapshot read. - -.. function:: Transaction.snapshot.getKey(keySelector[, callback]) - - Like :func:`Transaction.getKey`, but as a snapshot read. - -.. function:: Transaction.snapshot.getRange(begin, end[, options]) - - Like :func:`Transaction.getRange`, but as a snapshot read. - -.. function:: Transaction.snapshot.getRangeStartsWith(keyPrefix[, options]) - - Like :func:`Transaction.getRangeStartsWith`, but as a snapshot read. - -.. function:: Transaction.snapshot.getReadVersion([callback]) - - Identical to :func:`Transaction.getReadVersion` (since snapshot and serializable reads use the same read version). - -Writing Data ------------- - -.. function:: Transaction.set(key, value) - - Associates the given :ref:`key ` and :ref:`value `. Overwrites any prior value associated with ``key``. Returns immediately, having modified the snapshot represented by this ``Transaction``. - -.. function:: Transaction.clear(key) - - Removes the specified :ref:`key ` (and any associated value), if it exists. Returns immediately, having modified the snapshot represented by this ``Transaction``. - -.. function:: Transaction.clearRange(begin, end) - - Removes all keys ``k`` such that :ref:`begin ` <= k < :ref:`end `, and their associated values. Returns immediately, having modified the snapshot represented by this ``Transaction``. - - .. note :: Unlike in the case of :func:`Transaction.getRange`, ``begin`` and ``end`` must be :ref:`keys `, not :class:`KeySelector()s`. (Resolving arbitrary key selectors would prevent this method from returning immediately, introducing concurrency issues.) - -.. function:: Transaction.clearRangeStartsWith(prefix) - - Removes all the keys ``k`` such that ``k`` begins with :ref:`keyPrefix `, and their associated values. Returns immediately, having modified the snapshot represented by this transaction. - -.. _api-node-transaction-atomic-operations: - -Atomic operations ------------------ - -|atomic-ops-blurb1| - -|atomic-ops-blurb2| - -|atomic-ops-blurb3| - -.. warning:: |atomic-ops-warning| - -In each of the methods below, ``param`` should be a ``Buffer`` appropriately packed to represent the desired value. For example:: - - # wrong - tr.add('key', 1); - - # right - var value = new Buffer(4); - value.writeUInt32LE(1, 0); - tr.add('key', value); - -.. function:: Transaction.add(key, param) - - |atomic-add1| - - |atomic-add2| - -.. function:: Transaction.bit_and(key, param) - - |atomic-and| - -.. function:: Transaction.bit_or(key, param) - - |atomic-or| - -.. function:: Transaction.bit_xor(key, param) - - |atomic-xor| - -.. function:: Transaction.max(key, param) - - |atomic-max1| - - |atomic-max-min| - -.. function:: Transaction.byte_max(key, param) - - |atomic-byte-max| - -.. function:: Transaction.min(key, param) - - |atomic-min1| - - |atomic-max-min| - -.. function:: Transaction.byte_min(key, param) - - |atomic-byte-min| - -.. function:: Transaction.set_versionstamped_key(key, param) - - |atomic-set-versionstamped-key-1| - - |atomic-versionstamps-1| - - |atomic-versionstamps-2| - - |atomic-set-versionstamped-key-2| - - .. warning :: |atomic-versionstamps-tuple-warning-key| - -.. function:: Transaction.set_versionstamped_value(key, param) - - |atomic-set-versionstamped-value| - - |atomic-versionstamps-1| - - |atomic-versionstamps-2| - - .. warning :: |atomic-versionstamps-tuple-warning-value| - -Committing ----------- - -.. function:: fdb.transactional( func ) - - The ``fdb.transactional`` decorator function makes it easy to write transactional functions which automatically commit. See :func:`fdb.transactional` for explanation and examples. - -.. function :: Transaction.doTransaction( func[, callback] ) - - Executes the provided function ``func`` with the transaction and calls ``callback`` with the result produced by ``func``. This is the recommended way to do operations transactionally. - - ``func`` must take a :class:`Transaction` as its first argument and an inner :ref:`callback ` as its second argument. - - .. note:: Note that the ``callback`` passed to :func:`doTransaction` and the inner callback passed to ``func`` are distinct. - - This function, along with ``Database.doTransaction``, makes it easy to write transactional functions which automatically commit. See :func:`Database.doTransaction` for explanation of their interaction and examples. - -.. function :: Transaction.commit([callback]) - - Attempt to commit the changes made in the transaction to the database. - - |callback-when| once the transaction has committed. |if-no-callback-no-result| - - |commit-unknown-result-blurb| - - |commit-outstanding-reads-blurb| - - .. note :: Consider using either the :func:`fdb.transactional` decorator function or the :func:`Database.doTransaction` function, which not only call :func:`Database.createTransaction` and :func:`Transaction.commit()` for you but also implement the required error handling and retry logic for transactions. - - .. warning :: |used-during-commit-blurb| - -.. function :: Transaction.onError(error[, callback]) - - Determine whether an error returned by a method of ``Transaction`` is retryable. |asynchronous-function|. If the error is retryable, ``onError`` will delay, :func:`Transaction.reset` the transaction, and call :ref:`callback ` with no result. Otherwise, the :ref:`callback ` will be called immediately with the error. |if-no-callback| - - .. note :: Consider using either the :func:`fdb.transactional` decorator function or the :func:`Database.doTransaction` function, which call this method for you. - -.. function:: Transaction.reset() - - |transaction-reset-blurb| - -.. function :: Transaction.cancel() - - |transaction-cancel-blurb| - - .. warning :: |transaction-reset-cancel-warning| - - .. warning :: |transaction-commit-cancel-warning| - -Watches -------- - -.. function:: Transaction.watch(key) - - Returns a :class:`Future` that will be notified when the value stored at ``key`` changes. - - |transaction-watch-blurb| - - |transaction-watch-committed-blurb| - - |transaction-watch-error-blurb| - - |transaction-watch-limit-blurb| - - .. warning:: Unlike most asynchronous function in the FoundationDB API, watches do not take a callback. Instead, one must be passed to the :ref:`future ` that the watch function returns. A watch will be automatically cancelled if the :ref:`future ` returned by the watch function is garbage collected. - - -Conflict ranges ---------------- - -.. note:: |conflict-range-note| - -|conflict-range-blurb| - -.. function:: Transaction.addReadConflictRange(begin, end) - - |add-read-conflict-range-blurb| - -.. function:: Transaction.addReadConflictKey(key) - - |add-read-conflict-key-blurb| - -.. function:: Transaction.addWriteConflictRange(begin, end) - - |add-write-conflict-range-blurb| - -.. function:: Transaction.addWriteConflictKey(key) - - |add-write-conflict-key-blurb| - -Versions --------- - -Most applications should use the read version that FoundationDB determines automatically during the transaction's first read and ignore all of these methods. - -.. function:: Transaction.setReadVersion(version) - - |infrequent| Sets the database version that the transaction will read from the database. The database cannot guarantee causal consistency if this method is used (the transaction's reads will be causally consistent only if the provided read version has that property). - -.. function :: Transaction.getReadVersion([callback]) - - |infrequent| |callback| with the transaction's read version. |if-no-callback| - -.. function:: Transaction.getCommittedVersion() - - |infrequent| |transaction-get-committed-version-blurb| - -.. function:: Transaction.getVersionstamp() - - |infrequent| |transaction-get-versionstamp-blurb| - -Transaction options -------------------- - -|transaction-options-blurb| - -.. _api-node-snapshot-ryw: - -.. function:: Transaction.options.setSnapshotRywDisable - - |option-snapshot-ryw-disable-blurb| - -.. function:: Transaction.options.setSnapshotRywEnable - - |option-snapshot-ryw-enable-blurb| - -.. function:: Transaction.options.setPriorityBatch() - - |option-priority-batch-blurb| - -.. function:: Transaction.options.setPrioritySystemImmediate() - - |option-priority-system-immediate-blurb| - - .. warning:: |option-priority-system-immediate-warning| - -.. function:: Transaction.options.setCausalReadRisky() - - |option-causal-read-risky-blurb| - -.. function:: Transaction.options.setCausalWriteRisky() - - |option-causal-write-risky-blurb| - -.. function:: Transaction.options.setNextWriteNoWriteConflictRange() - - |option-next-write-no-write-conflict-range-blurb| - -.. function:: Transaction.options.setReadYourWritesDisable() - - |option-read-your-writes-disable-blurb| - - .. note:: |option-read-your-writes-disable-note| - -.. function:: Transaction.options.setReadAheadDisable() - - |option-read-ahead-disable-blurb| - -.. function:: Transaction.options.setAccessSystemKeys() - - |option-access-system-keys-blurb| - - .. warning:: |option-access-system-keys-warning| - -.. function:: Transaction.options.setReadSystemKeys() - - |option-read-system-keys-blurb| - - .. warning:: |option-read-system-keys-warning| - -.. function:: Transaction.options.setRetryLimit(numRetries) - - |option-set-retry-limit-blurb1| - - |option-set-retry-limit-blurb2| - -.. function:: Transaction.options.setMaxRetryDelay(delay) - - |option-set-max-retry-delay-blurb| - -.. function:: Transaction.options.setTimeout(timeoutInMilliseconds) - - |option-set-timeout-blurb1| - - |option-set-timeout-blurb2| - - |option-set-timeout-blurb3| - -.. function:: Transaction.options.setDurabilityDevNullIsWebScale() - - |option-durability-dev-null-is-web-scale-blurb| - -.. _callbacks: - -Callbacks -========= - -Many functions in the FoundationDB API are asynchronous and take as their final parameter an optional callback which is called when the function has completed. Unless otherwise stated, these callbacks will always have the following signature:: - - callback = function(error, result) { } - -If error is null or undefined, then the function succeeded, and the result it returned (if any) is provided in the second argument. - -Functions taking callbacks also return :ref:`futures `. If such a function is called without passing it a callback, then one can be set later by passing the callback to the returned future. - -.. _streamline: - -Streamline ----------- - -The FoundationDB Node bindings also support use of the `streamline module `_ for simplified asynchronous development. If using the streamline module, any function which takes a callback may also take an ``_`` to execute the function in a blocking manner:: - - var db = fdb.open(); - - var x = db.get('x', _); //Blocks until finished - var y = db.get('y', _); //Blocks until finished - -.. _nodeFutures: - -Futures -------- - -.. class:: Future - -Asynchronous functions in the FoundationDB API generally take a :ref:`callback ` argument that will be called when the operation fails or completes. If no callback argument is supplied to an asynchronous FoundationDB function, then it will instead return a :class:`Future` object:: - - // Database.get takes a callback - db.get('x', function(err, val)) - console.log('got x', err, val); - }); - - // Database.get can instead return a future - var future = db.get('x'); - -.. note:: If you pass a callback to an asynchronous function in the FoundationDB API, it will not return a Future. - -The result of an operation can be retrieved by passing a callback to the future object:: - - var future = db.get('x'); - future(function(err, val) { - console.log('got x', err, val); - }); - - -Futures make it possible to start multiple operations before waiting for the result. For example:: - - // Start both reads - var x = db.get('x') - var y = db.get('y') - - // Wait for both reads to complete - x(function(xErr, xVal) { - y(function(yErr, yVal) { - if(xErr || yErr) - console.log(xErr, yErr); - else - console.log('Finished parallel get:', xVal, yVal); - }); - }); - -Futures can be combined with :ref:`streamline`:: - - var x = db.get('x'); - var y = db.get('x'); - - //This blocks until both gets have completed - console.log(x(_) + y(_)); - -.. _api-node-promises: - -Promises -^^^^^^^^ - -Futures also support the `Promises/A+ specification `_, a popular standard for asynchronous operations in JavaScript. In the Promise/A+ interface, a promise is a future that exposes a ``then`` function, which registers callbacks to receive either a promise's eventual value or the reason why the promise cannot be fulfilled. A promise can be in one of three states: ``pending``, ``fulfilled``, or ``rejected``. - -* When ``pending``, a promise will eventually transition to either the ``fulfilled`` or ``rejected`` state. -* When ``fulfilled``, a promise has a value, which will not change. -* When ``rejected``, a promise has a reason, which will not change. - -.. function:: Future.cancel() - - Attempts to cancel the future and its associated asynchronous operation, if possible. If a :ref:`callback ` was passed to the original function or its returned future, it may be called with an :ref:`operation_cancelled ` error. - - .. note:: Currently, only :func:`watches ` support cancellation. All other asynchronous FoundationDB operations will continue running normally when cancelled. - -.. function:: Future.then(onFulfilled, onRejected) - - Provides access to the promise's current or eventual value or the reason it was rejected. ``then`` may be called multiple times on the same promise. - - ``onFulfilled`` and ``onRejected`` are both optional arguments. If ``onFulfilled`` is a function, it will be called after promise is fulfilled, with promise's value as its first argument. If ``onRejected`` is a function, it will be called after promise is rejected, with promise's reason as its first argument. See the `specification `_ for further details. - - Returns a :class:`Future`. - -.. function:: Future.catch(onRejected) - - Provides access to the reason a promise is rejected. ``onRejected`` will be called after promise is rejected, with promise's reason as its first argument. ``catch`` may be called multiple times on the same promise. - - Equivalent to calling :func:`Future.then(undefined, onRejected) `. - -Promise utilities ------------------ - -The ``fdb.future`` functions provide utilities for working with futures in a manner compatible with the promise interface. ``fdb.future`` also exports the prototype of created futures. - -.. function:: fdb.future.create(func [, cb]) - - Creates a :class:`Future` in the ``pending`` state, i.e. neither ``fulfilled`` nor ``rejected``, that will be satisfied once ``func`` has finished executing (either successfully or with an error). ``func`` will be passed a single :ref:`callback ` argument ``futureCb`` that ``func`` should call when it is complete. - - If the ``cb`` argument is supplied to ``fdb.future.create``, then no future will be returned; instead ``cb`` will be called when ``func`` has finished executing. Otherwise, a :class:`Future` will be returned. This allows an API to provide functions that can take Node-style callbacks or return :class:`Futures `. For example:: - - function getAndClearFoo(tr, cb) { - return fdb.future.create(function(futureCb) { - tr.get('foo', function(err, val) { - if(err) return futureCb(err); - tr.clear('foo'); - futureCb(undefined, val); - }); - - // Or we could use promises - // tr.get('foo') - // .then(function(val) { - // tr.clear('foo'); - // return val; - // })(futureCb); - }, cb); - } - - // Call getAndClearFoo without passing a callback - var future = getAndClearFoo(tr); - future.then(function(value) { - console.log('got value', value); - }, function(reason) { - console.log('got error', reason); - }); - - // Call getAndClearFoo with a callback - getAndClearFoo(tr, function(err, val) { - if(err) - console.log('got error', err); - else - console.log('got value', val); - }); - -.. function:: fdb.future.resolve(value) - - Creates a :class:`Future` that is ``fulfilled`` with ``value``. - -.. function:: fdb.future.reject(reason) - - Creates a :class:`Future` that is ``rejected`` with ``reason``. - -.. function:: fdb.future.all(futureArray) - - Returns a :class:`Future` that is ``fulfilled`` if and when all futures in ``futureArray`` are ``fulfilled``, or is ``rejected`` if and when any future in ``futureArray`` is ``rejected``. If ``fulfilled``, its value will be an array containing the values that ``fulfilled`` each of the futures in ``futureArray``, in the same order. If ``rejected``, the reason will be the same as the first future that was ``rejected``. - -.. function:: fdb.future.race(futureArray) - - Returns a :class:`Future` that is ``fulfilled`` if and when any future in ``futureArray`` is ``fulfilled``, or is ``rejected`` if and when any future in ``futureArray`` is ``rejected``. It's ``fullfilled`` value or ``rejected`` reason will be the same as the first future that was ``fulfilled`` or ``rejected``. - -Lazy iterators -============== - -.. class:: LazyIterator - -:func:`Transaction.getRange` and similar interfaces all return ``LazyIterator`` objects. A ``LazyIterator`` efficiently manages fetching the results of a query in batches as you iterate so that you can avoid receiving more data than you need (see :attr:`fdb.streamingMode` for more information). The interface of a ``LazyIterator`` consists of functions that follow a common pattern. - -Except for :func:`LazyIterator.next`, the ``LazyIterator`` functions always start iteration from the beginning of the results, even if the iterator has been used before or is being used concurrently. - -.. function:: LazyIterator.forEach(func[, callback]) - - Iterates over the requested results by calling ``func`` for each item being iterated over. - - ``func`` will be passed the next item in the iteration as its first argument and a :ref:`callback ` as its second. ``func`` must call its callback upon completion. If its callback is called with any error or defined result, then iteration will terminate immediately. - - |callback-when| when either all results have been exhausted or ``func`` terminates prematurely. It will be called with the result returned through ``func``'s callback, if any. |if-no-callback| - - .. note:: Note that the ``callback`` passed to :func:`forEach` and the callback passed to ``func`` are distinct. - - For example, the following will print the first 10 keys and values in the range ['apple', 'cherry'):: - - var numKeys = 0; - var itr = tr.getRange('apple', 'cherry'); - itr.forEach(function(kv, cb) { - console.log(kv.key, kv.value); - - if(++numKeys === 10) - cb(null, null); - else - cb(); - }, function(err, res) { - console.log('Finished forEach', err, res); - } - -.. function:: LazyIterator.forEachBatch(func[, callback]) - - Iterates over the requested range by calling ``func`` for each batch of items fetched from the database. The size of batches is determined by which :attr:`fdb.streamingMode` is used. - - ``func`` will be passed an array of items containing the current batch of results as its first argument and a :ref:`callback ` as its second. ``func`` must call its callback upon completion. If its callback is called with any error or defined result, then iteration will terminate immediately. - - |callback| when either all results have been exhausted or ``func`` terminates prematurely. It will be called with the result returned through ``func``'s callback, if any. |if-no-callback| - - .. note:: Note that the ``callback`` passed to :func:`forEachBatch` and the callback passed to ``func`` are distinct. - - For example, the following will print the first 10 keys and values in the range ['apple', 'cherry'):: - - var numKeys = 0; - var itr = tr.getRange('apple', 'cherry'); - itr.forEachBatch(function(arr, cb) { - for(var i = 0; i < arr.length; ++i) { - console.log(arr[i].key, arr[i].value); - if(++numKeys === 10) { - cb(null, null); - return; - } - } - - cb(); - }, function(err, res) { - console.log('Finished forEachBatch', err, res); - } - -.. function:: LazyIterator.toArray([callback]) - - Converts the requested results to an array. Unless you intend to use the entire result, it may be more efficient to use one of :func:`LazyIterator.forEachBatch` or :func:`LazyIterator.forEach`. - - |callback| with an array containing all items in the iteration. |if-no-callback| - - For example, the following will print all keys and values in the range ['apple', 'cherry'):: - - tr.getRange('apple', 'cherry').toArray(function(err, kvArr) { - if(err) - console.log('Error:', err); - else - for(var i = 0; i < arr.length; ++i) - console.log(kvArr[i].key, kvArr[i].value); - }; - -.. function:: LazyIterator.next([callback]) - - Gets the next item in the iteration. It is generally easier to use one of :func:`LazyIterator.forEachBatch`, :func:`LazyIterator.forEach`, or :func:`LazyIterator.toArray`. - - |callback| with the next item in the results. If there are no more results, then ``null`` is returned. |if-no-callback| - -Streaming modes -=============== - -.. attribute:: fdb.streamingMode - -|streaming-mode-blurb1| - -|streaming-mode-blurb2| - -The following streaming modes are available: - -.. attribute:: fdb.streamingMode.iterator - - *The default.* The client doesn't know how much of the range it is likely to use and wants different performance concerns to be balanced. - - Only a small portion of data is transferred to the client initially (in order to minimize costs if the client doesn't read the entire range), and as the caller iterates over more items in the range larger batches will be transferred in order to maximize throughput. - -.. attribute:: fdb.streamingMode.want_all - - The client intends to consume the entire range and would like it all transferred as early as possible. - -.. attribute:: fdb.streamingMode.small - - |infrequent| Transfer data in batches small enough to not be much more expensive than reading individual rows, to minimize cost if iteration stops early. - -.. attribute:: fdb.streamingMode.medium - - |infrequent| Transfer data in batches sized in between small and large. - -.. attribute:: fdb.streamingMode.large - - |infrequent| Transfer data in batches large enough to be, in a high-concurrency environment, nearly as efficient as possible. If the client stops iteration early, some disk and network bandwidth may be wasted. The batch size may still be too small to allow a single client to get high throughput from the database, so if that is what you need consider :attr:`fdb.streamingMode.serial`. - -.. attribute:: fdb.streamingMode.serial - - Transfer data in batches large enough that an individual client can get reasonable read bandwidth from the database. If the client stops iteration early, considerable disk and network bandwidth may be wasted. - -.. attribute:: fdb.streamingMode.exact - - |infrequent| The client has passed a specific row limit and wants that many rows delivered in a single batch. This is not particularly useful in Node.js because iterator functionality makes batches of data transparent, so use :attr:`fdb.streamingMode.want_all` instead. - -Errors -====== - -Errors in the FoundationDB API are raised as exceptions of type :class:`FDBError() `. These errors may be displayed for diagnostic purposes, but generally should be passed to :func:`Transaction.onError`. When using :func:`Database.doTransaction` or :func:`fdb.transactional`, appropriate errors will be retried automatically. - -.. class:: fdb.FDBError - -.. attribute:: fdb.FDBError.code - - An integer associated with the error type. - -.. attribute:: fdb.FDBError.message - - A somewhat human-readable description of the error. - -.. warning:: You should use only :attr:`FDBError.code ` for programmatic comparisons, as the message of the error may change at any time. Whenever possible, use the :func:`Transaction.onError()` method to handle :class:`FDBError() ` exceptions. - -.. _api-node-tuple-layer: - -Tuple layer -=========== - -.. attribute:: fdb.tuple - -|tuple-layer-blurb| - -.. note:: |tuple-layer-note| - -.. _tupleDataTypes: - -In the FoundationDB Node.js API, a tuple is a JavaScript array that contains elements of the following data types: - -+-----------------------+-----------------------------------------------------------------------------------+---------------------------+ -| Type | Legal Values | Canonical Value | -+=======================+===================================================================================+===========================+ -| Null value | ``null`` | ``null`` | -+-----------------------+-----------------------------------------------------------------------------------+---------------------------+ -| Byte string | Any value of type ``Buffer``, ``ArrayBuffer``, or ``Uint8Array`` | ``Buffer`` | -+-----------------------+-----------------------------------------------------------------------------------+---------------------------+ -| Unicode string | Any value of type ``String`` | ``String`` | -+-----------------------+-----------------------------------------------------------------------------------+---------------------------+ -| 54-bit signed integer | ``Number`` in the range [-2\ :sup:`53`, 2\ :sup:`53`) that has no fractional part | ``Number`` | -+-----------------------+-----------------------------------------------------------------------------------+---------------------------+ -| 32-bit float | ``fdb.tuple.Float`` with a value that fits within a 32-bit float | :class:`fdb.tuple.Float` | -+-----------------------+-----------------------------------------------------------------------------------+---------------------------+ -| 64-bit float | ``fdb.tuple.Double`` with a value that fits within a 64-bit float | :class:`fdb.tuple.Double` | -+-----------------------+-----------------------------------------------------------------------------------+---------------------------+ -| Boolean | Any value of type ``Boolean`` | ``Boolean`` | -+-----------------------+-----------------------------------------------------------------------------------+---------------------------+ -| UUID | ``fdb.tuple.UUID`` with a 16-byte underlying UUID | :class:`fdb.tuple.UUID` | -+-----------------------+-----------------------------------------------------------------------------------+---------------------------+ -| Array | An ``Array`` consisting of legal tuple-encodable values | ``Array`` | -+-----------------------+-----------------------------------------------------------------------------------+---------------------------+ - - -If ``T`` is a JavaScript array meeting these criteria, then conceptually:: - - T == fdb.tuple.unpack(fdb.tuple.pack(T)) - -.. note:: Unpacking a tuple always returns an array of elements in a canonical representation, so packing and then unpacking a tuple may result in an equivalent but not identical representation. - -.. warning:: In general, FoundationDB tuples can contain 64-bit integers. Node.js, however, lacks an appropriate data type to handle integers larger than 54 bits. If you intend to use the Node.js bindings with other language bindings, keep in mind that attempting to decode a tuple with signed integers larger than 54 bits will result in an error being thrown. - -.. function:: fdb.tuple.pack(tuple) - - Returns a key (Buffer) encoding the specified array ``tuple`` - - **Throws** an error if ``tuple`` contains any elements that are not one of the :ref:`encodable data types `. - -.. function:: fdb.tuple.unpack(key) - - Returns the tuple encoded by the given key as an array - - | **Throws** an error if the unpacked tuple contains any integers outside the range of a 54-bit signed integer. - | **Throws** an error if the encoded tuple contains unknown data types. - -.. function:: fdb.tuple.range(tuple) - - Returns the range containing all keys that encode tuples strictly starting with the array ``tuple`` (that is, all tuples of greater length than ``tuple`` of which ``tuple`` is a prefix). - - The range will be an object of the form:: - - var range = { - begin: new Buffer(''), // A Buffer containing the beginning of the range, inclusive - end: new Buffer('') // A Buffer containing the end of the range, exclusive - }; - - This range can be used to call :func:`Transaction.getRange`. For example:: - - var r = fdb.tuple.range(['A', 2]); - var itr = tr.getRange(r.begin, r.end); - - returns a :class:`LazyIterator` over all :ref:`key-value pairs ` in the database whose keys would unpack to tuples like ('A', 2, x), ('A', 2, x, y), etc. - - **Throws** an error if ``tuple`` contains any elements that are not one of the :ref:`encodable data types `. - -.. function:: fdb.tuple.compare(tuple1, tuple2) - - Compares ``tuple1`` and ``tuple2`` and returns -1 if ``tuple1`` will sort before ``tuple2`` when serialized, 0 if they are equal, and 1 otherwise. - - **Throws** an error if either tuple contains any elements that are not one of the :ref:`encodeable data types `. - -.. class:: fdb.tuple.Float(value) - - Wrapper class around a 32-bit floating point number. The constructor for this object takes a ``Number`` and uses it as the underlying - value for the given object. If the item is out of the correct range, one may experience a loss of precision. - The contract here is that for any value ``f`` in the correct range, we can conclude:: - - f == fdb.tuple.Float.fromBytes(new fdb.tuple.Float(f).toBytes()).value - -.. attribute:: fdb.tuple.Float.value - - Underlying value for the :class:`fdb.tuple.Float` instance. It should have the ``Number`` type. - -.. attribute:: fdb.tuple.Float.rawData - - Big-endian byte-array representation of the :class:`fdb.tuple.Float` value. This value is only set to something other than ``undefined`` - if the float is a NaN value (as Javascript will collapse all NaN values to a single value otherwise). - -.. function:: fdb.tuple.Float.toBytes() - - Retrieve the big-endian byte-array representation of the :class:`fdb.tuple.Float` instance. - -.. function:: fdb.tuple.Float.fromBytes(buf) - - Static initializer of the :class:`fdb.tuple.Float` type that starts with a big-endian byte array representation of - a 32-bit floating point number. The ``buf`` parameter must be a byte buffer of length 4. The contract - here is that for any byte buffer ``buf``, we can conclude:: - - buf == fdb.tuple.Float.fromBytes(buf).toBytes() - - **Throws** a ``RangeError`` if ``buf`` does not have length 4. - -.. class:: fdb.tuple.Double(value) - - Wrapper class around a 64-bit floating point number. The constructor for this object takes a ``Number`` and uses it as the underlying - value for the given object. The contract here is that for any value ``d`` in the correct range, we can conclude:: - - d == fdb.tuple.Double.fromBytes(new fdb.tuple.Double(d).toBytes()).value - -.. attribute:: fdb.tuple.Double.value - - Underlying value for the :class:`fdb.tuple.Double` instance. It should have the ``Number`` type. - -.. attribute:: fdb.tuple.Double.rawData - - Big-endian byte-array representation of the :class:`fdb.tuple.Double` value. This value is only set to something other than ``undefined`` - if the double is a NaN value (as Javascript will collapse all NaN values to a single value otherwise). - -.. function:: fdb.tuple.Double.toBytes() - - Retrieve the big-endian byte-array representation of the :class:`fdb.tuple.Double` instance. - -.. function:: fdb.tuple.Double.fromBytes(buf) - - Static initializer of the :class:`fdb.tuple.Double` type that starts with a big-endian byte array representation of - a 64-bit floating point number. The ``buf`` parameter must be a byte buffer of length 8. The contract - here is that for any byte buffer ``buf``, we can conclude:: - - buf == fdb.tuple.Double.fromBytes(buf).toBytes() - - **Throws** a ``RangeError`` if ``buf`` does not have length 8. - -.. class:: fdb.tuple.UUID(data) - - Wrapper class around a 128-bit UUID. The constructor takes a byte buffer of length 16 that should represent - the UUID in big-endian order. - - **Throws** an ``FDBError`` if ``buf`` does not have length 16. - -.. attribute:: fdb.tuple.UUID.data - - Data underlying the :class:`fdb.tuple.UUID` instance. This will be a buffer of length 16 just like the ``data`` - parameter of the :class:`fdb.tuple.UUID` constructor. - -.. _api-node-subspaces: - -Subspaces -========= - -|subspace-blurb1| - -|subspace-blurb2| - -.. note:: For general guidance on subspace usage, see the discussion in the :ref:`Developer Guide `. - -.. class:: fdb.Subspace([prefixArray=[], rawPrefix=new Buffer(0)]) - - |subspace-blurb3| - -.. function:: Subspace.key() - - |subspace-key-blurb| - -.. function:: Subspace.pack(arr) - - |subspace-pack-blurb| - -.. function:: Subspace.unpack(key) - - |subspace-unpack-blurb| - -.. function:: Subspace.range(arr=[]) - - |subspace-range-blurb| - - The range will be an object of the form:: - - var range = { - begin: new Buffer(''), // A Buffer containing the beginning of the range, inclusive - end: new Buffer('') // A Buffer containing the end of the range, exclusive - }; - - This range can be used to call :func:`Transaction.getRange`. For example:: - - var r = subspace.range(['A', 2]); - var itr = tr.getRange(r.begin, r.end); - -.. function:: Subspace.contains(key) - - |subspace-contains-blurb| - -.. function:: Subspace.asFoundationDBKey() - - |subspace-as-foundationdb-key-blurb| This method serves to support the :ref:`asFoundationdbKey() ` convenience interface. - -.. function:: Subspace.subspace(arr) - - |subspace-subspace-blurb| - -.. function:: Subspace.get(item) - - Shorthand for subspace.subspace([item]). This function can be combined with the :func:`Subspace.asFoundationDBKey()` convenience to turn this:: - - var s = new fdb.Subspace(['x']); - tr.set(s.pack(['foo']), ''); - tr.set(s.pack(['foo', 'bar']), ''); - - into this:: - - var s = new fdb.Subspace(['x']); - tr.set(s.get('foo'), ''); - tr.set(s.get('foo').get('bar'), ''); - -.. _api-node-directories: - -Directories -=========== - -|directory-blurb1| - -.. note:: For general guidance on directory usage, see the discussion in the :ref:`Developer Guide `. - -|directory-blurb2| - -|directory-blurb3| - -.. attribute:: fdb.directory - - The default instance of :class:`DirectoryLayer`. - -.. class:: fdb.DirectoryLayer(nodeSubspace=new fdb.Subspace([], fdb.buffer.fromByteLiteral('\\xFE')), contentSubspace=new fdb.Subspace(), allowManualPrefixes=false) - - |directory-layer-blurb| - -.. function:: DirectoryLayer.createOrOpen(databaseOrTransaction, path[, options, callback]) - - |directory-create-or-open-blurb| - - If the :ref:`value ` ``options.layer`` is specified and the directory is new, it is recorded as the layer for this directory; if ``layer`` is specified and the directory already exists, it is compared against the layer specified when the directory was created, and an error is raised if they differ. - - |callback| with the existing or newly created |directory-subspace|. |if-no-callback| - -.. function:: DirectoryLayer.open(databaseOrTransaction, path[, options, callback]) - - |directory-open-blurb| - - If the :ref:`value ` ``options.layer`` is specified, it is compared against the layer specified when the directory was created, and an error is raised if they differ. - - |callback| with the opened |directory-subspace|. |if-no-callback| - -.. function:: DirectoryLayer.create(databaseOrTransaction, path[, options, callback]) - - |directory-create-blurb| - - If the :ref:`key ` ``options.prefix`` is specified, the directory is created with the given physical prefix; otherwise a prefix is allocated automatically. - - If the :ref:`value ` ``options.layer`` is specified, it is recorded with the directory and will be checked by future calls to open. - - |callback| with the newly created |directory-subspace|. |if-no-callback| - -.. function:: DirectoryLayer.move(tr, oldPath, newPath[, callback]) - - |directory-move-blurb| - - |callback| with the |directory-subspace| at its new location. |if-no-callback| - -.. function:: DirectoryLayer.remove(tr[, path, callback]) - - |directory-remove-blurb| - - .. warning:: |directory-remove-warning| - - |callback-when| when the directory is removed. |if-no-callback-no-result| - -.. function:: DirectoryLayer.removeIfExists(tr[, path, callback]) - - |directory-remove-if-exists-blurb| - - .. warning:: |directory-remove-warning| - - |callback| with ``true`` if the directory existed prior to this call and ``false`` otherwise. |if-no-callback| - -.. function:: DirectoryLayer.list(tr[, path, callback]) - - Returns an array of names of the immediate subdirectories of the directory at ``path``. Each name is a unicode string representing the last component of a subdirectory's path. - - |callback| with the array of subdirectory names. |if-no-callback| - -.. function:: DirectoryLayer.exists(tr[, path, callback]) - - |directory-exists-blurb| - - |callback| with ``true`` if the directory exists and ``false`` if not. |if-no-callback| - -.. function:: DirectoryLayer.getLayer() - - |directory-get-layer-blurb| - -.. function:: DirectoryLayer.getPath() - - |directory-get-path-blurb| - -.. _api-node-directory-subspace: - -DirectorySubspace ------------------ - -|directory-subspace-blurb| - -.. function:: DirectorySubspace.moveTo(databaseOrTransaction, newAbsoluteNameOrPath[, callback]) - - |directory-move-to-blurb| - - |callback| with the |directory-subspace| at its new location. |if-no-callback| - -Locality information -==================== - -.. attribute:: fdb.locality - -|locality-api-blurb| - -.. function:: fdb.locality.getBoundaryKeys(databaseOrTransaction, begin, end, callback) - - |callback| with a :class:`LazyIterator` of :ref:`keys ` ``k`` such that ``begin <= k < end`` and ``k`` is located at the start of a contiguous range stored on a single server. |if-no-callback| - - |locality-get-boundary-keys-db-or-tr| - - |locality-get-boundary-keys-warning-danger| - -.. function:: fdb.locality.getAddressesForKey(transaction, key, callback) - - |locality-get-addresses-for-key-blurb| - - |callback| with an array of network address strings. |if-no-callback| diff --git a/documentation/sphinx/source/api-reference.rst b/documentation/sphinx/source/api-reference.rst index 3ce84ab606..4527d2a6a8 100644 --- a/documentation/sphinx/source/api-reference.rst +++ b/documentation/sphinx/source/api-reference.rst @@ -12,7 +12,6 @@ The following documents give detailed descriptions of the API for each language: api-python api-ruby - Node.js API Java API Go API api-c diff --git a/documentation/sphinx/source/getting-started-linux.rst b/documentation/sphinx/source/getting-started-linux.rst index ff4838ee69..ff6759a3db 100644 --- a/documentation/sphinx/source/getting-started-linux.rst +++ b/documentation/sphinx/source/getting-started-linux.rst @@ -110,7 +110,7 @@ Managing the FoundationDB service Next steps ========== -* Install the APIs for :doc:`Ruby `, `Java `_, or :doc:`Node.js ` if you intend to use those languages. :doc:`Python ` and :doc:`C ` APIs were installed along with the ``foundationdb-clients`` package above. +* Install the APIs for :doc:`Ruby `, `Java `_, or `Go `_ if you intend to use those languages. :doc:`Python ` and :doc:`C ` APIs were installed along with the ``foundationdb-clients`` package above. * See :doc:`tutorials` for samples of developing applications with FoundationDB. * See :doc:`developer-guide` for information of interest to developers, including common design patterns and performance considerations. * See :doc:`administration` for detailed administration information. diff --git a/documentation/sphinx/source/getting-started-mac.rst b/documentation/sphinx/source/getting-started-mac.rst index 69e5bc96d7..8eacc2ce7a 100644 --- a/documentation/sphinx/source/getting-started-mac.rst +++ b/documentation/sphinx/source/getting-started-mac.rst @@ -101,7 +101,7 @@ Managing the FoundationDB service Next steps ========== -* Install the APIs for :doc:`Ruby `, `Java `_, or :doc:`Node.js ` if you intend to use those languages. :doc:`Python ` and :doc:`C ` APIs were installed using the FoundationDB installer above. +* Install the APIs for :doc:`Ruby `, `Java `_, or `Go `_ if you intend to use those languages. :doc:`Python ` and :doc:`C ` APIs were installed using the FoundationDB installer above. * See :doc:`tutorials` for samples of developing applications with FoundationDB. * See :doc:`developer-guide` for information of interest to developers, including common design patterns and performance considerations. * See :doc:`administration` for detailed administration information. diff --git a/fdbclient/vexillographer/nodejs.cs b/fdbclient/vexillographer/nodejs.cs deleted file mode 100644 index 8a8a9f4bc6..0000000000 --- a/fdbclient/vexillographer/nodejs.cs +++ /dev/null @@ -1,90 +0,0 @@ -/* - * nodejs.cs - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; - -namespace vexillographer -{ - class nodejs : BindingWriter - { - private static string getNodeLine(Option o) - { - string comment = ""; - if(o.comment.Length > 0) - comment = String.Format("\t// {0}\n", o.comment); - - string parameterComment = ""; - if (o.getParameterComment().Length > 0) - parameterComment = String.Format("\t// {0}\n", "Parameter: " + o.getParameterComment()); - - return String.Format("{0}{1}\tADD_OPTION({2}, \"{3}\", {4}, {5});", comment, parameterComment, o.scope.ToString(), o.name, o.code, o.paramType.ToString()); - } - - public void writeFiles(string filePath, IEnumerable