UNPKG

@darlean/fs-persistence-suite

Version:

File System Persistence Suite that uses a physical or shared file system to persist data.

138 lines (137 loc) 5.71 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FsPersistenceService = void 0; const base_1 = require("@darlean/base"); const crypto = __importStar(require("crypto")); class FsPersistenceService { constructor(options, actorPortal, deser) { this.deser = deser; this.shards = []; for (let i = 0; i < options.shardCount; i++) { const nodeIdx = i % options.nodes.length; const node = options.nodes[nodeIdx]; const id = [i.toString(), node || '']; this.shards.push({ id, node, actor: actorPortal.retrieve(id) }); } } async activate() { const promises = []; for (const shard of this.shards) { promises.push(shard.actor.touch()); } await Promise.all(promises); } store(options) { const shardIdx = this.deriveShardIdx(options.partitionKey); const shard = this.shards[shardIdx]; return shard.actor.store(options); } storeBatch(options) { return this.storeBatchImpl(options); } async storeBatchBuffer(options) { return this.deser.serialize(await this.storeBatchImpl(this.deser.deserializeTyped(options))); } load(options) { const shardIdx = this.deriveShardIdx(options.partitionKey); const shard = this.shards[shardIdx]; return shard.actor.load(options); } async query(options) { const shardIdx = this.deriveShardIdx(options.partitionKey); const shard = this.shards[shardIdx]; return this.deser.deserializeTyped(await shard.actor.queryBuffer(options)); } queryBuffer(options) { const shardIdx = this.deriveShardIdx(options.partitionKey); const shard = this.shards[shardIdx]; return shard.actor.queryBuffer(options); } async storeBatchImpl(options) { const results = { unprocessedItems: [] }; const shardBatches = new Map(); for (const item of options.items) { const shardIdx = this.deriveShardIdx(item.partitionKey); let sb = shardBatches.get(shardIdx); if (!sb) { sb = { items: [] }; shardBatches.set(shardIdx, sb); } sb.items.push(item); } // TODO: In Parallel // TODO: Ensure eventual consistence by putting items in queue first for (const [shardIdx, batch] of shardBatches.entries()) { const shard = this.shards[shardIdx]; try { await shard.actor.storeBatchBuffer(this.deser.serialize(batch)); } catch (e) { for (const item of batch.items) { results.unprocessedItems.push({ identifier: item.identifier, error: (0, base_1.toApplicationError)(e) }); } } } return results; } deriveShardIdx(partitionKey) { const hash = crypto.createHash('sha1'); for (const part of partitionKey) { hash.update(part, 'utf8'); } const offset = hash.digest().readUInt16BE() % this.shards.length; return offset; } } __decorate([ (0, base_1.action)({ locking: 'shared' }) ], FsPersistenceService.prototype, "store", null); __decorate([ (0, base_1.action)({ locking: 'shared' }) ], FsPersistenceService.prototype, "storeBatch", null); __decorate([ (0, base_1.action)({ locking: 'shared' }) ], FsPersistenceService.prototype, "storeBatchBuffer", null); __decorate([ (0, base_1.action)({ locking: 'shared' }) ], FsPersistenceService.prototype, "load", null); __decorate([ (0, base_1.action)({ locking: 'shared' }) ], FsPersistenceService.prototype, "query", null); __decorate([ (0, base_1.action)({ locking: 'shared' }) ], FsPersistenceService.prototype, "queryBuffer", null); exports.FsPersistenceService = FsPersistenceService;