UNPKG

antarys

Version:

High-performance Node.js client for Antarys vector database with HTTP/2, connection pooling, and intelligent caching

226 lines (225 loc) 6.34 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BufferPool = exports.QueryCache = exports.HighPerformanceCache = void 0; const crypto_1 = require("crypto"); class HighPerformanceCache { // 5 minutes default TTL constructor(maxSize = 1000, ttl = 300000) { this.cache = new Map(); this.hits = 0; this.misses = 0; this.maxSize = maxSize; this.ttl = ttl; this.cleanupInterval = setInterval(() => this.cleanup(), 60000); } get(key) { const node = this.cache.get(key); if (!node) { this.misses++; return undefined; } if (Date.now() - node.value.timestamp > this.ttl) { this.delete(key); this.misses++; return undefined; } this.moveToFront(node); node.value.hits++; this.hits++; return node.value.value; } set(key, value) { const existing = this.cache.get(key); if (existing) { existing.value.value = value; existing.value.timestamp = Date.now(); this.moveToFront(existing); return; } const entry = { value, timestamp: Date.now(), hits: 0 }; const node = { key, value: entry }; this.addToFront(node); this.cache.set(key, node); if (this.cache.size > this.maxSize) { this.evictLRU(); } } delete(key) { const node = this.cache.get(key); if (!node) return false; this.removeNode(node); this.cache.delete(key); return true; } clear() { this.cache.clear(); this.head = undefined; this.tail = undefined; this.hits = 0; this.misses = 0; } getStats() { const totalRequests = this.hits + this.misses; return { cacheEnabled: true, cacheHits: this.hits, cacheMisses: this.misses, hitRate: totalRequests > 0 ? this.hits / totalRequests : 0, cacheSize: this.cache.size }; } moveToFront(node) { this.removeNode(node); this.addToFront(node); } addToFront(node) { node.prev = undefined; node.next = this.head; if (this.head) { this.head.prev = node; } this.head = node; if (!this.tail) { this.tail = node; } } removeNode(node) { if (node.prev) { node.prev.next = node.next; } else { this.head = node.next; } if (node.next) { node.next.prev = node.prev; } else { this.tail = node.prev; } } evictLRU() { if (this.tail) { this.cache.delete(this.tail.key); this.removeNode(this.tail); } } cleanup() { const now = Date.now(); const expiredKeys = []; for (const [key, node] of this.cache.entries()) { if (now - node.value.timestamp > this.ttl) { expiredKeys.push(key); } } for (const key of expiredKeys) { this.delete(key); } } destroy() { if (this.cleanupInterval) { clearInterval(this.cleanupInterval); } this.clear(); } } exports.HighPerformanceCache = HighPerformanceCache; class QueryCache { constructor(maxSize = 1000, ttl = 300000) { this.cache = new HighPerformanceCache(maxSize, ttl); } computeCacheKey(collection, vector, topK, params = {}) { const queryData = { collection, vector: this.hashVector(vector), topK, ...params }; const hash = (0, crypto_1.createHash)('sha256') .update(JSON.stringify(queryData)) .digest('hex'); return `${collection}:${hash.substring(0, 16)}`; } hashVector(vector) { if (vector.length <= 100) { return (0, crypto_1.createHash)('md5').update(vector.join(',')).digest('hex'); } // For large vectors, sample key points const samples = []; const step = Math.floor(vector.length / 20); for (let i = 0; i < vector.length; i += step) { samples.push(vector[i]); } return (0, crypto_1.createHash)('md5').update(samples.join(',')).digest('hex'); } get(key) { return this.cache.get(key); } set(key, value) { this.cache.set(key, value); } clear() { this.cache.clear(); } getStats() { return this.cache.getStats(); } destroy() { this.cache.destroy(); } } exports.QueryCache = QueryCache; class BufferPool { constructor(maxPoolSize = 50) { this.pools = new Map(); this.maxPoolSize = maxPoolSize; this.sizes = [1024, 4096, 16384, 65536, 262144]; // pre-allocate initial buffers for (const size of this.sizes) { this.pools.set(size, []); for (let i = 0; i < 10; i++) { this.pools.get(size).push(Buffer.allocUnsafe(size)); } } } acquire(size) { const poolSize = this.sizes.find(s => s >= size); if (!poolSize) { return Buffer.allocUnsafe(size); } const pool = this.pools.get(poolSize); if (pool && pool.length > 0) { const buffer = pool.pop(); return buffer.subarray(0, size); } return Buffer.allocUnsafe(size); } release(buffer) { const originalSize = this.getOriginalSize(buffer); if (!originalSize) return; const pool = this.pools.get(originalSize); if (pool && pool.length < this.maxPoolSize) { buffer.fill(0); pool.push(buffer); } } getOriginalSize(buffer) { return this.sizes.find(size => buffer.length <= size); } clear() { this.pools.clear(); } getStats() { const stats = {}; for (const [size, pool] of this.pools) { stats[`pool_${size}`] = pool.length; } return stats; } } exports.BufferPool = BufferPool;