From 969a81fabe19b097af748e1fe522e9f98d28c934 Mon Sep 17 00:00:00 2001 From: Mykola Bilochub Date: Mon, 17 Dec 2018 21:43:30 +0200 Subject: [PATCH] Implement identification primitives Refs: https://github.com/metarhia/globalstorage/issues/8 Refs: https://github.com/metarhia/Metarhia/issues/21 --- lib/identification.js | 122 ++++++++++++++++++++++++++++++++++++++++++ lib/provider.js | 7 +-- 2 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 lib/identification.js diff --git a/lib/identification.js b/lib/identification.js new file mode 100644 index 00000000..900c8d8a --- /dev/null +++ b/lib/identification.js @@ -0,0 +1,122 @@ +'use strict'; + +const { Uint64, sequence } = require('@metarhia/common'); +const { StorageProvider } = require('./provider'); + +class RemoteServer extends StorageProvider { + constructor({ + host, + ports, + }, providerOptions) { + super(providerOptions); + this.host = host; + this.ports = ports; + if (this.ports.length > 1) { + this.ports = sequence(this.ports, 0); + } + this.pool = []; + } +} + +const getTreeDepth = (node, depth = 0) => { + if (node[0] && node[1]) { + return Math.max( + getTreeDepth(node[0], depth + 1), + getTreeDepth(node[1], depth + 1) + ); + } + return depth; +}; + +const arrayifyTree = node => { + if (node[0] && node[1]) { + return [arrayifyTree(node[0]), arrayifyTree(node[1])]; + } else { + return node; + } +}; + +const buildIndex = (tree, depth, serverIds) => { + const result = new Array(Math.pow(2, depth)); + + const parseTree = (index, depth, node) => { + const isLeaf = !node[0] || !node[1]; + if (isLeaf) { + const serverSuffix = new Uint64(index) + .shiftLeft(SYSTEM_BITMASK_SIZE) + .or(serverIds.systemSuffix); + const serverBitmask = new Uint64(1) + .shiftLeft(depth) + .dec() + .shiftLeft(SYSTEM_BITMASK_SIZE) + .or(SYSTEM_BITMASK); + + result[index] = new RemoteServer(node, Object.assign({}, serverIds, { + serverSuffix, + serverBitmask, + })); + for (let i = 1 << depth; i < result.length; i <<= 1) { + result[index | i] = result[index]; + } + return; + } + parseTree(index, depth + 1, node[0]); + parseTree(index + (1 << depth), depth + 1, node[1]); + }; + parseTree(0, 0, tree); + + return result; +}; + +const SYSTEM_BITMASK_SIZE = 24; +const SYSTEM_BITMASK = new Uint64(1).shiftLeft(SYSTEM_BITMASK_SIZE).dec(); + +class ServerTree { + constructor(tree, systemId) { + this.tree = arrayifyTree(tree); + this.depth = getTreeDepth(this.tree); + this.serverBitmask = new Uint64(1).shiftLeft(this.depth).dec(); + this.treeIndex = buildIndex(this.tree, this.depth, { + systemSuffix: new Uint64(systemId), + systemBitmask: new Uint64(SYSTEM_BITMASK), + }); + } + + findServer(id) { + return this.treeIndex[ + Uint64.shiftRight(id, SYSTEM_BITMASK_SIZE) + .and(this.serverBitmask).toUint32() + ]; + } + + toJSON() { + return this.tree; + } +} + +class SystemList { + constructor(systems) { + this.systems = {}; + for (const id in systems) { + this.systems[id] = new ServerTree(systems[id], new Uint64(id)); + } + } + + findServer(id) { + const serverTree = this.systems[Uint64.and(SYSTEM_BITMASK).toUint32()]; + if (!serverTree) { + return null; + } + return serverTree.findServer(id); + } + + toJSON() { + return this.systems; + } +} + +module.exports = { + RemoteServer, + ServerTree, + SystemList, +}; diff --git a/lib/provider.js b/lib/provider.js index edef7187..b4565b2e 100644 --- a/lib/provider.js +++ b/lib/provider.js @@ -6,8 +6,6 @@ const { GSError, codes: errorCodes } = require('./errors'); const { createRemoteProviderJstpApi } = require('./remote.provider.jstp.api.js'); -const SYSTEM_BITMASK_SIZE = 24; - // Abstract Storage Provider class StorageProvider { // Create StorageProvider @@ -225,7 +223,4 @@ class StorageProvider { } } -module.exports = { - StorageProvider, - SYSTEM_BITMASK_SIZE, -}; +module.exports = { StorageProvider };