@topgunbuild/server 0.8.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +97 -0
- package/dist/index.d.mts +1569 -1461
- package/dist/index.d.ts +1569 -1461
- package/dist/index.js +2138 -262
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2081 -194
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -12
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _topgunbuild_core from '@topgunbuild/core';
|
|
2
|
-
import { Timestamp, LWWRecord, ORMapRecord, Principal, EventJournalImpl, EventJournalConfig, JournalEvent,
|
|
2
|
+
import { Timestamp, LWWRecord, ORMapRecord, Principal, EventJournalImpl, EventJournalConfig, JournalEvent, SearchUpdateType, FullTextIndexConfig, FTSSearchOptions, SearchRespPayload, SearchOptions, MigrationConfig, MigrationStatus, MigrationMetrics, PartitionMap, PartitionInfo, PartitionChange, PermissionPolicy, ConsistencyLevel, ReplicationConfig, LWWMap, ORMap, PermissionType, ReplicationLag, ReplicationHealth, ReplicationResult, ClusterReadOptions, MerkleTree, EntryProcessorDef, EntryProcessorResult, HLC, MergeRejection, ConflictResolverDef, MergeContext, MergeResult, IndexedLWWMap, IndexedORMap } from '@topgunbuild/core';
|
|
3
3
|
import { WebSocket } from 'ws';
|
|
4
4
|
import { Pool, PoolConfig } from 'pg';
|
|
5
5
|
import pino from 'pino';
|
|
@@ -1782,1085 +1782,1454 @@ declare class EventJournalService extends EventJournalImpl {
|
|
|
1782
1782
|
getPendingPersistCount(): number;
|
|
1783
1783
|
}
|
|
1784
1784
|
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
eventQueueCapacity?: number;
|
|
1805
|
-
/** Number of event queue stripes for parallel processing (default: 4) */
|
|
1806
|
-
eventStripeCount?: number;
|
|
1807
|
-
/** Enable/disable backpressure (default: true) */
|
|
1808
|
-
backpressureEnabled?: boolean;
|
|
1809
|
-
/** How often to force sync processing (default: 100 operations) */
|
|
1810
|
-
backpressureSyncFrequency?: number;
|
|
1811
|
-
/** Maximum pending async operations before blocking (default: 1000) */
|
|
1812
|
-
backpressureMaxPending?: number;
|
|
1813
|
-
/** Backoff timeout in ms when at capacity (default: 5000) */
|
|
1814
|
-
backpressureBackoffMs?: number;
|
|
1815
|
-
/** Enable/disable write coalescing (default: true) */
|
|
1816
|
-
writeCoalescingEnabled?: boolean;
|
|
1817
|
-
/** Coalescing preset: 'conservative', 'balanced', 'highThroughput', 'aggressive' (default: 'highThroughput') */
|
|
1818
|
-
writeCoalescingPreset?: CoalescingPreset;
|
|
1819
|
-
/** Maximum messages to batch before forcing flush (default: 500 for highThroughput) */
|
|
1820
|
-
writeCoalescingMaxBatch?: number;
|
|
1821
|
-
/** Maximum delay before flushing in ms (default: 10 for highThroughput) */
|
|
1822
|
-
writeCoalescingMaxDelayMs?: number;
|
|
1823
|
-
/** Maximum batch size in bytes (default: 262144/256KB for highThroughput) */
|
|
1824
|
-
writeCoalescingMaxBytes?: number;
|
|
1825
|
-
/** WebSocket backlog for pending connections (default: 511) */
|
|
1826
|
-
wsBacklog?: number;
|
|
1827
|
-
/** Enable WebSocket per-message compression (default: false for CPU savings) */
|
|
1828
|
-
wsCompression?: boolean;
|
|
1829
|
-
/** Maximum WebSocket payload size in bytes (default: 64MB) */
|
|
1830
|
-
wsMaxPayload?: number;
|
|
1831
|
-
/** Maximum server connections (default: 10000) */
|
|
1832
|
-
maxConnections?: number;
|
|
1833
|
-
/** Server timeout in ms (default: 120000 = 2 min) */
|
|
1834
|
-
serverTimeout?: number;
|
|
1835
|
-
/** Keep-alive timeout in ms (default: 5000) */
|
|
1836
|
-
keepAliveTimeout?: number;
|
|
1837
|
-
/** Headers timeout in ms (default: 60000) */
|
|
1838
|
-
headersTimeout?: number;
|
|
1839
|
-
/** Enable connection rate limiting (default: true) */
|
|
1840
|
-
rateLimitingEnabled?: boolean;
|
|
1841
|
-
/** Maximum new connections per second (default: 100) */
|
|
1842
|
-
maxConnectionsPerSecond?: number;
|
|
1843
|
-
/** Maximum pending connections (default: 1000) */
|
|
1844
|
-
maxPendingConnections?: number;
|
|
1845
|
-
/** Enable worker pool for CPU-bound operations (default: false) */
|
|
1846
|
-
workerPoolEnabled?: boolean;
|
|
1847
|
-
/** Worker pool configuration */
|
|
1848
|
-
workerPoolConfig?: Partial<WorkerPoolConfig>;
|
|
1849
|
-
/** Default timeout for Write Concern acknowledgments in ms (default: 5000) */
|
|
1850
|
-
writeAckTimeout?: number;
|
|
1851
|
-
/** Enable replication to backup nodes (default: true when cluster has peers) */
|
|
1852
|
-
replicationEnabled?: boolean;
|
|
1853
|
-
/** Default consistency level for replication (default: EVENTUAL) */
|
|
1854
|
-
defaultConsistency?: ConsistencyLevel;
|
|
1855
|
-
/** Replication configuration */
|
|
1856
|
-
replicationConfig?: Partial<ReplicationConfig>;
|
|
1857
|
-
/** Enable event journal for audit/CDC (default: false) */
|
|
1858
|
-
eventJournalEnabled?: boolean;
|
|
1859
|
-
/** Event journal configuration */
|
|
1860
|
-
eventJournalConfig?: Partial<Omit<EventJournalServiceConfig, 'pool'>>;
|
|
1861
|
-
/** Enable full-text search for specific maps */
|
|
1862
|
-
fullTextSearch?: Record<string, FullTextIndexConfig>;
|
|
1785
|
+
/**
|
|
1786
|
+
* SearchCoordinator - Server-side Full-Text Search Handler
|
|
1787
|
+
*
|
|
1788
|
+
* Manages FullTextIndex instances per map and handles search requests.
|
|
1789
|
+
* Part of Phase 11.1a: Server-side BM25 Search.
|
|
1790
|
+
* Phase 11.1b: Live Search Subscriptions with delta updates.
|
|
1791
|
+
* Phase 14.2: Distributed Live Subscriptions support.
|
|
1792
|
+
*
|
|
1793
|
+
* @module search/SearchCoordinator
|
|
1794
|
+
*/
|
|
1795
|
+
|
|
1796
|
+
/**
|
|
1797
|
+
* Result item returned from server search.
|
|
1798
|
+
*/
|
|
1799
|
+
interface ServerSearchResult {
|
|
1800
|
+
key: string;
|
|
1801
|
+
value: unknown;
|
|
1802
|
+
score: number;
|
|
1803
|
+
matchedTerms: string[];
|
|
1863
1804
|
}
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1805
|
+
/**
|
|
1806
|
+
* Configuration for enabling search on a map.
|
|
1807
|
+
*/
|
|
1808
|
+
interface SearchConfig extends FullTextIndexConfig {
|
|
1809
|
+
}
|
|
1810
|
+
/**
|
|
1811
|
+
* Cached result for a document in a subscription.
|
|
1812
|
+
*/
|
|
1813
|
+
interface CachedResult {
|
|
1814
|
+
score: number;
|
|
1815
|
+
matchedTerms: string[];
|
|
1816
|
+
}
|
|
1817
|
+
/**
|
|
1818
|
+
* Represents a live search subscription.
|
|
1819
|
+
*/
|
|
1820
|
+
interface SearchSubscription {
|
|
1821
|
+
/** Unique subscription ID */
|
|
1822
|
+
id: string;
|
|
1823
|
+
/** ID of the subscribed client */
|
|
1824
|
+
clientId: string;
|
|
1825
|
+
/** Name of the map being searched */
|
|
1826
|
+
mapName: string;
|
|
1827
|
+
/** Original query string */
|
|
1828
|
+
query: string;
|
|
1829
|
+
/** Tokenized query terms for fast comparison */
|
|
1830
|
+
queryTerms: string[];
|
|
1831
|
+
/** Search options (limit, minScore, boost) */
|
|
1832
|
+
options: SearchOptions;
|
|
1833
|
+
/** Cache of current results for delta computation */
|
|
1834
|
+
currentResults: Map<string, CachedResult>;
|
|
1835
|
+
/** If set, send updates to this coordinator node instead of local client */
|
|
1836
|
+
coordinatorNodeId?: string;
|
|
1837
|
+
/** True if registered via CLUSTER_SUB_REGISTER */
|
|
1838
|
+
isDistributed?: boolean;
|
|
1839
|
+
}
|
|
1840
|
+
/**
|
|
1841
|
+
* Callback type for sending updates to clients.
|
|
1842
|
+
*/
|
|
1843
|
+
type SendUpdateCallback = (clientId: string, subscriptionId: string, key: string, value: unknown, score: number, matchedTerms: string[], type: SearchUpdateType) => void;
|
|
1844
|
+
/**
|
|
1845
|
+
* Batched update for a single document change.
|
|
1846
|
+
*/
|
|
1847
|
+
interface BatchedUpdate {
|
|
1848
|
+
key: string;
|
|
1849
|
+
value: unknown;
|
|
1850
|
+
score: number;
|
|
1851
|
+
matchedTerms: string[];
|
|
1852
|
+
type: SearchUpdateType;
|
|
1853
|
+
}
|
|
1854
|
+
/**
|
|
1855
|
+
* Callback type for sending batched updates to clients.
|
|
1856
|
+
*/
|
|
1857
|
+
type SendBatchUpdateCallback = (clientId: string, subscriptionId: string, updates: BatchedUpdate[]) => void;
|
|
1858
|
+
/**
|
|
1859
|
+
* SearchCoordinator manages full-text search indexes for the server.
|
|
1860
|
+
*
|
|
1861
|
+
* Responsibilities:
|
|
1862
|
+
* - Maintain FullTextIndex per enabled map
|
|
1863
|
+
* - Execute one-shot search queries
|
|
1864
|
+
* - Update indexes when data changes
|
|
1865
|
+
*
|
|
1866
|
+
* @example
|
|
1867
|
+
* ```typescript
|
|
1868
|
+
* const searchCoordinator = new SearchCoordinator();
|
|
1869
|
+
*
|
|
1870
|
+
* // Enable FTS for a map
|
|
1871
|
+
* searchCoordinator.enableSearch('articles', {
|
|
1872
|
+
* fields: ['title', 'body'],
|
|
1873
|
+
* tokenizer: { minLength: 2 },
|
|
1874
|
+
* bm25: { k1: 1.2, b: 0.75 }
|
|
1875
|
+
* });
|
|
1876
|
+
*
|
|
1877
|
+
* // Search
|
|
1878
|
+
* const results = searchCoordinator.search('articles', 'machine learning', {
|
|
1879
|
+
* limit: 20,
|
|
1880
|
+
* boost: { title: 2.0 }
|
|
1881
|
+
* });
|
|
1882
|
+
* ```
|
|
1883
|
+
*/
|
|
1884
|
+
declare class SearchCoordinator extends EventEmitter {
|
|
1885
|
+
/** Map name → FullTextIndex */
|
|
1886
|
+
private readonly indexes;
|
|
1887
|
+
/** Map name → FullTextIndexConfig (for reference) */
|
|
1888
|
+
private readonly configs;
|
|
1889
|
+
/** Callback to get document value by key (injected by ServerCoordinator) */
|
|
1890
|
+
private getDocumentValue?;
|
|
1891
|
+
/** Subscription ID → SearchSubscription */
|
|
1892
|
+
private readonly subscriptions;
|
|
1893
|
+
/** Map name → Set of subscription IDs */
|
|
1894
|
+
private readonly subscriptionsByMap;
|
|
1895
|
+
/** Client ID → Set of subscription IDs */
|
|
1896
|
+
private readonly subscriptionsByClient;
|
|
1897
|
+
/** Callback for sending updates to clients */
|
|
1898
|
+
private sendUpdate?;
|
|
1899
|
+
/** Callback for sending batched updates to clients */
|
|
1900
|
+
private sendBatchUpdate?;
|
|
1901
|
+
/** Queue of pending notifications per map */
|
|
1902
|
+
private readonly pendingNotifications;
|
|
1903
|
+
/** Timer for batching notifications */
|
|
1904
|
+
private notificationTimer;
|
|
1905
|
+
/** Batch interval in milliseconds (~1 frame at 60fps) */
|
|
1906
|
+
private readonly BATCH_INTERVAL;
|
|
1907
|
+
/** Node ID for this server (set during init) */
|
|
1908
|
+
private nodeId?;
|
|
1909
|
+
constructor();
|
|
1918
1910
|
/**
|
|
1919
|
-
*
|
|
1920
|
-
*
|
|
1911
|
+
* Set the node ID for this server.
|
|
1912
|
+
* Required for distributed subscriptions.
|
|
1921
1913
|
*/
|
|
1922
|
-
|
|
1923
|
-
/** Wait for server to be fully ready (ports assigned) */
|
|
1924
|
-
ready(): Promise<void>;
|
|
1914
|
+
setNodeId(nodeId: string): void;
|
|
1925
1915
|
/**
|
|
1926
|
-
*
|
|
1927
|
-
*
|
|
1916
|
+
* Set the callback for sending updates to clients.
|
|
1917
|
+
* Called by ServerCoordinator during initialization.
|
|
1928
1918
|
*/
|
|
1929
|
-
|
|
1930
|
-
/**
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
/**
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
/**
|
|
1951
|
-
|
|
1952
|
-
|
|
1919
|
+
setSendUpdateCallback(callback: SendUpdateCallback): void;
|
|
1920
|
+
/**
|
|
1921
|
+
* Set the callback for sending batched updates to clients.
|
|
1922
|
+
* When set, notifications are batched within BATCH_INTERVAL (16ms) window.
|
|
1923
|
+
* Called by ServerCoordinator during initialization.
|
|
1924
|
+
*
|
|
1925
|
+
* @param callback - Function to call with batched updates
|
|
1926
|
+
*/
|
|
1927
|
+
setSendBatchUpdateCallback(callback: SendBatchUpdateCallback): void;
|
|
1928
|
+
/**
|
|
1929
|
+
* Set the callback for retrieving document values.
|
|
1930
|
+
* Called by ServerCoordinator during initialization.
|
|
1931
|
+
*/
|
|
1932
|
+
setDocumentValueGetter(getter: (mapName: string, key: string) => unknown | undefined): void;
|
|
1933
|
+
/**
|
|
1934
|
+
* Enable full-text search for a map.
|
|
1935
|
+
*
|
|
1936
|
+
* @param mapName - Name of the map to enable FTS for
|
|
1937
|
+
* @param config - FTS configuration (fields, tokenizer, bm25 options)
|
|
1938
|
+
*/
|
|
1939
|
+
enableSearch(mapName: string, config: SearchConfig): void;
|
|
1940
|
+
/**
|
|
1941
|
+
* Disable full-text search for a map.
|
|
1942
|
+
*
|
|
1943
|
+
* @param mapName - Name of the map to disable FTS for
|
|
1944
|
+
*/
|
|
1945
|
+
disableSearch(mapName: string): void;
|
|
1946
|
+
/**
|
|
1947
|
+
* Check if FTS is enabled for a map.
|
|
1948
|
+
*/
|
|
1949
|
+
isSearchEnabled(mapName: string): boolean;
|
|
1950
|
+
/**
|
|
1951
|
+
* Get enabled map names.
|
|
1952
|
+
*/
|
|
1953
|
+
getEnabledMaps(): string[];
|
|
1954
|
+
/**
|
|
1955
|
+
* Execute a one-shot search query.
|
|
1956
|
+
*
|
|
1957
|
+
* @param mapName - Name of the map to search
|
|
1958
|
+
* @param query - Search query text
|
|
1959
|
+
* @param options - Search options (limit, minScore, boost)
|
|
1960
|
+
* @returns Search response payload
|
|
1961
|
+
*/
|
|
1962
|
+
search(mapName: string, query: string, options?: FTSSearchOptions): SearchRespPayload;
|
|
1963
|
+
/**
|
|
1964
|
+
* Handle document set/update.
|
|
1965
|
+
* Called by ServerCoordinator when data changes.
|
|
1966
|
+
*
|
|
1967
|
+
* @param mapName - Name of the map
|
|
1968
|
+
* @param key - Document key
|
|
1969
|
+
* @param value - Document value
|
|
1970
|
+
*/
|
|
1971
|
+
onDataChange(mapName: string, key: string, value: Record<string, unknown> | null | undefined, changeType: 'add' | 'update' | 'remove'): void;
|
|
1972
|
+
/**
|
|
1973
|
+
* Build index from existing map entries.
|
|
1974
|
+
* Called when FTS is enabled for a map that already has data.
|
|
1975
|
+
*
|
|
1976
|
+
* @param mapName - Name of the map
|
|
1977
|
+
* @param entries - Iterator of [key, value] tuples
|
|
1978
|
+
*/
|
|
1979
|
+
buildIndexFromEntries(mapName: string, entries: Iterable<[string, Record<string, unknown> | null]>): void;
|
|
1980
|
+
/**
|
|
1981
|
+
* Get index statistics for monitoring.
|
|
1982
|
+
*/
|
|
1983
|
+
getIndexStats(mapName: string): {
|
|
1984
|
+
documentCount: number;
|
|
1985
|
+
fields: string[];
|
|
1986
|
+
} | null;
|
|
1987
|
+
/**
|
|
1988
|
+
* Clear all indexes (for testing or shutdown).
|
|
1989
|
+
*/
|
|
1990
|
+
clear(): void;
|
|
1991
|
+
/**
|
|
1992
|
+
* Subscribe to live search results.
|
|
1993
|
+
* Returns initial results and tracks the subscription for delta updates.
|
|
1994
|
+
*
|
|
1995
|
+
* @param clientId - ID of the subscribing client
|
|
1996
|
+
* @param subscriptionId - Unique subscription identifier
|
|
1997
|
+
* @param mapName - Name of the map to search
|
|
1998
|
+
* @param query - Search query text
|
|
1999
|
+
* @param options - Search options (limit, minScore, boost)
|
|
2000
|
+
* @returns Initial search results
|
|
2001
|
+
*/
|
|
2002
|
+
subscribe(clientId: string, subscriptionId: string, mapName: string, query: string, options?: SearchOptions): ServerSearchResult[];
|
|
2003
|
+
/**
|
|
2004
|
+
* Unsubscribe from a live search.
|
|
2005
|
+
*
|
|
2006
|
+
* @param subscriptionId - Subscription to remove
|
|
2007
|
+
*/
|
|
2008
|
+
unsubscribe(subscriptionId: string): void;
|
|
2009
|
+
/**
|
|
2010
|
+
* Unsubscribe all subscriptions for a client.
|
|
2011
|
+
* Called when a client disconnects.
|
|
2012
|
+
*
|
|
2013
|
+
* @param clientId - ID of the disconnected client
|
|
2014
|
+
*/
|
|
2015
|
+
unsubscribeClient(clientId: string): void;
|
|
2016
|
+
/**
|
|
2017
|
+
* Get the number of active subscriptions.
|
|
2018
|
+
*/
|
|
2019
|
+
getSubscriptionCount(): number;
|
|
2020
|
+
/**
|
|
2021
|
+
* Register a distributed subscription from a remote coordinator.
|
|
2022
|
+
* Called when receiving CLUSTER_SUB_REGISTER message.
|
|
2023
|
+
*
|
|
2024
|
+
* @param subscriptionId - Unique subscription ID
|
|
2025
|
+
* @param mapName - Map name to search
|
|
2026
|
+
* @param query - Search query string
|
|
2027
|
+
* @param options - Search options
|
|
2028
|
+
* @param coordinatorNodeId - Node ID of the coordinator (receives updates)
|
|
2029
|
+
* @returns Initial search results from this node
|
|
2030
|
+
*/
|
|
2031
|
+
registerDistributedSubscription(subscriptionId: string, mapName: string, query: string, options: SearchOptions, coordinatorNodeId: string): {
|
|
2032
|
+
results: ServerSearchResult[];
|
|
2033
|
+
totalHits: number;
|
|
1953
2034
|
};
|
|
1954
|
-
/** Get tasklet scheduler stats for monitoring cooperative multitasking */
|
|
1955
|
-
getTaskletSchedulerStats(): TaskletSchedulerStats;
|
|
1956
|
-
/** Get tasklet scheduler for scheduling long-running operations */
|
|
1957
|
-
getTaskletScheduler(): TaskletScheduler;
|
|
1958
2035
|
/**
|
|
1959
|
-
*
|
|
1960
|
-
*
|
|
2036
|
+
* Get a distributed subscription by ID.
|
|
2037
|
+
* Returns undefined if not found or not distributed.
|
|
2038
|
+
*/
|
|
2039
|
+
getDistributedSubscription(subscriptionId: string): SearchSubscription | undefined;
|
|
2040
|
+
/**
|
|
2041
|
+
* Unsubscribe all distributed subscriptions where the given node was the coordinator.
|
|
2042
|
+
* Called when a cluster node disconnects.
|
|
2043
|
+
*
|
|
2044
|
+
* @param coordinatorNodeId - Node ID of the disconnected coordinator
|
|
2045
|
+
*/
|
|
2046
|
+
unsubscribeByCoordinator(coordinatorNodeId: string): void;
|
|
2047
|
+
/**
|
|
2048
|
+
* Notify subscribers about a document change.
|
|
2049
|
+
* Computes delta (ENTER/UPDATE/LEAVE) for each affected subscription.
|
|
2050
|
+
* For distributed subscriptions, emits 'distributedUpdate' event instead of sending to client.
|
|
2051
|
+
*
|
|
2052
|
+
* @param mapName - Name of the map that changed
|
|
2053
|
+
* @param key - Document key that changed
|
|
2054
|
+
* @param value - New document value (null if removed)
|
|
2055
|
+
* @param changeType - Type of change
|
|
2056
|
+
*/
|
|
2057
|
+
private notifySubscribers;
|
|
2058
|
+
/**
|
|
2059
|
+
* Send update to remote coordinator node for a distributed subscription.
|
|
2060
|
+
* Emits 'distributedUpdate' event with ClusterSubUpdatePayload.
|
|
1961
2061
|
*
|
|
1962
|
-
* @param
|
|
1963
|
-
* @param
|
|
2062
|
+
* @param sub - The distributed subscription
|
|
2063
|
+
* @param key - Document key
|
|
2064
|
+
* @param value - Document value
|
|
2065
|
+
* @param score - Search score
|
|
2066
|
+
* @param matchedTerms - Matched search terms
|
|
2067
|
+
* @param changeType - Change type (ENTER/UPDATE/LEAVE)
|
|
1964
2068
|
*/
|
|
1965
|
-
|
|
2069
|
+
private sendDistributedUpdate;
|
|
1966
2070
|
/**
|
|
1967
|
-
*
|
|
2071
|
+
* Score a single document against a subscription's query.
|
|
1968
2072
|
*
|
|
1969
|
-
*
|
|
2073
|
+
* OPTIMIZED: O(Q × D) complexity instead of O(N) full index scan.
|
|
2074
|
+
* Uses pre-tokenized queryTerms and FullTextIndex.scoreSingleDocument().
|
|
2075
|
+
*
|
|
2076
|
+
* @param subscription - The subscription containing query and cached queryTerms
|
|
2077
|
+
* @param key - Document key
|
|
2078
|
+
* @param value - Document value
|
|
2079
|
+
* @param index - The FullTextIndex for this map
|
|
2080
|
+
* @returns Scored result or null if document doesn't match
|
|
1970
2081
|
*/
|
|
1971
|
-
|
|
2082
|
+
private scoreDocument;
|
|
1972
2083
|
/**
|
|
1973
|
-
*
|
|
2084
|
+
* Queue a notification for batched processing.
|
|
2085
|
+
* Notifications are collected and processed together after BATCH_INTERVAL.
|
|
1974
2086
|
*
|
|
1975
|
-
* @param mapName - Name of the map
|
|
1976
|
-
* @
|
|
2087
|
+
* @param mapName - Name of the map that changed
|
|
2088
|
+
* @param key - Document key that changed
|
|
2089
|
+
* @param value - New document value (null if removed)
|
|
2090
|
+
* @param changeType - Type of change
|
|
1977
2091
|
*/
|
|
1978
|
-
|
|
2092
|
+
queueNotification(mapName: string, key: string, value: Record<string, unknown> | null, changeType: 'add' | 'update' | 'remove'): void;
|
|
1979
2093
|
/**
|
|
1980
|
-
*
|
|
1981
|
-
*
|
|
1982
|
-
* @param mapName - Name of the map
|
|
1983
|
-
* @returns Index stats or null if FTS not enabled
|
|
2094
|
+
* Schedule a flush of pending notifications.
|
|
2095
|
+
* Uses setTimeout to batch notifications within BATCH_INTERVAL window.
|
|
1984
2096
|
*/
|
|
1985
|
-
|
|
1986
|
-
documentCount: number;
|
|
1987
|
-
fields: string[];
|
|
1988
|
-
} | null;
|
|
2097
|
+
private scheduleNotificationFlush;
|
|
1989
2098
|
/**
|
|
1990
|
-
*
|
|
1991
|
-
*
|
|
1992
|
-
* Notifies the cluster that this node is leaving and allows time for:
|
|
1993
|
-
* 1. Pending replication to complete
|
|
1994
|
-
* 2. Other nodes to detect departure
|
|
1995
|
-
* 3. Partition reassignment to begin
|
|
2099
|
+
* Flush all pending notifications.
|
|
2100
|
+
* Processes each map's notifications and sends batched updates.
|
|
1996
2101
|
*/
|
|
1997
|
-
|
|
2102
|
+
flushNotifications(): void;
|
|
1998
2103
|
/**
|
|
1999
|
-
*
|
|
2104
|
+
* Process batched notifications for a single map.
|
|
2105
|
+
* Computes updates for each subscription and sends as a batch.
|
|
2106
|
+
*
|
|
2107
|
+
* @param mapName - Name of the map
|
|
2108
|
+
* @param notifications - Array of pending notifications
|
|
2000
2109
|
*/
|
|
2001
|
-
private
|
|
2110
|
+
private processBatchedNotifications;
|
|
2002
2111
|
/**
|
|
2003
|
-
*
|
|
2112
|
+
* Compute the update for a single document change against a subscription.
|
|
2113
|
+
* Returns null if no update is needed.
|
|
2114
|
+
*
|
|
2115
|
+
* @param subscription - The subscription to check
|
|
2116
|
+
* @param key - Document key
|
|
2117
|
+
* @param value - Document value (null if removed)
|
|
2118
|
+
* @param changeType - Type of change
|
|
2119
|
+
* @param index - The FullTextIndex for this map
|
|
2120
|
+
* @returns BatchedUpdate or null
|
|
2004
2121
|
*/
|
|
2005
|
-
private
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2122
|
+
private computeSubscriptionUpdate;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
/**
|
|
2126
|
+
* FailureDetector - Phi Accrual Failure Detector
|
|
2127
|
+
*
|
|
2128
|
+
* Implements the Phi Accrual Failure Detection algorithm for distributed systems.
|
|
2129
|
+
* Based on the paper: "The φ Accrual Failure Detector" by Hayashibara et al.
|
|
2130
|
+
*
|
|
2131
|
+
* The detector provides a suspicion level (phi) rather than binary alive/dead status,
|
|
2132
|
+
* allowing the application to make decisions based on configurable thresholds.
|
|
2133
|
+
*
|
|
2134
|
+
* Hazelcast equivalent: com.hazelcast.internal.cluster.fd.PhiAccrualFailureDetector
|
|
2135
|
+
*/
|
|
2136
|
+
|
|
2137
|
+
interface FailureDetectorConfig {
|
|
2138
|
+
/** Interval between heartbeat checks (ms). Default: 1000 */
|
|
2139
|
+
heartbeatIntervalMs: number;
|
|
2140
|
+
/** Time after which a node is suspected if no heartbeat received (ms). Default: 5000 */
|
|
2141
|
+
suspicionTimeoutMs: number;
|
|
2142
|
+
/** Time after suspicion before confirming failure (ms). Default: 10000 */
|
|
2143
|
+
confirmationTimeoutMs: number;
|
|
2144
|
+
/** Phi threshold above which a node is considered suspected. Default: 8 */
|
|
2145
|
+
phiThreshold: number;
|
|
2146
|
+
/** Minimum samples required for accurate phi calculation. Default: 10 */
|
|
2147
|
+
minSamples: number;
|
|
2148
|
+
/** Maximum samples to keep in history. Default: 100 */
|
|
2149
|
+
maxSamples: number;
|
|
2150
|
+
/** Initial heartbeat interval estimate (ms). Default: 1000 */
|
|
2151
|
+
initialHeartbeatIntervalMs: number;
|
|
2152
|
+
}
|
|
2153
|
+
declare const DEFAULT_FAILURE_DETECTOR_CONFIG: FailureDetectorConfig;
|
|
2154
|
+
interface NodeState {
|
|
2155
|
+
/** Last heartbeat timestamp */
|
|
2156
|
+
lastHeartbeat: number;
|
|
2157
|
+
/** Heartbeat interval history for phi calculation */
|
|
2158
|
+
intervalHistory: number[];
|
|
2159
|
+
/** Whether node is currently suspected */
|
|
2160
|
+
isSuspected: boolean;
|
|
2161
|
+
/** Timestamp when suspicion started */
|
|
2162
|
+
suspicionStartTime?: number;
|
|
2163
|
+
/** Whether failure has been confirmed */
|
|
2164
|
+
isConfirmedFailed: boolean;
|
|
2165
|
+
}
|
|
2166
|
+
interface FailureDetectorEvents {
|
|
2167
|
+
nodeSuspected: {
|
|
2168
|
+
nodeId: string;
|
|
2169
|
+
phi: number;
|
|
2170
|
+
};
|
|
2171
|
+
nodeRecovered: {
|
|
2172
|
+
nodeId: string;
|
|
2173
|
+
};
|
|
2174
|
+
nodeConfirmedFailed: {
|
|
2175
|
+
nodeId: string;
|
|
2176
|
+
};
|
|
2177
|
+
}
|
|
2178
|
+
declare class FailureDetector extends EventEmitter {
|
|
2179
|
+
private config;
|
|
2180
|
+
private nodeStates;
|
|
2181
|
+
private monitoringNodes;
|
|
2182
|
+
private checkTimer?;
|
|
2183
|
+
private confirmationTimers;
|
|
2184
|
+
private started;
|
|
2185
|
+
constructor(config?: Partial<FailureDetectorConfig>);
|
|
2010
2186
|
/**
|
|
2011
|
-
*
|
|
2012
|
-
* Called when partition topology changes (node join/leave/failover).
|
|
2187
|
+
* Start the failure detector monitoring loop.
|
|
2013
2188
|
*/
|
|
2014
|
-
|
|
2189
|
+
start(): void;
|
|
2015
2190
|
/**
|
|
2016
|
-
*
|
|
2017
|
-
* Finds the client by node ID and sends MERGE_REJECTED message.
|
|
2191
|
+
* Stop the failure detector and clean up.
|
|
2018
2192
|
*/
|
|
2019
|
-
|
|
2020
|
-
private broadcast;
|
|
2193
|
+
stop(): void;
|
|
2021
2194
|
/**
|
|
2022
|
-
*
|
|
2023
|
-
* Groups clients by their permission roles and serializes once per group.
|
|
2024
|
-
* Also batches multiple events into a single SERVER_BATCH_EVENT message.
|
|
2025
|
-
* === OPTIMIZATION 4: Subscription-based Routing ===
|
|
2026
|
-
* Only sends events to clients with active subscriptions for affected maps.
|
|
2195
|
+
* Start monitoring a node.
|
|
2027
2196
|
*/
|
|
2028
|
-
|
|
2197
|
+
startMonitoring(nodeId: string): void;
|
|
2029
2198
|
/**
|
|
2030
|
-
*
|
|
2199
|
+
* Stop monitoring a node.
|
|
2031
2200
|
*/
|
|
2032
|
-
|
|
2201
|
+
stopMonitoring(nodeId: string): void;
|
|
2033
2202
|
/**
|
|
2034
|
-
*
|
|
2035
|
-
*
|
|
2036
|
-
* Used when backpressure forces sync processing to drain the pipeline.
|
|
2203
|
+
* Record a heartbeat from a node.
|
|
2204
|
+
* This updates the node's state and clears any suspicion.
|
|
2037
2205
|
*/
|
|
2038
|
-
|
|
2039
|
-
private setupClusterListeners;
|
|
2040
|
-
private executeLocalQuery;
|
|
2206
|
+
recordHeartbeat(nodeId: string): void;
|
|
2041
2207
|
/**
|
|
2042
|
-
*
|
|
2043
|
-
* Returns null if conversion is not possible (complex queries).
|
|
2208
|
+
* Check all monitored nodes for failure.
|
|
2044
2209
|
*/
|
|
2045
|
-
private
|
|
2210
|
+
private checkAllNodes;
|
|
2046
2211
|
/**
|
|
2047
|
-
*
|
|
2212
|
+
* Schedule failure confirmation after suspicion timeout.
|
|
2048
2213
|
*/
|
|
2049
|
-
private
|
|
2214
|
+
private scheduleConfirmation;
|
|
2050
2215
|
/**
|
|
2051
|
-
*
|
|
2216
|
+
* Confirm node failure after confirmation timeout.
|
|
2052
2217
|
*/
|
|
2053
|
-
private
|
|
2054
|
-
private finalizeClusterQuery;
|
|
2218
|
+
private confirmFailure;
|
|
2055
2219
|
/**
|
|
2056
|
-
*
|
|
2057
|
-
* Handles map merge, storage persistence, query evaluation, and event generation.
|
|
2220
|
+
* Calculate the phi value for a node using the Phi Accrual algorithm.
|
|
2058
2221
|
*
|
|
2059
|
-
*
|
|
2222
|
+
* Phi = -log10(P_later(t_now - t_last))
|
|
2223
|
+
*
|
|
2224
|
+
* where P_later is the probability that a heartbeat will arrive later than expected.
|
|
2060
2225
|
*/
|
|
2061
|
-
|
|
2226
|
+
calculatePhi(nodeId: string): number;
|
|
2062
2227
|
/**
|
|
2063
|
-
*
|
|
2228
|
+
* Calculate mean of an array of numbers.
|
|
2064
2229
|
*/
|
|
2065
|
-
private
|
|
2230
|
+
private calculateMean;
|
|
2066
2231
|
/**
|
|
2067
|
-
*
|
|
2068
|
-
* This is called when we receive a replicated operation as a backup node
|
|
2232
|
+
* Calculate variance of an array of numbers.
|
|
2069
2233
|
*/
|
|
2070
|
-
private
|
|
2234
|
+
private calculateVariance;
|
|
2071
2235
|
/**
|
|
2072
|
-
*
|
|
2236
|
+
* Get list of currently suspected nodes.
|
|
2073
2237
|
*/
|
|
2074
|
-
|
|
2238
|
+
getSuspectedNodes(): string[];
|
|
2075
2239
|
/**
|
|
2076
|
-
*
|
|
2240
|
+
* Get list of confirmed failed nodes.
|
|
2077
2241
|
*/
|
|
2078
|
-
|
|
2242
|
+
getConfirmedFailedNodes(): string[];
|
|
2079
2243
|
/**
|
|
2080
|
-
*
|
|
2244
|
+
* Check if a specific node is suspected.
|
|
2081
2245
|
*/
|
|
2082
|
-
|
|
2083
|
-
private handleLockGranted;
|
|
2084
|
-
private processLocalOp;
|
|
2246
|
+
isSuspected(nodeId: string): boolean;
|
|
2085
2247
|
/**
|
|
2086
|
-
*
|
|
2087
|
-
* Processes validated operations asynchronously after ACK has been sent.
|
|
2088
|
-
* Uses BackpressureRegulator to periodically force sync processing and
|
|
2089
|
-
* prevent unbounded accumulation of async work.
|
|
2248
|
+
* Check if a specific node's failure is confirmed.
|
|
2090
2249
|
*/
|
|
2091
|
-
|
|
2250
|
+
isConfirmedFailed(nodeId: string): boolean;
|
|
2092
2251
|
/**
|
|
2093
|
-
*
|
|
2094
|
-
* Processes operations synchronously, waiting for broadcast completion.
|
|
2095
|
-
* Used when backpressure forces sync to drain the pipeline.
|
|
2252
|
+
* Get the current phi value for a node.
|
|
2096
2253
|
*/
|
|
2097
|
-
|
|
2254
|
+
getPhi(nodeId: string): number;
|
|
2098
2255
|
/**
|
|
2099
|
-
*
|
|
2100
|
-
* Used in sync processing mode.
|
|
2256
|
+
* Get all monitored nodes.
|
|
2101
2257
|
*/
|
|
2102
|
-
|
|
2258
|
+
getMonitoredNodes(): string[];
|
|
2259
|
+
/**
|
|
2260
|
+
* Get metrics for monitoring.
|
|
2261
|
+
*/
|
|
2262
|
+
getMetrics(): {
|
|
2263
|
+
monitoredNodes: number;
|
|
2264
|
+
suspectedNodes: number;
|
|
2265
|
+
confirmedFailedNodes: number;
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
interface ClusterConfig {
|
|
2270
|
+
nodeId: string;
|
|
2271
|
+
host: string;
|
|
2272
|
+
port: number;
|
|
2273
|
+
peers: string[];
|
|
2274
|
+
discovery?: 'manual' | 'kubernetes';
|
|
2275
|
+
serviceName?: string;
|
|
2276
|
+
discoveryInterval?: number;
|
|
2277
|
+
tls?: ClusterTLSConfig;
|
|
2278
|
+
/** Heartbeat interval in milliseconds. Default: 1000 */
|
|
2279
|
+
heartbeatIntervalMs?: number;
|
|
2280
|
+
/** Failure detection configuration */
|
|
2281
|
+
failureDetection?: Partial<FailureDetectorConfig>;
|
|
2282
|
+
}
|
|
2283
|
+
interface ClusterMember {
|
|
2284
|
+
nodeId: string;
|
|
2285
|
+
host: string;
|
|
2286
|
+
port: number;
|
|
2287
|
+
socket: WebSocket;
|
|
2288
|
+
isSelf: boolean;
|
|
2289
|
+
}
|
|
2290
|
+
interface ClusterMessage {
|
|
2291
|
+
type: 'HELLO' | 'MEMBER_LIST' | 'OP_FORWARD' | 'PARTITION_UPDATE' | 'HEARTBEAT' | 'CLUSTER_EVENT' | 'CLUSTER_QUERY_EXEC' | 'CLUSTER_QUERY_RESP' | 'CLUSTER_GC_REPORT' | 'CLUSTER_GC_COMMIT' | 'CLUSTER_LOCK_REQ' | 'CLUSTER_LOCK_RELEASE' | 'CLUSTER_LOCK_GRANTED' | 'CLUSTER_LOCK_RELEASED' | 'CLUSTER_CLIENT_DISCONNECTED' | 'CLUSTER_TOPIC_PUB' | 'CLUSTER_MERKLE_ROOT_REQ' | 'CLUSTER_MERKLE_ROOT_RESP' | 'CLUSTER_MERKLE_BUCKETS_REQ' | 'CLUSTER_MERKLE_BUCKETS_RESP' | 'CLUSTER_MERKLE_KEYS_REQ' | 'CLUSTER_MERKLE_KEYS_RESP' | 'CLUSTER_REPAIR_DATA_REQ' | 'CLUSTER_REPAIR_DATA_RESP' | 'CLUSTER_SEARCH_REQ' | 'CLUSTER_SEARCH_RESP' | 'CLUSTER_SEARCH_SUBSCRIBE' | 'CLUSTER_SEARCH_UNSUBSCRIBE' | 'CLUSTER_SEARCH_UPDATE' | 'CLUSTER_SUB_REGISTER' | 'CLUSTER_SUB_ACK' | 'CLUSTER_SUB_UPDATE' | 'CLUSTER_SUB_UNREGISTER';
|
|
2292
|
+
senderId: string;
|
|
2293
|
+
payload: any;
|
|
2294
|
+
}
|
|
2295
|
+
declare class ClusterManager extends EventEmitter {
|
|
2296
|
+
readonly config: ClusterConfig;
|
|
2297
|
+
private server?;
|
|
2298
|
+
private members;
|
|
2299
|
+
private pendingConnections;
|
|
2300
|
+
private reconnectIntervals;
|
|
2301
|
+
private discoveryTimer?;
|
|
2302
|
+
private heartbeatTimer?;
|
|
2303
|
+
private failureDetector;
|
|
2304
|
+
constructor(config: ClusterConfig);
|
|
2103
2305
|
/**
|
|
2104
|
-
*
|
|
2105
|
-
* Uses shared applyOpToMap but collects events instead of broadcasting immediately.
|
|
2306
|
+
* Get the failure detector instance.
|
|
2106
2307
|
*/
|
|
2107
|
-
|
|
2108
|
-
private
|
|
2109
|
-
|
|
2308
|
+
getFailureDetector(): FailureDetector;
|
|
2309
|
+
private _actualPort;
|
|
2310
|
+
/** Get the actual port the cluster is listening on */
|
|
2311
|
+
get port(): number;
|
|
2312
|
+
start(): Promise<number>;
|
|
2313
|
+
/** Called when server is ready - registers self and initiates peer connections */
|
|
2314
|
+
private onServerReady;
|
|
2315
|
+
stop(): void;
|
|
2110
2316
|
/**
|
|
2111
|
-
*
|
|
2112
|
-
* Use this for queries to avoid returning empty results during initial load.
|
|
2317
|
+
* Start sending heartbeats to all peers.
|
|
2113
2318
|
*/
|
|
2114
|
-
|
|
2319
|
+
private startHeartbeat;
|
|
2115
2320
|
/**
|
|
2116
|
-
*
|
|
2117
|
-
* Returns the LWWRecord for a key, used by RepairScheduler
|
|
2321
|
+
* Stop sending heartbeats.
|
|
2118
2322
|
*/
|
|
2119
|
-
private
|
|
2323
|
+
private stopHeartbeat;
|
|
2120
2324
|
/**
|
|
2121
|
-
*
|
|
2122
|
-
* Used by RepairScheduler to apply resolved conflicts
|
|
2325
|
+
* Send heartbeat to all connected peers.
|
|
2123
2326
|
*/
|
|
2124
|
-
private
|
|
2125
|
-
private loadMapFromStorage;
|
|
2126
|
-
private startGarbageCollection;
|
|
2327
|
+
private sendHeartbeatToAll;
|
|
2127
2328
|
/**
|
|
2128
|
-
*
|
|
2329
|
+
* Handle incoming heartbeat from a peer.
|
|
2129
2330
|
*/
|
|
2130
|
-
private
|
|
2331
|
+
private handleHeartbeat;
|
|
2131
2332
|
/**
|
|
2132
|
-
*
|
|
2133
|
-
*
|
|
2333
|
+
* Send current member list to a specific node (gossip protocol).
|
|
2334
|
+
* Called when a new node joins to propagate cluster topology.
|
|
2134
2335
|
*/
|
|
2135
|
-
private
|
|
2336
|
+
private sendMemberList;
|
|
2136
2337
|
/**
|
|
2137
|
-
*
|
|
2338
|
+
* Broadcast member list to all connected nodes.
|
|
2339
|
+
* Called when cluster membership changes.
|
|
2138
2340
|
*/
|
|
2139
|
-
|
|
2341
|
+
private broadcastMemberList;
|
|
2140
2342
|
/**
|
|
2141
|
-
*
|
|
2343
|
+
* Handle incoming member list from a peer (gossip protocol).
|
|
2344
|
+
* Attempts to connect to unknown members.
|
|
2142
2345
|
*/
|
|
2143
|
-
|
|
2346
|
+
private handleMemberList;
|
|
2144
2347
|
/**
|
|
2145
|
-
*
|
|
2348
|
+
* Handle confirmed node failure.
|
|
2146
2349
|
*/
|
|
2147
|
-
private
|
|
2148
|
-
private
|
|
2149
|
-
private
|
|
2150
|
-
private
|
|
2151
|
-
private
|
|
2350
|
+
private handleNodeFailure;
|
|
2351
|
+
private connectToPeers;
|
|
2352
|
+
private startDiscovery;
|
|
2353
|
+
private scheduleReconnect;
|
|
2354
|
+
private connectToPeerWithBackoff;
|
|
2355
|
+
private connectToPeer;
|
|
2356
|
+
private _connectToPeerInternal;
|
|
2357
|
+
private handleSocket;
|
|
2358
|
+
send(nodeId: string, type: ClusterMessage['type'], payload: any): void;
|
|
2359
|
+
sendToNode(nodeId: string, message: any): void;
|
|
2360
|
+
getMembers(): string[];
|
|
2361
|
+
isLocal(nodeId: string): boolean;
|
|
2362
|
+
private buildClusterTLSOptions;
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2365
|
+
/**
|
|
2366
|
+
* MigrationManager - Manages gradual partition rebalancing
|
|
2367
|
+
*
|
|
2368
|
+
* Phase 4 Task 03: Parallel Partition Sync
|
|
2369
|
+
*
|
|
2370
|
+
* Features:
|
|
2371
|
+
* - Gradual rebalancing with configurable batch size
|
|
2372
|
+
* - State machine for migration lifecycle
|
|
2373
|
+
* - Backpressure via chunk acknowledgments
|
|
2374
|
+
* - Retry logic for failed migrations
|
|
2375
|
+
* - Metrics and observability
|
|
2376
|
+
*/
|
|
2377
|
+
|
|
2378
|
+
declare class MigrationManager extends EventEmitter {
|
|
2379
|
+
private readonly config;
|
|
2380
|
+
private readonly clusterManager;
|
|
2381
|
+
private readonly partitionService;
|
|
2382
|
+
private activeMigrations;
|
|
2383
|
+
private migrationQueue;
|
|
2384
|
+
private incomingMigrations;
|
|
2385
|
+
private pendingChunkAcks;
|
|
2386
|
+
private pendingVerifications;
|
|
2387
|
+
private metrics;
|
|
2388
|
+
private batchTimer;
|
|
2389
|
+
private dataCollector;
|
|
2390
|
+
private dataStorer;
|
|
2391
|
+
constructor(clusterManager: ClusterManager, partitionService: PartitionService, config?: Partial<MigrationConfig>);
|
|
2152
2392
|
/**
|
|
2153
|
-
*
|
|
2154
|
-
*
|
|
2393
|
+
* Set the data collector callback
|
|
2394
|
+
* Called to collect all records for a partition before migration
|
|
2155
2395
|
*/
|
|
2156
|
-
|
|
2396
|
+
setDataCollector(collector: (partitionId: number) => Promise<Uint8Array[]>): void;
|
|
2157
2397
|
/**
|
|
2158
|
-
*
|
|
2398
|
+
* Set the data storer callback
|
|
2399
|
+
* Called to store received records after successful migration
|
|
2159
2400
|
*/
|
|
2160
|
-
|
|
2401
|
+
setDataStorer(storer: (partitionId: number, data: Uint8Array[]) => Promise<void>): void;
|
|
2161
2402
|
/**
|
|
2162
|
-
*
|
|
2163
|
-
* Notifies WriteAckManager at each stage of processing.
|
|
2403
|
+
* Plan migration for topology change
|
|
2164
2404
|
*/
|
|
2165
|
-
|
|
2405
|
+
planMigration(oldDistribution: Map<number, PartitionDistribution>, newDistribution: Map<number, PartitionDistribution>): void;
|
|
2166
2406
|
/**
|
|
2167
|
-
*
|
|
2407
|
+
* Start batch processing timer
|
|
2168
2408
|
*/
|
|
2169
|
-
private
|
|
2409
|
+
private startBatchProcessing;
|
|
2170
2410
|
/**
|
|
2171
|
-
*
|
|
2411
|
+
* Stop batch processing
|
|
2172
2412
|
*/
|
|
2173
|
-
private
|
|
2413
|
+
private stopBatchProcessing;
|
|
2174
2414
|
/**
|
|
2175
|
-
*
|
|
2176
|
-
* Used for PERSISTED Write Concern.
|
|
2415
|
+
* Start next batch of migrations
|
|
2177
2416
|
*/
|
|
2178
|
-
|
|
2417
|
+
startNextBatch(): Promise<void>;
|
|
2179
2418
|
/**
|
|
2180
|
-
*
|
|
2181
|
-
* Used for non-PERSISTED Write Concern levels.
|
|
2419
|
+
* Start migration for a single partition
|
|
2182
2420
|
*/
|
|
2183
|
-
private
|
|
2184
|
-
}
|
|
2185
|
-
|
|
2186
|
-
interface PostgresAdapterOptions {
|
|
2187
|
-
tableName?: string;
|
|
2188
|
-
}
|
|
2189
|
-
declare class PostgresAdapter implements IServerStorage {
|
|
2190
|
-
private pool;
|
|
2191
|
-
private tableName;
|
|
2192
|
-
constructor(configOrPool: PoolConfig | Pool, options?: PostgresAdapterOptions);
|
|
2193
|
-
initialize(): Promise<void>;
|
|
2194
|
-
close(): Promise<void>;
|
|
2195
|
-
load(mapName: string, key: string): Promise<StorageValue<any> | undefined>;
|
|
2196
|
-
loadAll(mapName: string, keys: string[]): Promise<Map<string, StorageValue<any>>>;
|
|
2197
|
-
loadAllKeys(mapName: string): Promise<string[]>;
|
|
2198
|
-
store(mapName: string, key: string, record: StorageValue<any>): Promise<void>;
|
|
2199
|
-
storeAll(mapName: string, records: Map<string, StorageValue<any>>): Promise<void>;
|
|
2200
|
-
delete(mapName: string, key: string): Promise<void>;
|
|
2201
|
-
deleteAll(mapName: string, keys: string[]): Promise<void>;
|
|
2202
|
-
private mapRowToRecord;
|
|
2203
|
-
private isORMapValue;
|
|
2204
|
-
}
|
|
2205
|
-
|
|
2206
|
-
/**
|
|
2207
|
-
* In-memory implementation of IServerStorage.
|
|
2208
|
-
* Useful for development, testing, and demos without requiring a database.
|
|
2209
|
-
*
|
|
2210
|
-
* Note: Data is lost when the server restarts.
|
|
2211
|
-
*/
|
|
2212
|
-
declare class MemoryServerAdapter implements IServerStorage {
|
|
2213
|
-
private storage;
|
|
2214
|
-
initialize(): Promise<void>;
|
|
2215
|
-
close(): Promise<void>;
|
|
2216
|
-
private getMap;
|
|
2217
|
-
load(mapName: string, key: string): Promise<StorageValue<any> | undefined>;
|
|
2218
|
-
loadAll(mapName: string, keys: string[]): Promise<Map<string, StorageValue<any>>>;
|
|
2219
|
-
loadAllKeys(mapName: string): Promise<string[]>;
|
|
2220
|
-
store(mapName: string, key: string, record: StorageValue<any>): Promise<void>;
|
|
2221
|
-
storeAll(mapName: string, records: Map<string, StorageValue<any>>): Promise<void>;
|
|
2222
|
-
delete(mapName: string, key: string): Promise<void>;
|
|
2223
|
-
deleteAll(mapName: string, keys: string[]): Promise<void>;
|
|
2224
|
-
}
|
|
2225
|
-
|
|
2226
|
-
declare class SecurityManager {
|
|
2227
|
-
private policies;
|
|
2228
|
-
constructor(policies?: PermissionPolicy[]);
|
|
2229
|
-
addPolicy(policy: PermissionPolicy): void;
|
|
2230
|
-
checkPermission(principal: Principal, mapName: string, action: PermissionType): boolean;
|
|
2231
|
-
filterObject(object: any, principal: Principal, mapName: string): any;
|
|
2232
|
-
private hasRole;
|
|
2233
|
-
private matchesMap;
|
|
2234
|
-
}
|
|
2235
|
-
|
|
2236
|
-
declare const logger: pino.Logger<never, boolean>;
|
|
2237
|
-
type Logger = typeof logger;
|
|
2238
|
-
|
|
2239
|
-
/**
|
|
2240
|
-
* ConnectionRateLimiter - Rate limiter for incoming WebSocket connections.
|
|
2241
|
-
*
|
|
2242
|
-
* Implements connection rate limiting to prevent connection storms and
|
|
2243
|
-
* protect the server from being overwhelmed during high load scenarios.
|
|
2244
|
-
*
|
|
2245
|
-
* Features:
|
|
2246
|
-
* - Limits connections per second to prevent TCP backlog exhaustion
|
|
2247
|
-
* - Tracks pending connections (in-progress handshakes)
|
|
2248
|
-
* - Provides graceful rejection when limits are exceeded
|
|
2249
|
-
* - Auto-resets counters after cooldown period
|
|
2250
|
-
*/
|
|
2251
|
-
interface RateLimiterConfig {
|
|
2252
|
-
/** Maximum new connections allowed per second (default: 100) */
|
|
2253
|
-
maxConnectionsPerSecond: number;
|
|
2254
|
-
/** Maximum pending connections waiting for handshake (default: 1000) */
|
|
2255
|
-
maxPendingConnections: number;
|
|
2256
|
-
/** Cooldown period in ms after which counters reset (default: 1000) */
|
|
2257
|
-
cooldownMs: number;
|
|
2258
|
-
}
|
|
2259
|
-
interface RateLimiterStats {
|
|
2260
|
-
/** Current connections per second rate */
|
|
2261
|
-
connectionsPerSecond: number;
|
|
2262
|
-
/** Number of connections currently pending (handshake in progress) */
|
|
2263
|
-
pendingConnections: number;
|
|
2264
|
-
/** Total connections established since start */
|
|
2265
|
-
totalConnections: number;
|
|
2266
|
-
/** Total connections rejected due to rate limiting */
|
|
2267
|
-
totalRejected: number;
|
|
2268
|
-
}
|
|
2269
|
-
declare class ConnectionRateLimiter {
|
|
2270
|
-
private config;
|
|
2271
|
-
/** Connection attempts in current window */
|
|
2272
|
-
private connectionCount;
|
|
2273
|
-
/** Timestamp when current window started */
|
|
2274
|
-
private windowStart;
|
|
2275
|
-
/** Currently pending connections (handshake in progress) */
|
|
2276
|
-
private pendingCount;
|
|
2277
|
-
/** Total connections established since start */
|
|
2278
|
-
private totalConnections;
|
|
2279
|
-
/** Total connections rejected since start */
|
|
2280
|
-
private totalRejected;
|
|
2281
|
-
constructor(config?: Partial<RateLimiterConfig>);
|
|
2421
|
+
private startPartitionMigration;
|
|
2282
2422
|
/**
|
|
2283
|
-
*
|
|
2284
|
-
* @returns true if the connection should be accepted, false if it should be rejected
|
|
2423
|
+
* Split records into chunks
|
|
2285
2424
|
*/
|
|
2286
|
-
|
|
2425
|
+
private chunkify;
|
|
2287
2426
|
/**
|
|
2288
|
-
*
|
|
2289
|
-
* Call this when a new connection is initiated (before handshake completes).
|
|
2427
|
+
* Calculate checksum for a chunk using native xxhash
|
|
2290
2428
|
*/
|
|
2291
|
-
|
|
2429
|
+
private calculateChecksum;
|
|
2292
2430
|
/**
|
|
2293
|
-
*
|
|
2294
|
-
* Call this when the connection is fully established and authenticated.
|
|
2431
|
+
* Calculate checksum for all partition records using streaming xxhash
|
|
2295
2432
|
*/
|
|
2296
|
-
|
|
2433
|
+
private calculatePartitionChecksum;
|
|
2297
2434
|
/**
|
|
2298
|
-
*
|
|
2299
|
-
* Call this when a pending connection is closed before completing handshake.
|
|
2435
|
+
* Wait for chunk acknowledgment
|
|
2300
2436
|
*/
|
|
2301
|
-
|
|
2437
|
+
private waitForChunkAck;
|
|
2302
2438
|
/**
|
|
2303
|
-
*
|
|
2304
|
-
* Call this when shouldAccept() returns false and the connection is rejected.
|
|
2439
|
+
* Wait for migration verification
|
|
2305
2440
|
*/
|
|
2306
|
-
|
|
2441
|
+
private waitForVerification;
|
|
2307
2442
|
/**
|
|
2308
|
-
*
|
|
2309
|
-
* Call this when a pending connection fails to complete handshake.
|
|
2443
|
+
* Handle successful migration completion
|
|
2310
2444
|
*/
|
|
2311
|
-
|
|
2445
|
+
private onMigrationComplete;
|
|
2312
2446
|
/**
|
|
2313
|
-
*
|
|
2447
|
+
* Handle migration failure
|
|
2314
2448
|
*/
|
|
2315
|
-
|
|
2449
|
+
private onMigrationFailed;
|
|
2316
2450
|
/**
|
|
2317
|
-
*
|
|
2318
|
-
* Useful for testing or when recovering from errors.
|
|
2451
|
+
* Handle MIGRATION_START message
|
|
2319
2452
|
*/
|
|
2320
|
-
|
|
2453
|
+
private handleMigrationStart;
|
|
2321
2454
|
/**
|
|
2322
|
-
*
|
|
2455
|
+
* Handle MIGRATION_CHUNK message
|
|
2323
2456
|
*/
|
|
2324
|
-
|
|
2457
|
+
private handleMigrationChunk;
|
|
2325
2458
|
/**
|
|
2326
|
-
*
|
|
2459
|
+
* Handle MIGRATION_COMPLETE message
|
|
2327
2460
|
*/
|
|
2328
|
-
private
|
|
2329
|
-
}
|
|
2330
|
-
|
|
2331
|
-
declare class TimestampInterceptor implements IInterceptor {
|
|
2332
|
-
name: string;
|
|
2333
|
-
onBeforeOp(op: ServerOp, context: OpContext): Promise<ServerOp>;
|
|
2334
|
-
}
|
|
2335
|
-
|
|
2336
|
-
interface RateLimitConfig {
|
|
2337
|
-
windowMs: number;
|
|
2338
|
-
maxOps: number;
|
|
2339
|
-
}
|
|
2340
|
-
declare class RateLimitInterceptor implements IInterceptor {
|
|
2341
|
-
name: string;
|
|
2342
|
-
private limits;
|
|
2343
|
-
private config;
|
|
2344
|
-
constructor(config?: RateLimitConfig);
|
|
2345
|
-
onBeforeOp(op: ServerOp, context: OpContext): Promise<ServerOp | null>;
|
|
2346
|
-
onDisconnect(context: any): Promise<void>;
|
|
2347
|
-
}
|
|
2348
|
-
|
|
2349
|
-
/**
|
|
2350
|
-
* Native Module Statistics
|
|
2351
|
-
*
|
|
2352
|
-
* Provides information about available native optimizations.
|
|
2353
|
-
*
|
|
2354
|
-
* Phase 3.05: Integration
|
|
2355
|
-
*/
|
|
2356
|
-
|
|
2357
|
-
/**
|
|
2358
|
-
* Native module availability status
|
|
2359
|
-
*/
|
|
2360
|
-
interface NativeModuleStatus {
|
|
2361
|
-
/** Native xxHash64 is available and being used */
|
|
2362
|
-
nativeHash: boolean;
|
|
2363
|
-
/** SharedArrayBuffer is available */
|
|
2364
|
-
sharedArrayBuffer: boolean;
|
|
2365
|
-
}
|
|
2366
|
-
/**
|
|
2367
|
-
* Comprehensive native statistics
|
|
2368
|
-
*/
|
|
2369
|
-
interface NativeStats {
|
|
2370
|
-
/** Module availability status */
|
|
2371
|
-
modules: NativeModuleStatus;
|
|
2372
|
-
/** Shared memory statistics (if enabled) */
|
|
2373
|
-
sharedMemory: SharedMemoryStats | null;
|
|
2374
|
-
/** Summary of what's being used */
|
|
2375
|
-
summary: string;
|
|
2376
|
-
}
|
|
2377
|
-
/**
|
|
2378
|
-
* Check which native modules are available.
|
|
2379
|
-
*/
|
|
2380
|
-
declare function getNativeModuleStatus(): NativeModuleStatus;
|
|
2381
|
-
/**
|
|
2382
|
-
* Get native statistics including shared memory.
|
|
2383
|
-
*
|
|
2384
|
-
* @param sharedMemoryManager - Optional SharedMemoryManager instance
|
|
2385
|
-
*/
|
|
2386
|
-
declare function getNativeStats(sharedMemoryManager?: SharedMemoryManager): NativeStats;
|
|
2387
|
-
/**
|
|
2388
|
-
* Log native module status to console.
|
|
2389
|
-
*/
|
|
2390
|
-
declare function logNativeStatus(): void;
|
|
2391
|
-
|
|
2392
|
-
/**
|
|
2393
|
-
* FailureDetector - Phi Accrual Failure Detector
|
|
2394
|
-
*
|
|
2395
|
-
* Implements the Phi Accrual Failure Detection algorithm for distributed systems.
|
|
2396
|
-
* Based on the paper: "The φ Accrual Failure Detector" by Hayashibara et al.
|
|
2397
|
-
*
|
|
2398
|
-
* The detector provides a suspicion level (phi) rather than binary alive/dead status,
|
|
2399
|
-
* allowing the application to make decisions based on configurable thresholds.
|
|
2400
|
-
*
|
|
2401
|
-
* Hazelcast equivalent: com.hazelcast.internal.cluster.fd.PhiAccrualFailureDetector
|
|
2402
|
-
*/
|
|
2403
|
-
|
|
2404
|
-
interface FailureDetectorConfig {
|
|
2405
|
-
/** Interval between heartbeat checks (ms). Default: 1000 */
|
|
2406
|
-
heartbeatIntervalMs: number;
|
|
2407
|
-
/** Time after which a node is suspected if no heartbeat received (ms). Default: 5000 */
|
|
2408
|
-
suspicionTimeoutMs: number;
|
|
2409
|
-
/** Time after suspicion before confirming failure (ms). Default: 10000 */
|
|
2410
|
-
confirmationTimeoutMs: number;
|
|
2411
|
-
/** Phi threshold above which a node is considered suspected. Default: 8 */
|
|
2412
|
-
phiThreshold: number;
|
|
2413
|
-
/** Minimum samples required for accurate phi calculation. Default: 10 */
|
|
2414
|
-
minSamples: number;
|
|
2415
|
-
/** Maximum samples to keep in history. Default: 100 */
|
|
2416
|
-
maxSamples: number;
|
|
2417
|
-
/** Initial heartbeat interval estimate (ms). Default: 1000 */
|
|
2418
|
-
initialHeartbeatIntervalMs: number;
|
|
2419
|
-
}
|
|
2420
|
-
declare const DEFAULT_FAILURE_DETECTOR_CONFIG: FailureDetectorConfig;
|
|
2421
|
-
interface NodeState {
|
|
2422
|
-
/** Last heartbeat timestamp */
|
|
2423
|
-
lastHeartbeat: number;
|
|
2424
|
-
/** Heartbeat interval history for phi calculation */
|
|
2425
|
-
intervalHistory: number[];
|
|
2426
|
-
/** Whether node is currently suspected */
|
|
2427
|
-
isSuspected: boolean;
|
|
2428
|
-
/** Timestamp when suspicion started */
|
|
2429
|
-
suspicionStartTime?: number;
|
|
2430
|
-
/** Whether failure has been confirmed */
|
|
2431
|
-
isConfirmedFailed: boolean;
|
|
2432
|
-
}
|
|
2433
|
-
interface FailureDetectorEvents {
|
|
2434
|
-
nodeSuspected: {
|
|
2435
|
-
nodeId: string;
|
|
2436
|
-
phi: number;
|
|
2437
|
-
};
|
|
2438
|
-
nodeRecovered: {
|
|
2439
|
-
nodeId: string;
|
|
2440
|
-
};
|
|
2441
|
-
nodeConfirmedFailed: {
|
|
2442
|
-
nodeId: string;
|
|
2443
|
-
};
|
|
2444
|
-
}
|
|
2445
|
-
declare class FailureDetector extends EventEmitter {
|
|
2446
|
-
private config;
|
|
2447
|
-
private nodeStates;
|
|
2448
|
-
private monitoringNodes;
|
|
2449
|
-
private checkTimer?;
|
|
2450
|
-
private confirmationTimers;
|
|
2451
|
-
private started;
|
|
2452
|
-
constructor(config?: Partial<FailureDetectorConfig>);
|
|
2461
|
+
private handleMigrationComplete;
|
|
2453
2462
|
/**
|
|
2454
|
-
*
|
|
2463
|
+
* Handle MIGRATION_CHUNK_ACK message
|
|
2455
2464
|
*/
|
|
2456
|
-
|
|
2465
|
+
private handleMigrationChunkAck;
|
|
2457
2466
|
/**
|
|
2458
|
-
*
|
|
2467
|
+
* Handle MIGRATION_VERIFY message
|
|
2459
2468
|
*/
|
|
2460
|
-
|
|
2469
|
+
private handleMigrationVerify;
|
|
2461
2470
|
/**
|
|
2462
|
-
*
|
|
2471
|
+
* Reassemble chunks into continuous data
|
|
2463
2472
|
*/
|
|
2464
|
-
|
|
2473
|
+
private reassemble;
|
|
2465
2474
|
/**
|
|
2466
|
-
*
|
|
2475
|
+
* Deserialize records from chunk data
|
|
2467
2476
|
*/
|
|
2468
|
-
|
|
2477
|
+
private deserializeRecords;
|
|
2469
2478
|
/**
|
|
2470
|
-
*
|
|
2471
|
-
* This updates the node's state and clears any suspicion.
|
|
2479
|
+
* Setup cluster message handlers
|
|
2472
2480
|
*/
|
|
2473
|
-
|
|
2481
|
+
private setupMessageHandlers;
|
|
2474
2482
|
/**
|
|
2475
|
-
* Check
|
|
2483
|
+
* Check if a partition is currently migrating
|
|
2476
2484
|
*/
|
|
2477
|
-
|
|
2485
|
+
isActive(partitionId: number): boolean;
|
|
2486
|
+
/**
|
|
2487
|
+
* Get migration status
|
|
2488
|
+
*/
|
|
2489
|
+
getStatus(): MigrationStatus;
|
|
2490
|
+
/**
|
|
2491
|
+
* Get migration metrics
|
|
2492
|
+
*/
|
|
2493
|
+
getMetrics(): MigrationMetrics;
|
|
2494
|
+
/**
|
|
2495
|
+
* Cancel all active and queued migrations
|
|
2496
|
+
*/
|
|
2497
|
+
cancelAll(): Promise<void>;
|
|
2498
|
+
/**
|
|
2499
|
+
* Cleanup resources (sync version for backwards compatibility)
|
|
2500
|
+
*/
|
|
2501
|
+
close(): void;
|
|
2502
|
+
/**
|
|
2503
|
+
* Async cleanup - waits for cancellation to complete
|
|
2504
|
+
*/
|
|
2505
|
+
closeAsync(): Promise<void>;
|
|
2506
|
+
}
|
|
2507
|
+
|
|
2508
|
+
interface PartitionDistribution {
|
|
2509
|
+
owner: string;
|
|
2510
|
+
backups: string[];
|
|
2511
|
+
}
|
|
2512
|
+
interface PartitionServiceEvents {
|
|
2513
|
+
'rebalanced': (map: PartitionMap, changes: PartitionChange[]) => void;
|
|
2514
|
+
'partitionMoved': (info: {
|
|
2515
|
+
partitionId: number;
|
|
2516
|
+
previousOwner: string;
|
|
2517
|
+
newOwner: string;
|
|
2518
|
+
version: number;
|
|
2519
|
+
}) => void;
|
|
2520
|
+
}
|
|
2521
|
+
interface PartitionServiceConfig {
|
|
2522
|
+
/** Enable gradual rebalancing (default: false for backward compatibility) */
|
|
2523
|
+
gradualRebalancing: boolean;
|
|
2524
|
+
/** Migration configuration */
|
|
2525
|
+
migration: Partial<MigrationConfig>;
|
|
2526
|
+
}
|
|
2527
|
+
declare class PartitionService extends EventEmitter {
|
|
2528
|
+
private cluster;
|
|
2529
|
+
private partitions;
|
|
2530
|
+
private readonly PARTITION_COUNT;
|
|
2531
|
+
private readonly BACKUP_COUNT;
|
|
2532
|
+
private mapVersion;
|
|
2533
|
+
private lastRebalanceTime;
|
|
2534
|
+
private config;
|
|
2535
|
+
private migrationManager;
|
|
2536
|
+
constructor(cluster: ClusterManager, config?: Partial<PartitionServiceConfig>);
|
|
2537
|
+
/**
|
|
2538
|
+
* Handle membership change
|
|
2539
|
+
*/
|
|
2540
|
+
private onMembershipChange;
|
|
2541
|
+
getPartitionId(key: string): number;
|
|
2542
|
+
getDistribution(key: string): PartitionDistribution;
|
|
2543
|
+
getOwner(key: string): string;
|
|
2544
|
+
isLocalOwner(key: string): boolean;
|
|
2545
|
+
isLocalBackup(key: string): boolean;
|
|
2546
|
+
isRelated(key: string): boolean;
|
|
2478
2547
|
/**
|
|
2479
|
-
*
|
|
2548
|
+
* Get current partition map version
|
|
2480
2549
|
*/
|
|
2481
|
-
|
|
2550
|
+
getMapVersion(): number;
|
|
2482
2551
|
/**
|
|
2483
|
-
*
|
|
2552
|
+
* Generate full PartitionMap for client consumption
|
|
2484
2553
|
*/
|
|
2485
|
-
|
|
2554
|
+
getPartitionMap(): PartitionMap;
|
|
2486
2555
|
/**
|
|
2487
|
-
*
|
|
2488
|
-
*
|
|
2489
|
-
* Phi = -log10(P_later(t_now - t_last))
|
|
2490
|
-
*
|
|
2491
|
-
* where P_later is the probability that a heartbeat will arrive later than expected.
|
|
2556
|
+
* Get partition info by ID
|
|
2492
2557
|
*/
|
|
2493
|
-
|
|
2558
|
+
getPartitionInfo(partitionId: number): PartitionInfo | null;
|
|
2494
2559
|
/**
|
|
2495
|
-
*
|
|
2560
|
+
* Get owner node for a partition ID
|
|
2496
2561
|
*/
|
|
2497
|
-
|
|
2562
|
+
getPartitionOwner(partitionId: number): string | null;
|
|
2563
|
+
private rebalance;
|
|
2498
2564
|
/**
|
|
2499
|
-
*
|
|
2565
|
+
* Perform gradual rebalancing using MigrationManager
|
|
2500
2566
|
*/
|
|
2501
|
-
private
|
|
2567
|
+
private rebalanceGradual;
|
|
2502
2568
|
/**
|
|
2503
|
-
*
|
|
2569
|
+
* Set partition owner (called after migration completes)
|
|
2504
2570
|
*/
|
|
2505
|
-
|
|
2571
|
+
setOwner(partitionId: number, nodeId: string): void;
|
|
2506
2572
|
/**
|
|
2507
|
-
* Get
|
|
2573
|
+
* Get backups for a partition
|
|
2508
2574
|
*/
|
|
2509
|
-
|
|
2575
|
+
getBackups(partitionId: number): string[];
|
|
2510
2576
|
/**
|
|
2511
|
-
*
|
|
2577
|
+
* Get migration status
|
|
2512
2578
|
*/
|
|
2513
|
-
|
|
2579
|
+
getMigrationStatus(): MigrationStatus | null;
|
|
2514
2580
|
/**
|
|
2515
|
-
* Check if
|
|
2581
|
+
* Check if partition is currently migrating
|
|
2516
2582
|
*/
|
|
2517
|
-
|
|
2583
|
+
isMigrating(partitionId: number): boolean;
|
|
2518
2584
|
/**
|
|
2519
|
-
*
|
|
2585
|
+
* Check if any partition is currently migrating
|
|
2520
2586
|
*/
|
|
2521
|
-
|
|
2587
|
+
isRebalancing(): boolean;
|
|
2522
2588
|
/**
|
|
2523
|
-
* Get
|
|
2589
|
+
* Get MigrationManager for configuration
|
|
2524
2590
|
*/
|
|
2525
|
-
|
|
2591
|
+
getMigrationManager(): MigrationManager | null;
|
|
2526
2592
|
/**
|
|
2527
|
-
*
|
|
2593
|
+
* Cancel all migrations
|
|
2528
2594
|
*/
|
|
2529
|
-
|
|
2530
|
-
monitoredNodes: number;
|
|
2531
|
-
suspectedNodes: number;
|
|
2532
|
-
confirmedFailedNodes: number;
|
|
2533
|
-
};
|
|
2595
|
+
cancelMigrations(): Promise<void>;
|
|
2534
2596
|
}
|
|
2535
2597
|
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2598
|
+
/**
|
|
2599
|
+
* ClusterSearchCoordinator - Distributed Search across Cluster Nodes
|
|
2600
|
+
*
|
|
2601
|
+
* Implements Scatter-Gather architecture for distributed full-text search.
|
|
2602
|
+
* Broadcasts search queries to all nodes, collects local results, and merges
|
|
2603
|
+
* them using Reciprocal Rank Fusion (RRF) for unified ranking.
|
|
2604
|
+
*
|
|
2605
|
+
* Key features:
|
|
2606
|
+
* - Scatter-Gather search across all cluster nodes
|
|
2607
|
+
* - RRF-based result merging (handles distributed IDF problem)
|
|
2608
|
+
* - Cursor-based pagination for efficient deep results
|
|
2609
|
+
* - Graceful degradation on node failures
|
|
2610
|
+
* - Single-node optimization (skip broadcast when all data is local)
|
|
2611
|
+
*
|
|
2612
|
+
* @module search/ClusterSearchCoordinator
|
|
2613
|
+
*/
|
|
2614
|
+
|
|
2615
|
+
/**
|
|
2616
|
+
* Configuration for ClusterSearchCoordinator.
|
|
2617
|
+
*/
|
|
2618
|
+
interface ClusterSearchConfig {
|
|
2619
|
+
/** RRF constant k (default: 60) */
|
|
2620
|
+
rrfK?: number;
|
|
2621
|
+
/** Default timeout for node responses (ms) */
|
|
2622
|
+
defaultTimeoutMs?: number;
|
|
2623
|
+
/** Minimum nodes required to respond (default: 0 = all available) */
|
|
2624
|
+
defaultMinResponses?: number;
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
interface ServerCoordinatorConfig {
|
|
2539
2628
|
port: number;
|
|
2540
|
-
|
|
2629
|
+
nodeId: string;
|
|
2630
|
+
storage?: IServerStorage;
|
|
2631
|
+
jwtSecret?: string;
|
|
2632
|
+
host?: string;
|
|
2633
|
+
clusterPort?: number;
|
|
2634
|
+
peers?: string[];
|
|
2635
|
+
securityPolicies?: PermissionPolicy[];
|
|
2636
|
+
/** Callback to resolve dynamic peer addresses after ports are known */
|
|
2637
|
+
resolvePeers?: () => string[];
|
|
2638
|
+
interceptors?: IInterceptor[];
|
|
2639
|
+
metricsPort?: number;
|
|
2541
2640
|
discovery?: 'manual' | 'kubernetes';
|
|
2542
2641
|
serviceName?: string;
|
|
2543
2642
|
discoveryInterval?: number;
|
|
2544
|
-
tls?:
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2643
|
+
tls?: TLSConfig;
|
|
2644
|
+
clusterTls?: ClusterTLSConfig;
|
|
2645
|
+
/** Total event queue capacity for bounded queue (default: 10000) */
|
|
2646
|
+
eventQueueCapacity?: number;
|
|
2647
|
+
/** Number of event queue stripes for parallel processing (default: 4) */
|
|
2648
|
+
eventStripeCount?: number;
|
|
2649
|
+
/** Enable/disable backpressure (default: true) */
|
|
2650
|
+
backpressureEnabled?: boolean;
|
|
2651
|
+
/** How often to force sync processing (default: 100 operations) */
|
|
2652
|
+
backpressureSyncFrequency?: number;
|
|
2653
|
+
/** Maximum pending async operations before blocking (default: 1000) */
|
|
2654
|
+
backpressureMaxPending?: number;
|
|
2655
|
+
/** Backoff timeout in ms when at capacity (default: 5000) */
|
|
2656
|
+
backpressureBackoffMs?: number;
|
|
2657
|
+
/** Enable/disable write coalescing (default: true) */
|
|
2658
|
+
writeCoalescingEnabled?: boolean;
|
|
2659
|
+
/** Coalescing preset: 'conservative', 'balanced', 'highThroughput', 'aggressive' (default: 'highThroughput') */
|
|
2660
|
+
writeCoalescingPreset?: CoalescingPreset;
|
|
2661
|
+
/** Maximum messages to batch before forcing flush (default: 500 for highThroughput) */
|
|
2662
|
+
writeCoalescingMaxBatch?: number;
|
|
2663
|
+
/** Maximum delay before flushing in ms (default: 10 for highThroughput) */
|
|
2664
|
+
writeCoalescingMaxDelayMs?: number;
|
|
2665
|
+
/** Maximum batch size in bytes (default: 262144/256KB for highThroughput) */
|
|
2666
|
+
writeCoalescingMaxBytes?: number;
|
|
2667
|
+
/** WebSocket backlog for pending connections (default: 511) */
|
|
2668
|
+
wsBacklog?: number;
|
|
2669
|
+
/** Enable WebSocket per-message compression (default: false for CPU savings) */
|
|
2670
|
+
wsCompression?: boolean;
|
|
2671
|
+
/** Maximum WebSocket payload size in bytes (default: 64MB) */
|
|
2672
|
+
wsMaxPayload?: number;
|
|
2673
|
+
/** Maximum server connections (default: 10000) */
|
|
2674
|
+
maxConnections?: number;
|
|
2675
|
+
/** Server timeout in ms (default: 120000 = 2 min) */
|
|
2676
|
+
serverTimeout?: number;
|
|
2677
|
+
/** Keep-alive timeout in ms (default: 5000) */
|
|
2678
|
+
keepAliveTimeout?: number;
|
|
2679
|
+
/** Headers timeout in ms (default: 60000) */
|
|
2680
|
+
headersTimeout?: number;
|
|
2681
|
+
/** Enable connection rate limiting (default: true) */
|
|
2682
|
+
rateLimitingEnabled?: boolean;
|
|
2683
|
+
/** Maximum new connections per second (default: 100) */
|
|
2684
|
+
maxConnectionsPerSecond?: number;
|
|
2685
|
+
/** Maximum pending connections (default: 1000) */
|
|
2686
|
+
maxPendingConnections?: number;
|
|
2687
|
+
/** Enable worker pool for CPU-bound operations (default: false) */
|
|
2688
|
+
workerPoolEnabled?: boolean;
|
|
2689
|
+
/** Worker pool configuration */
|
|
2690
|
+
workerPoolConfig?: Partial<WorkerPoolConfig>;
|
|
2691
|
+
/** Default timeout for Write Concern acknowledgments in ms (default: 5000) */
|
|
2692
|
+
writeAckTimeout?: number;
|
|
2693
|
+
/** Enable replication to backup nodes (default: true when cluster has peers) */
|
|
2694
|
+
replicationEnabled?: boolean;
|
|
2695
|
+
/** Default consistency level for replication (default: EVENTUAL) */
|
|
2696
|
+
defaultConsistency?: ConsistencyLevel;
|
|
2697
|
+
/** Replication configuration */
|
|
2698
|
+
replicationConfig?: Partial<ReplicationConfig>;
|
|
2699
|
+
/** Enable event journal for audit/CDC (default: false) */
|
|
2700
|
+
eventJournalEnabled?: boolean;
|
|
2701
|
+
/** Event journal configuration */
|
|
2702
|
+
eventJournalConfig?: Partial<Omit<EventJournalServiceConfig, 'pool'>>;
|
|
2703
|
+
/** Enable full-text search for specific maps */
|
|
2704
|
+
fullTextSearch?: Record<string, FullTextIndexConfig>;
|
|
2705
|
+
/** Configuration for distributed search across cluster nodes */
|
|
2706
|
+
distributedSearch?: ClusterSearchConfig;
|
|
2561
2707
|
}
|
|
2562
|
-
declare class
|
|
2563
|
-
|
|
2564
|
-
private
|
|
2565
|
-
private
|
|
2566
|
-
private
|
|
2567
|
-
private
|
|
2568
|
-
private
|
|
2569
|
-
private
|
|
2570
|
-
private
|
|
2571
|
-
|
|
2708
|
+
declare class ServerCoordinator {
|
|
2709
|
+
private httpServer;
|
|
2710
|
+
private metricsServer?;
|
|
2711
|
+
private metricsService;
|
|
2712
|
+
private wss;
|
|
2713
|
+
private clients;
|
|
2714
|
+
private interceptors;
|
|
2715
|
+
private maps;
|
|
2716
|
+
private hlc;
|
|
2717
|
+
private storage?;
|
|
2718
|
+
private jwtSecret;
|
|
2719
|
+
private queryRegistry;
|
|
2720
|
+
private cluster;
|
|
2721
|
+
private partitionService;
|
|
2722
|
+
private replicationPipeline?;
|
|
2723
|
+
private lockManager;
|
|
2724
|
+
private topicManager;
|
|
2725
|
+
private securityManager;
|
|
2726
|
+
private systemManager;
|
|
2727
|
+
private pendingClusterQueries;
|
|
2728
|
+
private gcInterval?;
|
|
2729
|
+
private heartbeatCheckInterval?;
|
|
2730
|
+
private gcReports;
|
|
2731
|
+
private mapLoadingPromises;
|
|
2732
|
+
private pendingBatchOperations;
|
|
2733
|
+
private eventExecutor;
|
|
2734
|
+
private backpressure;
|
|
2735
|
+
private writeCoalescingEnabled;
|
|
2736
|
+
private writeCoalescingOptions;
|
|
2737
|
+
private rateLimiter;
|
|
2738
|
+
private rateLimitingEnabled;
|
|
2739
|
+
private workerPool?;
|
|
2740
|
+
private merkleWorker?;
|
|
2741
|
+
private crdtMergeWorker?;
|
|
2742
|
+
private serializationWorker?;
|
|
2743
|
+
private eventPayloadPool;
|
|
2744
|
+
private taskletScheduler;
|
|
2745
|
+
private writeAckManager;
|
|
2746
|
+
private counterHandler;
|
|
2747
|
+
private entryProcessorHandler;
|
|
2748
|
+
private conflictResolverHandler;
|
|
2749
|
+
private eventJournalService?;
|
|
2750
|
+
private journalSubscriptions;
|
|
2751
|
+
private partitionReassigner?;
|
|
2752
|
+
private readReplicaHandler?;
|
|
2753
|
+
private merkleTreeManager?;
|
|
2754
|
+
private repairScheduler?;
|
|
2755
|
+
private searchCoordinator;
|
|
2756
|
+
private clusterSearchCoordinator?;
|
|
2757
|
+
private distributedSubCoordinator?;
|
|
2758
|
+
private readonly _nodeId;
|
|
2759
|
+
private _actualPort;
|
|
2760
|
+
private _actualClusterPort;
|
|
2761
|
+
private _readyPromise;
|
|
2762
|
+
private _readyResolve;
|
|
2763
|
+
constructor(config: ServerCoordinatorConfig);
|
|
2764
|
+
/**
|
|
2765
|
+
* Populate FTS indexes from existing map data.
|
|
2766
|
+
* Called after storage initialization.
|
|
2767
|
+
*/
|
|
2768
|
+
private backfillSearchIndexes;
|
|
2769
|
+
/** Wait for server to be fully ready (ports assigned) */
|
|
2770
|
+
ready(): Promise<void>;
|
|
2771
|
+
/**
|
|
2772
|
+
* Wait for all pending batch operations to complete.
|
|
2773
|
+
* Useful for tests that need to verify state after OP_BATCH.
|
|
2774
|
+
*/
|
|
2775
|
+
waitForPendingBatches(): Promise<void>;
|
|
2776
|
+
/** Get the actual port the server is listening on */
|
|
2777
|
+
get port(): number;
|
|
2778
|
+
/** Get the actual cluster port */
|
|
2779
|
+
get clusterPort(): number;
|
|
2780
|
+
/** Get event executor metrics for monitoring */
|
|
2781
|
+
getEventExecutorMetrics(): StripeMetrics[];
|
|
2782
|
+
/** Get total event executor metrics across all stripes */
|
|
2783
|
+
getEventExecutorTotalMetrics(): QueueMetrics;
|
|
2784
|
+
/** Get connection rate limiter stats for monitoring */
|
|
2785
|
+
getRateLimiterStats(): RateLimiterStats;
|
|
2786
|
+
/** Get worker pool stats for monitoring */
|
|
2787
|
+
getWorkerPoolStats(): WorkerPoolStats | null;
|
|
2788
|
+
/** Check if worker pool is enabled */
|
|
2789
|
+
get workerPoolEnabled(): boolean;
|
|
2790
|
+
/** Get MerkleWorker for external use (null if worker pool disabled) */
|
|
2791
|
+
getMerkleWorker(): MerkleWorker | null;
|
|
2792
|
+
/** Get CRDTMergeWorker for external use (null if worker pool disabled) */
|
|
2793
|
+
getCRDTMergeWorker(): CRDTMergeWorker | null;
|
|
2794
|
+
/** Get SerializationWorker for external use (null if worker pool disabled) */
|
|
2795
|
+
getSerializationWorker(): SerializationWorker | null;
|
|
2796
|
+
/** Get memory pool stats for monitoring GC pressure reduction */
|
|
2797
|
+
getMemoryPoolStats(): {
|
|
2798
|
+
eventPayloadPool: ObjectPoolStats;
|
|
2799
|
+
};
|
|
2800
|
+
/** Get tasklet scheduler stats for monitoring cooperative multitasking */
|
|
2801
|
+
getTaskletSchedulerStats(): TaskletSchedulerStats;
|
|
2802
|
+
/** Get tasklet scheduler for scheduling long-running operations */
|
|
2803
|
+
getTaskletScheduler(): TaskletScheduler;
|
|
2572
2804
|
/**
|
|
2573
|
-
*
|
|
2805
|
+
* Enable full-text search for a map.
|
|
2806
|
+
* Can be called at runtime to enable FTS dynamically.
|
|
2807
|
+
*
|
|
2808
|
+
* @param mapName - Name of the map to enable FTS for
|
|
2809
|
+
* @param config - FTS configuration (fields, tokenizer, bm25 options)
|
|
2574
2810
|
*/
|
|
2575
|
-
|
|
2576
|
-
private _actualPort;
|
|
2577
|
-
/** Get the actual port the cluster is listening on */
|
|
2578
|
-
get port(): number;
|
|
2579
|
-
start(): Promise<number>;
|
|
2580
|
-
/** Called when server is ready - registers self and initiates peer connections */
|
|
2581
|
-
private onServerReady;
|
|
2582
|
-
stop(): void;
|
|
2811
|
+
enableFullTextSearch(mapName: string, config: FullTextIndexConfig): void;
|
|
2583
2812
|
/**
|
|
2584
|
-
*
|
|
2813
|
+
* Disable full-text search for a map.
|
|
2814
|
+
*
|
|
2815
|
+
* @param mapName - Name of the map to disable FTS for
|
|
2585
2816
|
*/
|
|
2586
|
-
|
|
2817
|
+
disableFullTextSearch(mapName: string): void;
|
|
2587
2818
|
/**
|
|
2588
|
-
*
|
|
2819
|
+
* Check if full-text search is enabled for a map.
|
|
2820
|
+
*
|
|
2821
|
+
* @param mapName - Name of the map to check
|
|
2822
|
+
* @returns True if FTS is enabled
|
|
2589
2823
|
*/
|
|
2590
|
-
|
|
2824
|
+
isFullTextSearchEnabled(mapName: string): boolean;
|
|
2591
2825
|
/**
|
|
2592
|
-
*
|
|
2826
|
+
* Get FTS index statistics for a map.
|
|
2827
|
+
*
|
|
2828
|
+
* @param mapName - Name of the map
|
|
2829
|
+
* @returns Index stats or null if FTS not enabled
|
|
2593
2830
|
*/
|
|
2594
|
-
|
|
2831
|
+
getFullTextSearchStats(mapName: string): {
|
|
2832
|
+
documentCount: number;
|
|
2833
|
+
fields: string[];
|
|
2834
|
+
} | null;
|
|
2595
2835
|
/**
|
|
2596
|
-
*
|
|
2836
|
+
* Phase 10.02: Graceful cluster departure
|
|
2837
|
+
*
|
|
2838
|
+
* Notifies the cluster that this node is leaving and allows time for:
|
|
2839
|
+
* 1. Pending replication to complete
|
|
2840
|
+
* 2. Other nodes to detect departure
|
|
2841
|
+
* 3. Partition reassignment to begin
|
|
2597
2842
|
*/
|
|
2598
|
-
private
|
|
2843
|
+
private gracefulClusterDeparture;
|
|
2599
2844
|
/**
|
|
2600
|
-
*
|
|
2601
|
-
* Called when a new node joins to propagate cluster topology.
|
|
2845
|
+
* Get list of partition IDs owned by this node
|
|
2602
2846
|
*/
|
|
2603
|
-
private
|
|
2847
|
+
private getOwnedPartitions;
|
|
2604
2848
|
/**
|
|
2605
|
-
*
|
|
2606
|
-
* Called when cluster membership changes.
|
|
2849
|
+
* Wait for replication pipeline to flush pending operations
|
|
2607
2850
|
*/
|
|
2608
|
-
private
|
|
2851
|
+
private waitForReplicationFlush;
|
|
2852
|
+
shutdown(): Promise<void>;
|
|
2853
|
+
private handleConnection;
|
|
2854
|
+
private handleMessage;
|
|
2855
|
+
private updateClientHlc;
|
|
2609
2856
|
/**
|
|
2610
|
-
*
|
|
2611
|
-
*
|
|
2857
|
+
* Broadcast partition map to all connected and authenticated clients.
|
|
2858
|
+
* Called when partition topology changes (node join/leave/failover).
|
|
2612
2859
|
*/
|
|
2613
|
-
private
|
|
2860
|
+
private broadcastPartitionMap;
|
|
2614
2861
|
/**
|
|
2615
|
-
*
|
|
2862
|
+
* Notify a client about a merge rejection (Phase 5.05).
|
|
2863
|
+
* Finds the client by node ID and sends MERGE_REJECTED message.
|
|
2616
2864
|
*/
|
|
2617
|
-
private
|
|
2618
|
-
private
|
|
2619
|
-
private startDiscovery;
|
|
2620
|
-
private scheduleReconnect;
|
|
2621
|
-
private connectToPeerWithBackoff;
|
|
2622
|
-
private connectToPeer;
|
|
2623
|
-
private _connectToPeerInternal;
|
|
2624
|
-
private handleSocket;
|
|
2625
|
-
send(nodeId: string, type: ClusterMessage['type'], payload: any): void;
|
|
2626
|
-
sendToNode(nodeId: string, message: any): void;
|
|
2627
|
-
getMembers(): string[];
|
|
2628
|
-
isLocal(nodeId: string): boolean;
|
|
2629
|
-
private buildClusterTLSOptions;
|
|
2630
|
-
}
|
|
2631
|
-
|
|
2632
|
-
/**
|
|
2633
|
-
* MigrationManager - Manages gradual partition rebalancing
|
|
2634
|
-
*
|
|
2635
|
-
* Phase 4 Task 03: Parallel Partition Sync
|
|
2636
|
-
*
|
|
2637
|
-
* Features:
|
|
2638
|
-
* - Gradual rebalancing with configurable batch size
|
|
2639
|
-
* - State machine for migration lifecycle
|
|
2640
|
-
* - Backpressure via chunk acknowledgments
|
|
2641
|
-
* - Retry logic for failed migrations
|
|
2642
|
-
* - Metrics and observability
|
|
2643
|
-
*/
|
|
2644
|
-
|
|
2645
|
-
declare class MigrationManager extends EventEmitter {
|
|
2646
|
-
private readonly config;
|
|
2647
|
-
private readonly clusterManager;
|
|
2648
|
-
private readonly partitionService;
|
|
2649
|
-
private activeMigrations;
|
|
2650
|
-
private migrationQueue;
|
|
2651
|
-
private incomingMigrations;
|
|
2652
|
-
private pendingChunkAcks;
|
|
2653
|
-
private pendingVerifications;
|
|
2654
|
-
private metrics;
|
|
2655
|
-
private batchTimer;
|
|
2656
|
-
private dataCollector;
|
|
2657
|
-
private dataStorer;
|
|
2658
|
-
constructor(clusterManager: ClusterManager, partitionService: PartitionService, config?: Partial<MigrationConfig>);
|
|
2865
|
+
private notifyMergeRejection;
|
|
2866
|
+
private broadcast;
|
|
2659
2867
|
/**
|
|
2660
|
-
*
|
|
2661
|
-
*
|
|
2868
|
+
* === OPTIMIZATION 2 & 3: Batched Broadcast with Serialization Caching ===
|
|
2869
|
+
* Groups clients by their permission roles and serializes once per group.
|
|
2870
|
+
* Also batches multiple events into a single SERVER_BATCH_EVENT message.
|
|
2871
|
+
* === OPTIMIZATION 4: Subscription-based Routing ===
|
|
2872
|
+
* Only sends events to clients with active subscriptions for affected maps.
|
|
2662
2873
|
*/
|
|
2663
|
-
|
|
2874
|
+
private broadcastBatch;
|
|
2664
2875
|
/**
|
|
2665
|
-
*
|
|
2666
|
-
* Called to store received records after successful migration
|
|
2876
|
+
* Helper method to get role signature for a client (for caching key)
|
|
2667
2877
|
*/
|
|
2668
|
-
|
|
2878
|
+
private getClientRoleSignature;
|
|
2669
2879
|
/**
|
|
2670
|
-
*
|
|
2880
|
+
* === BACKPRESSURE: Synchronous Broadcast ===
|
|
2881
|
+
* Same as broadcastBatch but waits for all sends to complete.
|
|
2882
|
+
* Used when backpressure forces sync processing to drain the pipeline.
|
|
2671
2883
|
*/
|
|
2672
|
-
|
|
2884
|
+
private broadcastBatchSync;
|
|
2885
|
+
private setupClusterListeners;
|
|
2886
|
+
private executeLocalQuery;
|
|
2673
2887
|
/**
|
|
2674
|
-
*
|
|
2888
|
+
* Convert server Query format to core Query format for indexed execution.
|
|
2889
|
+
* Returns null if conversion is not possible (complex queries).
|
|
2675
2890
|
*/
|
|
2676
|
-
private
|
|
2891
|
+
private convertToCoreQuery;
|
|
2677
2892
|
/**
|
|
2678
|
-
*
|
|
2893
|
+
* Convert predicate node to core Query format.
|
|
2679
2894
|
*/
|
|
2680
|
-
private
|
|
2895
|
+
private predicateToCoreQuery;
|
|
2681
2896
|
/**
|
|
2682
|
-
*
|
|
2897
|
+
* Convert server operator to core query type.
|
|
2683
2898
|
*/
|
|
2684
|
-
|
|
2899
|
+
private convertOperator;
|
|
2900
|
+
private finalizeClusterQuery;
|
|
2685
2901
|
/**
|
|
2686
|
-
*
|
|
2902
|
+
* Core operation application logic shared between processLocalOp and processLocalOpForBatch.
|
|
2903
|
+
* Handles map merge, storage persistence, query evaluation, and event generation.
|
|
2904
|
+
*
|
|
2905
|
+
* @returns Event payload for broadcasting (or null if operation failed)
|
|
2687
2906
|
*/
|
|
2688
|
-
private
|
|
2907
|
+
private applyOpToMap;
|
|
2689
2908
|
/**
|
|
2690
|
-
*
|
|
2909
|
+
* Apply replicated operation from another node (callback for ReplicationPipeline)
|
|
2910
|
+
* This is called when we receive a replicated operation as a backup node
|
|
2691
2911
|
*/
|
|
2692
|
-
private
|
|
2912
|
+
private applyReplicatedOperation;
|
|
2693
2913
|
/**
|
|
2694
|
-
*
|
|
2914
|
+
* Build OpContext for interceptors.
|
|
2695
2915
|
*/
|
|
2696
|
-
private
|
|
2916
|
+
private buildOpContext;
|
|
2697
2917
|
/**
|
|
2698
|
-
*
|
|
2918
|
+
* Run onBeforeOp interceptors. Returns modified op or null if dropped.
|
|
2699
2919
|
*/
|
|
2700
|
-
private
|
|
2920
|
+
private runBeforeInterceptors;
|
|
2701
2921
|
/**
|
|
2702
|
-
*
|
|
2922
|
+
* Run onAfterOp interceptors (fire-and-forget).
|
|
2703
2923
|
*/
|
|
2704
|
-
private
|
|
2924
|
+
private runAfterInterceptors;
|
|
2925
|
+
private handleLockGranted;
|
|
2926
|
+
private processLocalOp;
|
|
2705
2927
|
/**
|
|
2706
|
-
*
|
|
2928
|
+
* === OPTIMIZATION 1: Async Batch Processing with Backpressure ===
|
|
2929
|
+
* Processes validated operations asynchronously after ACK has been sent.
|
|
2930
|
+
* Uses BackpressureRegulator to periodically force sync processing and
|
|
2931
|
+
* prevent unbounded accumulation of async work.
|
|
2707
2932
|
*/
|
|
2708
|
-
private
|
|
2933
|
+
private processBatchAsync;
|
|
2709
2934
|
/**
|
|
2710
|
-
*
|
|
2935
|
+
* === BACKPRESSURE: Synchronous Batch Processing ===
|
|
2936
|
+
* Processes operations synchronously, waiting for broadcast completion.
|
|
2937
|
+
* Used when backpressure forces sync to drain the pipeline.
|
|
2711
2938
|
*/
|
|
2712
|
-
private
|
|
2939
|
+
private processBatchSync;
|
|
2713
2940
|
/**
|
|
2714
|
-
*
|
|
2941
|
+
* Forward operation to owner node and wait for completion.
|
|
2942
|
+
* Used in sync processing mode.
|
|
2715
2943
|
*/
|
|
2716
|
-
private
|
|
2944
|
+
private forwardOpAndWait;
|
|
2717
2945
|
/**
|
|
2718
|
-
*
|
|
2946
|
+
* Process a single operation for batch processing.
|
|
2947
|
+
* Uses shared applyOpToMap but collects events instead of broadcasting immediately.
|
|
2719
2948
|
*/
|
|
2720
|
-
private
|
|
2949
|
+
private processLocalOpForBatch;
|
|
2950
|
+
private handleClusterEvent;
|
|
2951
|
+
getMap(name: string, typeHint?: 'LWW' | 'OR'): LWWMap<string, any> | ORMap<string, any>;
|
|
2721
2952
|
/**
|
|
2722
|
-
*
|
|
2953
|
+
* Returns map after ensuring it's fully loaded from storage.
|
|
2954
|
+
* Use this for queries to avoid returning empty results during initial load.
|
|
2723
2955
|
*/
|
|
2724
|
-
|
|
2956
|
+
getMapAsync(name: string, typeHint?: 'LWW' | 'OR'): Promise<LWWMap<string, any> | ORMap<string, any>>;
|
|
2725
2957
|
/**
|
|
2726
|
-
*
|
|
2958
|
+
* Phase 10.04: Get local record for anti-entropy repair
|
|
2959
|
+
* Returns the LWWRecord for a key, used by RepairScheduler
|
|
2727
2960
|
*/
|
|
2728
|
-
private
|
|
2961
|
+
private getLocalRecord;
|
|
2729
2962
|
/**
|
|
2730
|
-
*
|
|
2963
|
+
* Phase 10.04: Apply repaired record from anti-entropy repair
|
|
2964
|
+
* Used by RepairScheduler to apply resolved conflicts
|
|
2731
2965
|
*/
|
|
2732
|
-
private
|
|
2966
|
+
private applyRepairRecord;
|
|
2967
|
+
private loadMapFromStorage;
|
|
2968
|
+
private startGarbageCollection;
|
|
2733
2969
|
/**
|
|
2734
|
-
*
|
|
2970
|
+
* Starts the periodic check for dead clients (those that haven't sent PING).
|
|
2735
2971
|
*/
|
|
2736
|
-
private
|
|
2972
|
+
private startHeartbeatCheck;
|
|
2737
2973
|
/**
|
|
2738
|
-
*
|
|
2974
|
+
* Handles incoming PING message from client.
|
|
2975
|
+
* Responds with PONG immediately.
|
|
2739
2976
|
*/
|
|
2740
|
-
private
|
|
2977
|
+
private handlePing;
|
|
2741
2978
|
/**
|
|
2742
|
-
*
|
|
2979
|
+
* Checks if a client is still alive based on heartbeat.
|
|
2743
2980
|
*/
|
|
2744
|
-
|
|
2981
|
+
isClientAlive(clientId: string): boolean;
|
|
2745
2982
|
/**
|
|
2746
|
-
*
|
|
2983
|
+
* Returns how long the client has been idle (no PING received).
|
|
2984
|
+
*/
|
|
2985
|
+
getClientIdleTime(clientId: string): number;
|
|
2986
|
+
/**
|
|
2987
|
+
* Evicts clients that haven't sent a PING within the timeout period.
|
|
2988
|
+
*/
|
|
2989
|
+
private evictDeadClients;
|
|
2990
|
+
private reportLocalHlc;
|
|
2991
|
+
private handleGcReport;
|
|
2992
|
+
private performGarbageCollection;
|
|
2993
|
+
private buildTLSOptions;
|
|
2994
|
+
/**
|
|
2995
|
+
* Get effective Write Concern level for an operation.
|
|
2996
|
+
* Per-op writeConcern overrides batch-level.
|
|
2747
2997
|
*/
|
|
2748
|
-
private
|
|
2998
|
+
private getEffectiveWriteConcern;
|
|
2749
2999
|
/**
|
|
2750
|
-
*
|
|
3000
|
+
* Convert string WriteConcern value to enum.
|
|
2751
3001
|
*/
|
|
2752
|
-
|
|
3002
|
+
private stringToWriteConcern;
|
|
2753
3003
|
/**
|
|
2754
|
-
*
|
|
3004
|
+
* Process batch with Write Concern tracking.
|
|
3005
|
+
* Notifies WriteAckManager at each stage of processing.
|
|
2755
3006
|
*/
|
|
2756
|
-
|
|
3007
|
+
private processBatchAsyncWithWriteConcern;
|
|
2757
3008
|
/**
|
|
2758
|
-
*
|
|
3009
|
+
* Synchronous batch processing with Write Concern.
|
|
2759
3010
|
*/
|
|
2760
|
-
|
|
3011
|
+
private processBatchSyncWithWriteConcern;
|
|
2761
3012
|
/**
|
|
2762
|
-
*
|
|
3013
|
+
* Process a single operation with Write Concern level notifications.
|
|
2763
3014
|
*/
|
|
2764
|
-
|
|
3015
|
+
private processLocalOpWithWriteConcern;
|
|
2765
3016
|
/**
|
|
2766
|
-
*
|
|
3017
|
+
* Persist operation synchronously (blocking).
|
|
3018
|
+
* Used for PERSISTED Write Concern.
|
|
2767
3019
|
*/
|
|
2768
|
-
|
|
3020
|
+
private persistOpSync;
|
|
2769
3021
|
/**
|
|
2770
|
-
*
|
|
3022
|
+
* Persist operation asynchronously (fire-and-forget).
|
|
3023
|
+
* Used for non-PERSISTED Write Concern levels.
|
|
2771
3024
|
*/
|
|
2772
|
-
|
|
3025
|
+
private persistOpAsync;
|
|
2773
3026
|
}
|
|
2774
3027
|
|
|
2775
|
-
interface
|
|
2776
|
-
|
|
2777
|
-
backups: string[];
|
|
3028
|
+
interface PostgresAdapterOptions {
|
|
3029
|
+
tableName?: string;
|
|
2778
3030
|
}
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
3031
|
+
declare class PostgresAdapter implements IServerStorage {
|
|
3032
|
+
private pool;
|
|
3033
|
+
private tableName;
|
|
3034
|
+
constructor(configOrPool: PoolConfig | Pool, options?: PostgresAdapterOptions);
|
|
3035
|
+
initialize(): Promise<void>;
|
|
3036
|
+
close(): Promise<void>;
|
|
3037
|
+
load(mapName: string, key: string): Promise<StorageValue<any> | undefined>;
|
|
3038
|
+
loadAll(mapName: string, keys: string[]): Promise<Map<string, StorageValue<any>>>;
|
|
3039
|
+
loadAllKeys(mapName: string): Promise<string[]>;
|
|
3040
|
+
store(mapName: string, key: string, record: StorageValue<any>): Promise<void>;
|
|
3041
|
+
storeAll(mapName: string, records: Map<string, StorageValue<any>>): Promise<void>;
|
|
3042
|
+
delete(mapName: string, key: string): Promise<void>;
|
|
3043
|
+
deleteAll(mapName: string, keys: string[]): Promise<void>;
|
|
3044
|
+
private mapRowToRecord;
|
|
3045
|
+
private isORMapValue;
|
|
2787
3046
|
}
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
3047
|
+
|
|
3048
|
+
/**
|
|
3049
|
+
* In-memory implementation of IServerStorage.
|
|
3050
|
+
* Useful for development, testing, and demos without requiring a database.
|
|
3051
|
+
*
|
|
3052
|
+
* Note: Data is lost when the server restarts.
|
|
3053
|
+
*/
|
|
3054
|
+
declare class MemoryServerAdapter implements IServerStorage {
|
|
3055
|
+
private storage;
|
|
3056
|
+
initialize(): Promise<void>;
|
|
3057
|
+
close(): Promise<void>;
|
|
3058
|
+
private getMap;
|
|
3059
|
+
load(mapName: string, key: string): Promise<StorageValue<any> | undefined>;
|
|
3060
|
+
loadAll(mapName: string, keys: string[]): Promise<Map<string, StorageValue<any>>>;
|
|
3061
|
+
loadAllKeys(mapName: string): Promise<string[]>;
|
|
3062
|
+
store(mapName: string, key: string, record: StorageValue<any>): Promise<void>;
|
|
3063
|
+
storeAll(mapName: string, records: Map<string, StorageValue<any>>): Promise<void>;
|
|
3064
|
+
delete(mapName: string, key: string): Promise<void>;
|
|
3065
|
+
deleteAll(mapName: string, keys: string[]): Promise<void>;
|
|
2793
3066
|
}
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
private
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
3067
|
+
|
|
3068
|
+
declare class SecurityManager {
|
|
3069
|
+
private policies;
|
|
3070
|
+
constructor(policies?: PermissionPolicy[]);
|
|
3071
|
+
addPolicy(policy: PermissionPolicy): void;
|
|
3072
|
+
checkPermission(principal: Principal, mapName: string, action: PermissionType): boolean;
|
|
3073
|
+
filterObject(object: any, principal: Principal, mapName: string): any;
|
|
3074
|
+
private hasRole;
|
|
3075
|
+
private matchesMap;
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3078
|
+
declare const logger: pino.Logger<never, boolean>;
|
|
3079
|
+
type Logger = typeof logger;
|
|
3080
|
+
|
|
3081
|
+
/**
|
|
3082
|
+
* ConnectionRateLimiter - Rate limiter for incoming WebSocket connections.
|
|
3083
|
+
*
|
|
3084
|
+
* Implements connection rate limiting to prevent connection storms and
|
|
3085
|
+
* protect the server from being overwhelmed during high load scenarios.
|
|
3086
|
+
*
|
|
3087
|
+
* Features:
|
|
3088
|
+
* - Limits connections per second to prevent TCP backlog exhaustion
|
|
3089
|
+
* - Tracks pending connections (in-progress handshakes)
|
|
3090
|
+
* - Provides graceful rejection when limits are exceeded
|
|
3091
|
+
* - Auto-resets counters after cooldown period
|
|
3092
|
+
*/
|
|
3093
|
+
interface RateLimiterConfig {
|
|
3094
|
+
/** Maximum new connections allowed per second (default: 100) */
|
|
3095
|
+
maxConnectionsPerSecond: number;
|
|
3096
|
+
/** Maximum pending connections waiting for handshake (default: 1000) */
|
|
3097
|
+
maxPendingConnections: number;
|
|
3098
|
+
/** Cooldown period in ms after which counters reset (default: 1000) */
|
|
3099
|
+
cooldownMs: number;
|
|
3100
|
+
}
|
|
3101
|
+
interface RateLimiterStats {
|
|
3102
|
+
/** Current connections per second rate */
|
|
3103
|
+
connectionsPerSecond: number;
|
|
3104
|
+
/** Number of connections currently pending (handshake in progress) */
|
|
3105
|
+
pendingConnections: number;
|
|
3106
|
+
/** Total connections established since start */
|
|
3107
|
+
totalConnections: number;
|
|
3108
|
+
/** Total connections rejected due to rate limiting */
|
|
3109
|
+
totalRejected: number;
|
|
3110
|
+
}
|
|
3111
|
+
declare class ConnectionRateLimiter {
|
|
2801
3112
|
private config;
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
/**
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
private
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
isRelated(key: string): boolean;
|
|
2814
|
-
/**
|
|
2815
|
-
* Get current partition map version
|
|
2816
|
-
*/
|
|
2817
|
-
getMapVersion(): number;
|
|
2818
|
-
/**
|
|
2819
|
-
* Generate full PartitionMap for client consumption
|
|
2820
|
-
*/
|
|
2821
|
-
getPartitionMap(): PartitionMap;
|
|
3113
|
+
/** Connection attempts in current window */
|
|
3114
|
+
private connectionCount;
|
|
3115
|
+
/** Timestamp when current window started */
|
|
3116
|
+
private windowStart;
|
|
3117
|
+
/** Currently pending connections (handshake in progress) */
|
|
3118
|
+
private pendingCount;
|
|
3119
|
+
/** Total connections established since start */
|
|
3120
|
+
private totalConnections;
|
|
3121
|
+
/** Total connections rejected since start */
|
|
3122
|
+
private totalRejected;
|
|
3123
|
+
constructor(config?: Partial<RateLimiterConfig>);
|
|
2822
3124
|
/**
|
|
2823
|
-
*
|
|
3125
|
+
* Check if a new connection should be accepted.
|
|
3126
|
+
* @returns true if the connection should be accepted, false if it should be rejected
|
|
2824
3127
|
*/
|
|
2825
|
-
|
|
3128
|
+
shouldAccept(): boolean;
|
|
2826
3129
|
/**
|
|
2827
|
-
*
|
|
3130
|
+
* Register a connection attempt.
|
|
3131
|
+
* Call this when a new connection is initiated (before handshake completes).
|
|
2828
3132
|
*/
|
|
2829
|
-
|
|
2830
|
-
private rebalance;
|
|
3133
|
+
onConnectionAttempt(): void;
|
|
2831
3134
|
/**
|
|
2832
|
-
*
|
|
3135
|
+
* Register that a connection has been established (handshake complete).
|
|
3136
|
+
* Call this when the connection is fully established and authenticated.
|
|
2833
3137
|
*/
|
|
2834
|
-
|
|
3138
|
+
onConnectionEstablished(): void;
|
|
2835
3139
|
/**
|
|
2836
|
-
*
|
|
3140
|
+
* Register that a connection has been closed.
|
|
3141
|
+
* Call this when a pending connection is closed before completing handshake.
|
|
2837
3142
|
*/
|
|
2838
|
-
|
|
3143
|
+
onConnectionClosed(): void;
|
|
2839
3144
|
/**
|
|
2840
|
-
*
|
|
3145
|
+
* Register that a connection was rejected.
|
|
3146
|
+
* Call this when shouldAccept() returns false and the connection is rejected.
|
|
2841
3147
|
*/
|
|
2842
|
-
|
|
3148
|
+
onConnectionRejected(): void;
|
|
2843
3149
|
/**
|
|
2844
|
-
*
|
|
3150
|
+
* Decrease pending count when a connection times out or fails.
|
|
3151
|
+
* Call this when a pending connection fails to complete handshake.
|
|
2845
3152
|
*/
|
|
2846
|
-
|
|
3153
|
+
onPendingConnectionFailed(): void;
|
|
2847
3154
|
/**
|
|
2848
|
-
*
|
|
3155
|
+
* Get current rate limiter statistics.
|
|
2849
3156
|
*/
|
|
2850
|
-
|
|
3157
|
+
getStats(): RateLimiterStats;
|
|
2851
3158
|
/**
|
|
2852
|
-
*
|
|
3159
|
+
* Reset the rate limiter state.
|
|
3160
|
+
* Useful for testing or when recovering from errors.
|
|
2853
3161
|
*/
|
|
2854
|
-
|
|
3162
|
+
reset(): void;
|
|
2855
3163
|
/**
|
|
2856
|
-
*
|
|
3164
|
+
* Update configuration at runtime.
|
|
2857
3165
|
*/
|
|
2858
|
-
|
|
3166
|
+
updateConfig(config: Partial<RateLimiterConfig>): void;
|
|
2859
3167
|
/**
|
|
2860
|
-
*
|
|
3168
|
+
* Check if window has expired and reset if needed.
|
|
2861
3169
|
*/
|
|
2862
|
-
|
|
3170
|
+
private maybeResetWindow;
|
|
3171
|
+
}
|
|
3172
|
+
|
|
3173
|
+
declare class TimestampInterceptor implements IInterceptor {
|
|
3174
|
+
name: string;
|
|
3175
|
+
onBeforeOp(op: ServerOp, context: OpContext): Promise<ServerOp>;
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3178
|
+
interface RateLimitConfig {
|
|
3179
|
+
windowMs: number;
|
|
3180
|
+
maxOps: number;
|
|
3181
|
+
}
|
|
3182
|
+
declare class RateLimitInterceptor implements IInterceptor {
|
|
3183
|
+
name: string;
|
|
3184
|
+
private limits;
|
|
3185
|
+
private config;
|
|
3186
|
+
constructor(config?: RateLimitConfig);
|
|
3187
|
+
onBeforeOp(op: ServerOp, context: OpContext): Promise<ServerOp | null>;
|
|
3188
|
+
onDisconnect(context: any): Promise<void>;
|
|
3189
|
+
}
|
|
3190
|
+
|
|
3191
|
+
/**
|
|
3192
|
+
* Native Module Statistics
|
|
3193
|
+
*
|
|
3194
|
+
* Provides information about available native optimizations.
|
|
3195
|
+
*
|
|
3196
|
+
* Phase 3.05: Integration
|
|
3197
|
+
*/
|
|
3198
|
+
|
|
3199
|
+
/**
|
|
3200
|
+
* Native module availability status
|
|
3201
|
+
*/
|
|
3202
|
+
interface NativeModuleStatus {
|
|
3203
|
+
/** Native xxHash64 is available and being used */
|
|
3204
|
+
nativeHash: boolean;
|
|
3205
|
+
/** SharedArrayBuffer is available */
|
|
3206
|
+
sharedArrayBuffer: boolean;
|
|
3207
|
+
}
|
|
3208
|
+
/**
|
|
3209
|
+
* Comprehensive native statistics
|
|
3210
|
+
*/
|
|
3211
|
+
interface NativeStats {
|
|
3212
|
+
/** Module availability status */
|
|
3213
|
+
modules: NativeModuleStatus;
|
|
3214
|
+
/** Shared memory statistics (if enabled) */
|
|
3215
|
+
sharedMemory: SharedMemoryStats | null;
|
|
3216
|
+
/** Summary of what's being used */
|
|
3217
|
+
summary: string;
|
|
2863
3218
|
}
|
|
3219
|
+
/**
|
|
3220
|
+
* Check which native modules are available.
|
|
3221
|
+
*/
|
|
3222
|
+
declare function getNativeModuleStatus(): NativeModuleStatus;
|
|
3223
|
+
/**
|
|
3224
|
+
* Get native statistics including shared memory.
|
|
3225
|
+
*
|
|
3226
|
+
* @param sharedMemoryManager - Optional SharedMemoryManager instance
|
|
3227
|
+
*/
|
|
3228
|
+
declare function getNativeStats(sharedMemoryManager?: SharedMemoryManager): NativeStats;
|
|
3229
|
+
/**
|
|
3230
|
+
* Log native module status to console.
|
|
3231
|
+
*/
|
|
3232
|
+
declare function logNativeStatus(): void;
|
|
2864
3233
|
|
|
2865
3234
|
/**
|
|
2866
3235
|
* LagTracker - Monitors replication lag across cluster nodes
|
|
@@ -3687,6 +4056,7 @@ declare class RepairScheduler extends EventEmitter {
|
|
|
3687
4056
|
private activeRepairs;
|
|
3688
4057
|
private scanTimer?;
|
|
3689
4058
|
private processTimer?;
|
|
4059
|
+
private initialScanTimer?;
|
|
3690
4060
|
private started;
|
|
3691
4061
|
private pendingRequests;
|
|
3692
4062
|
private metrics;
|
|
@@ -3955,792 +4325,530 @@ declare class EntryProcessorHandler {
|
|
|
3955
4325
|
fallbackScripts: number;
|
|
3956
4326
|
};
|
|
3957
4327
|
/**
|
|
3958
|
-
* Clear sandbox cache.
|
|
3959
|
-
*/
|
|
3960
|
-
clearCache(processorName?: string): void;
|
|
3961
|
-
/**
|
|
3962
|
-
* Dispose of the handler and its sandbox.
|
|
3963
|
-
*/
|
|
3964
|
-
dispose(): void;
|
|
3965
|
-
}
|
|
3966
|
-
|
|
3967
|
-
/**
|
|
3968
|
-
* Configuration for ConflictResolverService.
|
|
3969
|
-
*/
|
|
3970
|
-
interface ConflictResolverServiceConfig {
|
|
3971
|
-
/** Maximum resolvers per map */
|
|
3972
|
-
maxResolversPerMap: number;
|
|
3973
|
-
/** Enable sandboxed code execution (requires isolated-vm) */
|
|
3974
|
-
enableSandboxedResolvers: boolean;
|
|
3975
|
-
/** Default timeout for resolver execution in milliseconds */
|
|
3976
|
-
resolverTimeoutMs: number;
|
|
3977
|
-
}
|
|
3978
|
-
/**
|
|
3979
|
-
* Default service configuration.
|
|
3980
|
-
*/
|
|
3981
|
-
declare const DEFAULT_CONFLICT_RESOLVER_CONFIG: ConflictResolverServiceConfig;
|
|
3982
|
-
/**
|
|
3983
|
-
* Service for managing and executing conflict resolvers.
|
|
3984
|
-
*
|
|
3985
|
-
* Resolvers are executed in priority order (highest first).
|
|
3986
|
-
* The first resolver that returns a non-'local' action wins.
|
|
3987
|
-
* If all resolvers return 'local', LWW is used as fallback.
|
|
3988
|
-
*
|
|
3989
|
-
* ## Design Decisions
|
|
3990
|
-
*
|
|
3991
|
-
* ### In-Memory Storage
|
|
3992
|
-
* Resolvers are stored in memory only (not persisted to database).
|
|
3993
|
-
* This is intentional - resolvers represent application logic that should
|
|
3994
|
-
* be registered by clients on connection. Benefits:
|
|
3995
|
-
* - Simpler architecture without resolver schema migrations
|
|
3996
|
-
* - Clients control their own conflict resolution logic
|
|
3997
|
-
* - Natural cleanup when client disconnects
|
|
3998
|
-
*
|
|
3999
|
-
* ### Permission Model
|
|
4000
|
-
* Resolver registration requires PUT permission on the target map.
|
|
4001
|
-
* This aligns with the principle that if you can write to a map,
|
|
4002
|
-
* you can define how your writes are resolved. For stricter control,
|
|
4003
|
-
* implement custom permission checks in ServerCoordinator.
|
|
4004
|
-
*
|
|
4005
|
-
* ### Deletion Handling
|
|
4006
|
-
* Deletions (tombstones with null value) are passed through resolvers
|
|
4007
|
-
* with `remoteValue: null`. This allows resolvers like IMMUTABLE or
|
|
4008
|
-
* OWNER_ONLY to protect against unauthorized deletions.
|
|
4009
|
-
*/
|
|
4010
|
-
declare class ConflictResolverService {
|
|
4011
|
-
private resolvers;
|
|
4012
|
-
private sandbox;
|
|
4013
|
-
private config;
|
|
4014
|
-
private onRejectionCallback?;
|
|
4015
|
-
private disposed;
|
|
4016
|
-
constructor(sandbox: ProcessorSandbox, config?: Partial<ConflictResolverServiceConfig>);
|
|
4017
|
-
/**
|
|
4018
|
-
* Set callback for merge rejections.
|
|
4019
|
-
*/
|
|
4020
|
-
onRejection(callback: (rejection: MergeRejection) => void): void;
|
|
4021
|
-
/**
|
|
4022
|
-
* Register a resolver for a map.
|
|
4023
|
-
*
|
|
4024
|
-
* @param mapName The map this resolver applies to
|
|
4025
|
-
* @param resolver The resolver definition
|
|
4026
|
-
* @param registeredBy Optional client ID that registered this resolver
|
|
4027
|
-
*/
|
|
4028
|
-
register<V>(mapName: string, resolver: ConflictResolverDef<V>, registeredBy?: string): void;
|
|
4029
|
-
/**
|
|
4030
|
-
* Unregister a resolver.
|
|
4031
|
-
*
|
|
4032
|
-
* @param mapName The map name
|
|
4033
|
-
* @param resolverName The resolver name to unregister
|
|
4034
|
-
* @param clientId Optional - only unregister if registered by this client
|
|
4035
|
-
*/
|
|
4036
|
-
unregister(mapName: string, resolverName: string, clientId?: string): boolean;
|
|
4037
|
-
/**
|
|
4038
|
-
* Resolve a merge conflict using registered resolvers.
|
|
4039
|
-
*
|
|
4040
|
-
* @param context The merge context
|
|
4041
|
-
* @returns The merge result
|
|
4042
|
-
*/
|
|
4043
|
-
resolve<V>(context: MergeContext<V>): Promise<MergeResult<V>>;
|
|
4044
|
-
/**
|
|
4045
|
-
* List registered resolvers.
|
|
4046
|
-
*
|
|
4047
|
-
* @param mapName Optional - filter by map name
|
|
4048
|
-
*/
|
|
4049
|
-
list(mapName?: string): Array<{
|
|
4050
|
-
mapName: string;
|
|
4051
|
-
name: string;
|
|
4052
|
-
priority?: number;
|
|
4053
|
-
keyPattern?: string;
|
|
4054
|
-
registeredBy?: string;
|
|
4055
|
-
}>;
|
|
4056
|
-
/**
|
|
4057
|
-
* Check if a map has any registered resolvers.
|
|
4058
|
-
*/
|
|
4059
|
-
hasResolvers(mapName: string): boolean;
|
|
4060
|
-
/**
|
|
4061
|
-
* Get the number of registered resolvers.
|
|
4062
|
-
*/
|
|
4063
|
-
get size(): number;
|
|
4064
|
-
/**
|
|
4065
|
-
* Clear all registered resolvers.
|
|
4066
|
-
*
|
|
4067
|
-
* @param mapName Optional - only clear resolvers for specific map
|
|
4068
|
-
*/
|
|
4069
|
-
clear(mapName?: string): void;
|
|
4070
|
-
/**
|
|
4071
|
-
* Clear resolvers registered by a specific client.
|
|
4072
|
-
*/
|
|
4073
|
-
clearByClient(clientId: string): number;
|
|
4074
|
-
/**
|
|
4075
|
-
* Dispose the service.
|
|
4076
|
-
*/
|
|
4077
|
-
dispose(): void;
|
|
4078
|
-
/**
|
|
4079
|
-
* Match a key against a glob-like pattern.
|
|
4080
|
-
* Supports * (any chars) and ? (single char).
|
|
4081
|
-
*/
|
|
4082
|
-
private matchKeyPattern;
|
|
4083
|
-
/**
|
|
4084
|
-
* Compile sandboxed resolver code.
|
|
4085
|
-
*/
|
|
4086
|
-
private compileSandboxed;
|
|
4087
|
-
}
|
|
4088
|
-
|
|
4089
|
-
/**
|
|
4090
|
-
* Configuration for MapWithResolver.
|
|
4091
|
-
*/
|
|
4092
|
-
interface MapWithResolverConfig {
|
|
4093
|
-
/** Map name */
|
|
4094
|
-
name: string;
|
|
4095
|
-
/** Node ID for HLC */
|
|
4096
|
-
nodeId: string;
|
|
4097
|
-
/** Conflict resolver service */
|
|
4098
|
-
resolverService: ConflictResolverService;
|
|
4099
|
-
/** Callback for merge rejections */
|
|
4100
|
-
onRejection?: (rejection: MergeRejection) => void;
|
|
4101
|
-
}
|
|
4102
|
-
/**
|
|
4103
|
-
* Result of setWithResolver operation.
|
|
4104
|
-
*/
|
|
4105
|
-
interface SetWithResolverResult<V> {
|
|
4106
|
-
/** Whether the value was applied */
|
|
4107
|
-
applied: boolean;
|
|
4108
|
-
/** The merge result */
|
|
4109
|
-
result: MergeResult<V>;
|
|
4110
|
-
/** The final record if applied */
|
|
4111
|
-
record?: LWWRecord<V>;
|
|
4112
|
-
}
|
|
4113
|
-
/**
|
|
4114
|
-
* Extended LWWMap that supports custom conflict resolvers.
|
|
4115
|
-
*
|
|
4116
|
-
* This wrapper delegates merge operations to ConflictResolverService,
|
|
4117
|
-
* allowing custom business logic to intercept and modify merge behavior.
|
|
4118
|
-
*/
|
|
4119
|
-
declare class MapWithResolver<K extends string, V> {
|
|
4120
|
-
private map;
|
|
4121
|
-
private resolverService;
|
|
4122
|
-
private mapName;
|
|
4123
|
-
private hlc;
|
|
4124
|
-
private onRejection?;
|
|
4125
|
-
constructor(config: MapWithResolverConfig);
|
|
4126
|
-
/**
|
|
4127
|
-
* Get the map name.
|
|
4128
|
-
*/
|
|
4129
|
-
get name(): string;
|
|
4130
|
-
/**
|
|
4131
|
-
* Get the underlying LWWMap.
|
|
4132
|
-
*/
|
|
4133
|
-
get rawMap(): LWWMap<K, V>;
|
|
4134
|
-
/**
|
|
4135
|
-
* Get a value by key.
|
|
4136
|
-
*/
|
|
4137
|
-
get(key: K): V | undefined;
|
|
4138
|
-
/**
|
|
4139
|
-
* Get the full record for a key.
|
|
4140
|
-
*/
|
|
4141
|
-
getRecord(key: K): LWWRecord<V> | undefined;
|
|
4142
|
-
/**
|
|
4143
|
-
* Get the timestamp for a key.
|
|
4144
|
-
*/
|
|
4145
|
-
getTimestamp(key: K): Timestamp | undefined;
|
|
4146
|
-
/**
|
|
4147
|
-
* Set a value locally (no resolver).
|
|
4148
|
-
* Use for server-initiated writes.
|
|
4149
|
-
*/
|
|
4150
|
-
set(key: K, value: V, ttlMs?: number): LWWRecord<V>;
|
|
4151
|
-
/**
|
|
4152
|
-
* Set a value with conflict resolution.
|
|
4153
|
-
* Use for client-initiated writes.
|
|
4154
|
-
*
|
|
4155
|
-
* @param key The key to set
|
|
4156
|
-
* @param value The new value
|
|
4157
|
-
* @param timestamp The client's timestamp
|
|
4158
|
-
* @param remoteNodeId The client's node ID
|
|
4159
|
-
* @param auth Optional authentication context
|
|
4160
|
-
* @returns Result containing applied status and merge result
|
|
4161
|
-
*/
|
|
4162
|
-
setWithResolver(key: K, value: V, timestamp: Timestamp, remoteNodeId: string, auth?: MergeContext['auth']): Promise<SetWithResolverResult<V>>;
|
|
4163
|
-
/**
|
|
4164
|
-
* Remove a key.
|
|
4165
|
-
*/
|
|
4166
|
-
remove(key: K): LWWRecord<V>;
|
|
4167
|
-
/**
|
|
4168
|
-
* Standard merge without resolver (for sync operations).
|
|
4169
|
-
*/
|
|
4170
|
-
merge(key: K, record: LWWRecord<V>): boolean;
|
|
4171
|
-
/**
|
|
4172
|
-
* Merge with resolver support.
|
|
4173
|
-
* Equivalent to setWithResolver but takes a full record.
|
|
4174
|
-
*/
|
|
4175
|
-
mergeWithResolver(key: K, record: LWWRecord<V>, remoteNodeId: string, auth?: MergeContext['auth']): Promise<SetWithResolverResult<V>>;
|
|
4176
|
-
/**
|
|
4177
|
-
* Clear all data.
|
|
4178
|
-
*/
|
|
4179
|
-
clear(): void;
|
|
4180
|
-
/**
|
|
4181
|
-
* Get map size.
|
|
4182
|
-
*/
|
|
4183
|
-
get size(): number;
|
|
4184
|
-
/**
|
|
4185
|
-
* Iterate over entries.
|
|
4186
|
-
*/
|
|
4187
|
-
entries(): IterableIterator<[K, V]>;
|
|
4188
|
-
/**
|
|
4189
|
-
* Get all keys.
|
|
4190
|
-
*/
|
|
4191
|
-
allKeys(): IterableIterator<K>;
|
|
4192
|
-
/**
|
|
4193
|
-
* Subscribe to changes.
|
|
4194
|
-
*/
|
|
4195
|
-
onChange(callback: () => void): () => void;
|
|
4196
|
-
/**
|
|
4197
|
-
* Get MerkleTree for sync.
|
|
4328
|
+
* Clear sandbox cache.
|
|
4198
4329
|
*/
|
|
4199
|
-
|
|
4330
|
+
clearCache(processorName?: string): void;
|
|
4200
4331
|
/**
|
|
4201
|
-
*
|
|
4332
|
+
* Dispose of the handler and its sandbox.
|
|
4202
4333
|
*/
|
|
4203
|
-
|
|
4334
|
+
dispose(): void;
|
|
4204
4335
|
}
|
|
4205
4336
|
|
|
4206
4337
|
/**
|
|
4207
|
-
* Configuration for
|
|
4338
|
+
* Configuration for ConflictResolverService.
|
|
4208
4339
|
*/
|
|
4209
|
-
interface
|
|
4210
|
-
/**
|
|
4211
|
-
|
|
4212
|
-
/**
|
|
4213
|
-
|
|
4214
|
-
/**
|
|
4215
|
-
|
|
4340
|
+
interface ConflictResolverServiceConfig {
|
|
4341
|
+
/** Maximum resolvers per map */
|
|
4342
|
+
maxResolversPerMap: number;
|
|
4343
|
+
/** Enable sandboxed code execution (requires isolated-vm) */
|
|
4344
|
+
enableSandboxedResolvers: boolean;
|
|
4345
|
+
/** Default timeout for resolver execution in milliseconds */
|
|
4346
|
+
resolverTimeoutMs: number;
|
|
4216
4347
|
}
|
|
4217
4348
|
/**
|
|
4218
|
-
*
|
|
4349
|
+
* Default service configuration.
|
|
4219
4350
|
*/
|
|
4220
|
-
|
|
4221
|
-
/** Whether the merge was applied */
|
|
4222
|
-
applied: boolean;
|
|
4223
|
-
/** The merge result details */
|
|
4224
|
-
result: MergeResult<V>;
|
|
4225
|
-
/** The final record if applied */
|
|
4226
|
-
record?: LWWRecord<V>;
|
|
4227
|
-
/** Rejection details if rejected */
|
|
4228
|
-
rejection?: MergeRejection;
|
|
4229
|
-
}
|
|
4351
|
+
declare const DEFAULT_CONFLICT_RESOLVER_CONFIG: ConflictResolverServiceConfig;
|
|
4230
4352
|
/**
|
|
4231
|
-
*
|
|
4353
|
+
* Service for managing and executing conflict resolvers.
|
|
4232
4354
|
*
|
|
4233
|
-
*
|
|
4234
|
-
*
|
|
4235
|
-
*
|
|
4236
|
-
*
|
|
4355
|
+
* Resolvers are executed in priority order (highest first).
|
|
4356
|
+
* The first resolver that returns a non-'local' action wins.
|
|
4357
|
+
* If all resolvers return 'local', LWW is used as fallback.
|
|
4358
|
+
*
|
|
4359
|
+
* ## Design Decisions
|
|
4360
|
+
*
|
|
4361
|
+
* ### In-Memory Storage
|
|
4362
|
+
* Resolvers are stored in memory only (not persisted to database).
|
|
4363
|
+
* This is intentional - resolvers represent application logic that should
|
|
4364
|
+
* be registered by clients on connection. Benefits:
|
|
4365
|
+
* - Simpler architecture without resolver schema migrations
|
|
4366
|
+
* - Clients control their own conflict resolution logic
|
|
4367
|
+
* - Natural cleanup when client disconnects
|
|
4368
|
+
*
|
|
4369
|
+
* ### Permission Model
|
|
4370
|
+
* Resolver registration requires PUT permission on the target map.
|
|
4371
|
+
* This aligns with the principle that if you can write to a map,
|
|
4372
|
+
* you can define how your writes are resolved. For stricter control,
|
|
4373
|
+
* implement custom permission checks in ServerCoordinator.
|
|
4374
|
+
*
|
|
4375
|
+
* ### Deletion Handling
|
|
4376
|
+
* Deletions (tombstones with null value) are passed through resolvers
|
|
4377
|
+
* with `remoteValue: null`. This allows resolvers like IMMUTABLE or
|
|
4378
|
+
* OWNER_ONLY to protect against unauthorized deletions.
|
|
4237
4379
|
*/
|
|
4238
|
-
declare class
|
|
4380
|
+
declare class ConflictResolverService {
|
|
4381
|
+
private resolvers;
|
|
4239
4382
|
private sandbox;
|
|
4240
|
-
private
|
|
4241
|
-
|
|
4242
|
-
private
|
|
4243
|
-
|
|
4244
|
-
constructor(config: ConflictResolverHandlerConfig);
|
|
4383
|
+
private config;
|
|
4384
|
+
private onRejectionCallback?;
|
|
4385
|
+
private disposed;
|
|
4386
|
+
constructor(sandbox: ProcessorSandbox, config?: Partial<ConflictResolverServiceConfig>);
|
|
4245
4387
|
/**
|
|
4246
|
-
*
|
|
4388
|
+
* Set callback for merge rejections.
|
|
4389
|
+
*/
|
|
4390
|
+
onRejection(callback: (rejection: MergeRejection) => void): void;
|
|
4391
|
+
/**
|
|
4392
|
+
* Register a resolver for a map.
|
|
4247
4393
|
*
|
|
4248
|
-
* @param mapName The map
|
|
4394
|
+
* @param mapName The map this resolver applies to
|
|
4249
4395
|
* @param resolver The resolver definition
|
|
4250
|
-
* @param
|
|
4396
|
+
* @param registeredBy Optional client ID that registered this resolver
|
|
4251
4397
|
*/
|
|
4252
|
-
|
|
4398
|
+
register<V>(mapName: string, resolver: ConflictResolverDef<V>, registeredBy?: string): void;
|
|
4253
4399
|
/**
|
|
4254
|
-
* Unregister a
|
|
4400
|
+
* Unregister a resolver.
|
|
4255
4401
|
*
|
|
4256
4402
|
* @param mapName The map name
|
|
4257
|
-
* @param resolverName The resolver name
|
|
4403
|
+
* @param resolverName The resolver name to unregister
|
|
4258
4404
|
* @param clientId Optional - only unregister if registered by this client
|
|
4259
4405
|
*/
|
|
4260
|
-
|
|
4406
|
+
unregister(mapName: string, resolverName: string, clientId?: string): boolean;
|
|
4407
|
+
/**
|
|
4408
|
+
* Resolve a merge conflict using registered resolvers.
|
|
4409
|
+
*
|
|
4410
|
+
* @param context The merge context
|
|
4411
|
+
* @returns The merge result
|
|
4412
|
+
*/
|
|
4413
|
+
resolve<V>(context: MergeContext<V>): Promise<MergeResult<V>>;
|
|
4261
4414
|
/**
|
|
4262
4415
|
* List registered resolvers.
|
|
4263
4416
|
*
|
|
4264
4417
|
* @param mapName Optional - filter by map name
|
|
4265
4418
|
*/
|
|
4266
|
-
|
|
4419
|
+
list(mapName?: string): Array<{
|
|
4267
4420
|
mapName: string;
|
|
4268
4421
|
name: string;
|
|
4269
4422
|
priority?: number;
|
|
4270
4423
|
keyPattern?: string;
|
|
4424
|
+
registeredBy?: string;
|
|
4271
4425
|
}>;
|
|
4272
4426
|
/**
|
|
4273
|
-
*
|
|
4274
|
-
*
|
|
4275
|
-
* Deletions (tombstones) are also passed through resolvers to allow
|
|
4276
|
-
* protection via IMMUTABLE, OWNER_ONLY, or similar resolvers.
|
|
4277
|
-
* If no custom resolvers are registered, deletions use standard LWW.
|
|
4278
|
-
*
|
|
4279
|
-
* @param map The LWWMap to merge into
|
|
4280
|
-
* @param mapName The map name (for resolver lookup)
|
|
4281
|
-
* @param key The key being merged
|
|
4282
|
-
* @param record The incoming record
|
|
4283
|
-
* @param remoteNodeId The source node ID
|
|
4284
|
-
* @param auth Optional authentication context
|
|
4427
|
+
* Check if a map has any registered resolvers.
|
|
4285
4428
|
*/
|
|
4286
|
-
|
|
4429
|
+
hasResolvers(mapName: string): boolean;
|
|
4287
4430
|
/**
|
|
4288
|
-
*
|
|
4431
|
+
* Get the number of registered resolvers.
|
|
4289
4432
|
*/
|
|
4290
|
-
|
|
4433
|
+
get size(): number;
|
|
4291
4434
|
/**
|
|
4292
|
-
*
|
|
4435
|
+
* Clear all registered resolvers.
|
|
4436
|
+
*
|
|
4437
|
+
* @param mapName Optional - only clear resolvers for specific map
|
|
4293
4438
|
*/
|
|
4294
|
-
|
|
4439
|
+
clear(mapName?: string): void;
|
|
4295
4440
|
/**
|
|
4296
4441
|
* Clear resolvers registered by a specific client.
|
|
4297
4442
|
*/
|
|
4298
4443
|
clearByClient(clientId: string): number;
|
|
4299
4444
|
/**
|
|
4300
|
-
*
|
|
4445
|
+
* Dispose the service.
|
|
4301
4446
|
*/
|
|
4302
|
-
|
|
4447
|
+
dispose(): void;
|
|
4303
4448
|
/**
|
|
4304
|
-
*
|
|
4449
|
+
* Match a key against a glob-like pattern.
|
|
4450
|
+
* Supports * (any chars) and ? (single char).
|
|
4305
4451
|
*/
|
|
4306
|
-
|
|
4452
|
+
private matchKeyPattern;
|
|
4307
4453
|
/**
|
|
4308
|
-
*
|
|
4454
|
+
* Compile sandboxed resolver code.
|
|
4309
4455
|
*/
|
|
4310
|
-
|
|
4456
|
+
private compileSandboxed;
|
|
4311
4457
|
}
|
|
4312
4458
|
|
|
4313
4459
|
/**
|
|
4314
|
-
*
|
|
4315
|
-
*
|
|
4316
|
-
* Configuration types for server-side index management.
|
|
4317
|
-
* Used to define indexes per map at server startup.
|
|
4318
|
-
*
|
|
4319
|
-
* @module config/IndexConfig
|
|
4320
|
-
*/
|
|
4321
|
-
/**
|
|
4322
|
-
* Definition of a single index on a map.
|
|
4323
|
-
*/
|
|
4324
|
-
interface IndexDefinition {
|
|
4325
|
-
/** Attribute name (supports dot notation for nested attributes, e.g., "user.email") */
|
|
4326
|
-
attribute: string;
|
|
4327
|
-
/** Index type */
|
|
4328
|
-
type: 'hash' | 'navigable';
|
|
4329
|
-
/**
|
|
4330
|
-
* Comparator type for navigable indexes.
|
|
4331
|
-
* Defaults to natural ordering (string/number).
|
|
4332
|
-
*/
|
|
4333
|
-
comparator?: 'number' | 'string' | 'date';
|
|
4334
|
-
}
|
|
4335
|
-
/**
|
|
4336
|
-
* Index configuration for a specific map.
|
|
4460
|
+
* Configuration for MapWithResolver.
|
|
4337
4461
|
*/
|
|
4338
|
-
interface
|
|
4462
|
+
interface MapWithResolverConfig {
|
|
4339
4463
|
/** Map name */
|
|
4340
|
-
|
|
4341
|
-
/**
|
|
4342
|
-
|
|
4464
|
+
name: string;
|
|
4465
|
+
/** Node ID for HLC */
|
|
4466
|
+
nodeId: string;
|
|
4467
|
+
/** Conflict resolver service */
|
|
4468
|
+
resolverService: ConflictResolverService;
|
|
4469
|
+
/** Callback for merge rejections */
|
|
4470
|
+
onRejection?: (rejection: MergeRejection) => void;
|
|
4343
4471
|
}
|
|
4344
4472
|
/**
|
|
4345
|
-
*
|
|
4473
|
+
* Result of setWithResolver operation.
|
|
4346
4474
|
*/
|
|
4347
|
-
interface
|
|
4348
|
-
/**
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
/**
|
|
4355
|
-
* Maximum number of auto-created indexes per map.
|
|
4356
|
-
* Prevents unbounded memory growth from auto-indexing.
|
|
4357
|
-
* Default: 10
|
|
4358
|
-
*/
|
|
4359
|
-
maxAutoIndexesPerMap?: number;
|
|
4360
|
-
/**
|
|
4361
|
-
* Pre-configured indexes per map.
|
|
4362
|
-
* These indexes are created at map initialization.
|
|
4363
|
-
*/
|
|
4364
|
-
maps?: MapIndexConfig[];
|
|
4365
|
-
/**
|
|
4366
|
-
* Whether to log index usage statistics.
|
|
4367
|
-
* Default: false
|
|
4368
|
-
*/
|
|
4369
|
-
logStats?: boolean;
|
|
4370
|
-
/**
|
|
4371
|
-
* Interval in milliseconds for logging index statistics.
|
|
4372
|
-
* Only used if logStats is true.
|
|
4373
|
-
* Default: 60000 (1 minute)
|
|
4374
|
-
*/
|
|
4375
|
-
statsLogInterval?: number;
|
|
4475
|
+
interface SetWithResolverResult<V> {
|
|
4476
|
+
/** Whether the value was applied */
|
|
4477
|
+
applied: boolean;
|
|
4478
|
+
/** The merge result */
|
|
4479
|
+
result: MergeResult<V>;
|
|
4480
|
+
/** The final record if applied */
|
|
4481
|
+
record?: LWWRecord<V>;
|
|
4376
4482
|
}
|
|
4377
4483
|
/**
|
|
4378
|
-
*
|
|
4379
|
-
*/
|
|
4380
|
-
declare const DEFAULT_INDEX_CONFIG: ServerIndexConfig;
|
|
4381
|
-
/**
|
|
4382
|
-
* Validate a ServerIndexConfig object.
|
|
4383
|
-
*
|
|
4384
|
-
* @param config - Config to validate
|
|
4385
|
-
* @returns Array of validation errors (empty if valid)
|
|
4386
|
-
*/
|
|
4387
|
-
declare function validateIndexConfig(config: ServerIndexConfig): string[];
|
|
4388
|
-
/**
|
|
4389
|
-
* Merge user config with defaults.
|
|
4390
|
-
*
|
|
4391
|
-
* @param userConfig - User-provided config
|
|
4392
|
-
* @returns Merged config with defaults
|
|
4393
|
-
*/
|
|
4394
|
-
declare function mergeWithDefaults(userConfig: Partial<ServerIndexConfig>): ServerIndexConfig;
|
|
4395
|
-
|
|
4396
|
-
/**
|
|
4397
|
-
* MapFactory Implementation
|
|
4398
|
-
*
|
|
4399
|
-
* Factory for creating LWWMap or IndexedLWWMap based on configuration.
|
|
4400
|
-
* Used by ServerCoordinator to create maps with proper indexes.
|
|
4484
|
+
* Extended LWWMap that supports custom conflict resolvers.
|
|
4401
4485
|
*
|
|
4402
|
-
*
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
/**
|
|
4406
|
-
* Factory for creating indexed or regular CRDT maps.
|
|
4486
|
+
* This wrapper delegates merge operations to ConflictResolverService,
|
|
4487
|
+
* allowing custom business logic to intercept and modify merge behavior.
|
|
4407
4488
|
*/
|
|
4408
|
-
declare class
|
|
4409
|
-
private
|
|
4410
|
-
private
|
|
4489
|
+
declare class MapWithResolver<K extends string, V> {
|
|
4490
|
+
private map;
|
|
4491
|
+
private resolverService;
|
|
4492
|
+
private mapName;
|
|
4493
|
+
private hlc;
|
|
4494
|
+
private onRejection?;
|
|
4495
|
+
constructor(config: MapWithResolverConfig);
|
|
4411
4496
|
/**
|
|
4412
|
-
*
|
|
4413
|
-
*
|
|
4414
|
-
* @param config - Server index configuration
|
|
4497
|
+
* Get the map name.
|
|
4415
4498
|
*/
|
|
4416
|
-
|
|
4499
|
+
get name(): string;
|
|
4417
4500
|
/**
|
|
4418
|
-
*
|
|
4419
|
-
*
|
|
4420
|
-
* @param mapName - Name of the map
|
|
4421
|
-
* @param hlc - Hybrid Logical Clock instance
|
|
4422
|
-
* @returns LWWMap or IndexedLWWMap depending on configuration
|
|
4501
|
+
* Get the underlying LWWMap.
|
|
4423
4502
|
*/
|
|
4424
|
-
|
|
4503
|
+
get rawMap(): LWWMap<K, V>;
|
|
4425
4504
|
/**
|
|
4426
|
-
*
|
|
4427
|
-
*
|
|
4428
|
-
* @param mapName - Name of the map
|
|
4429
|
-
* @param hlc - Hybrid Logical Clock instance
|
|
4430
|
-
* @returns ORMap or IndexedORMap depending on configuration
|
|
4505
|
+
* Get a value by key.
|
|
4431
4506
|
*/
|
|
4432
|
-
|
|
4507
|
+
get(key: K): V | undefined;
|
|
4433
4508
|
/**
|
|
4434
|
-
*
|
|
4509
|
+
* Get the full record for a key.
|
|
4435
4510
|
*/
|
|
4436
|
-
|
|
4511
|
+
getRecord(key: K): LWWRecord<V> | undefined;
|
|
4437
4512
|
/**
|
|
4438
|
-
*
|
|
4513
|
+
* Get the timestamp for a key.
|
|
4439
4514
|
*/
|
|
4440
|
-
|
|
4515
|
+
getTimestamp(key: K): Timestamp | undefined;
|
|
4441
4516
|
/**
|
|
4442
|
-
*
|
|
4443
|
-
*
|
|
4517
|
+
* Set a value locally (no resolver).
|
|
4518
|
+
* Use for server-initiated writes.
|
|
4444
4519
|
*/
|
|
4445
|
-
|
|
4520
|
+
set(key: K, value: V, ttlMs?: number): LWWRecord<V>;
|
|
4446
4521
|
/**
|
|
4447
|
-
*
|
|
4522
|
+
* Set a value with conflict resolution.
|
|
4523
|
+
* Use for client-initiated writes.
|
|
4448
4524
|
*
|
|
4449
|
-
* @param
|
|
4450
|
-
* @param
|
|
4451
|
-
* @
|
|
4525
|
+
* @param key The key to set
|
|
4526
|
+
* @param value The new value
|
|
4527
|
+
* @param timestamp The client's timestamp
|
|
4528
|
+
* @param remoteNodeId The client's node ID
|
|
4529
|
+
* @param auth Optional authentication context
|
|
4530
|
+
* @returns Result containing applied status and merge result
|
|
4452
4531
|
*/
|
|
4453
|
-
|
|
4532
|
+
setWithResolver(key: K, value: V, timestamp: Timestamp, remoteNodeId: string, auth?: MergeContext['auth']): Promise<SetWithResolverResult<V>>;
|
|
4454
4533
|
/**
|
|
4455
|
-
*
|
|
4534
|
+
* Remove a key.
|
|
4456
4535
|
*/
|
|
4457
|
-
|
|
4536
|
+
remove(key: K): LWWRecord<V>;
|
|
4458
4537
|
/**
|
|
4459
|
-
*
|
|
4460
|
-
*
|
|
4461
|
-
* @param mapName - Name of the map
|
|
4462
|
-
* @returns true if map has index configuration
|
|
4538
|
+
* Standard merge without resolver (for sync operations).
|
|
4463
4539
|
*/
|
|
4464
|
-
|
|
4540
|
+
merge(key: K, record: LWWRecord<V>): boolean;
|
|
4465
4541
|
/**
|
|
4466
|
-
*
|
|
4467
|
-
*
|
|
4468
|
-
* @param mapName - Name of the map
|
|
4469
|
-
* @returns Map index config or undefined
|
|
4542
|
+
* Merge with resolver support.
|
|
4543
|
+
* Equivalent to setWithResolver but takes a full record.
|
|
4470
4544
|
*/
|
|
4471
|
-
|
|
4545
|
+
mergeWithResolver(key: K, record: LWWRecord<V>, remoteNodeId: string, auth?: MergeContext['auth']): Promise<SetWithResolverResult<V>>;
|
|
4472
4546
|
/**
|
|
4473
|
-
*
|
|
4474
|
-
*
|
|
4475
|
-
* @returns Array of map names with index configuration
|
|
4547
|
+
* Clear all data.
|
|
4476
4548
|
*/
|
|
4477
|
-
|
|
4549
|
+
clear(): void;
|
|
4478
4550
|
/**
|
|
4479
|
-
* Get
|
|
4551
|
+
* Get map size.
|
|
4480
4552
|
*/
|
|
4481
|
-
|
|
4553
|
+
get size(): number;
|
|
4554
|
+
/**
|
|
4555
|
+
* Iterate over entries.
|
|
4556
|
+
*/
|
|
4557
|
+
entries(): IterableIterator<[K, V]>;
|
|
4558
|
+
/**
|
|
4559
|
+
* Get all keys.
|
|
4560
|
+
*/
|
|
4561
|
+
allKeys(): IterableIterator<K>;
|
|
4562
|
+
/**
|
|
4563
|
+
* Subscribe to changes.
|
|
4564
|
+
*/
|
|
4565
|
+
onChange(callback: () => void): () => void;
|
|
4566
|
+
/**
|
|
4567
|
+
* Get MerkleTree for sync.
|
|
4568
|
+
*/
|
|
4569
|
+
getMerkleTree(): _topgunbuild_core.MerkleTree;
|
|
4570
|
+
/**
|
|
4571
|
+
* Prune old tombstones.
|
|
4572
|
+
*/
|
|
4573
|
+
prune(olderThan: Timestamp): K[];
|
|
4482
4574
|
}
|
|
4483
4575
|
|
|
4484
4576
|
/**
|
|
4485
|
-
*
|
|
4486
|
-
*
|
|
4487
|
-
* Manages FullTextIndex instances per map and handles search requests.
|
|
4488
|
-
* Part of Phase 11.1a: Server-side BM25 Search.
|
|
4489
|
-
* Phase 11.1b: Live Search Subscriptions with delta updates.
|
|
4490
|
-
*
|
|
4491
|
-
* @module search/SearchCoordinator
|
|
4492
|
-
*/
|
|
4493
|
-
|
|
4494
|
-
/**
|
|
4495
|
-
* Result item returned from server search.
|
|
4496
|
-
*/
|
|
4497
|
-
interface ServerSearchResult {
|
|
4498
|
-
key: string;
|
|
4499
|
-
value: unknown;
|
|
4500
|
-
score: number;
|
|
4501
|
-
matchedTerms: string[];
|
|
4502
|
-
}
|
|
4503
|
-
/**
|
|
4504
|
-
* Configuration for enabling search on a map.
|
|
4577
|
+
* Configuration for ConflictResolverHandler.
|
|
4505
4578
|
*/
|
|
4506
|
-
interface
|
|
4579
|
+
interface ConflictResolverHandlerConfig {
|
|
4580
|
+
/** Node ID for identifying server-side resolvers */
|
|
4581
|
+
nodeId: string;
|
|
4582
|
+
/** Optional sandbox configuration override */
|
|
4583
|
+
sandboxConfig?: Partial<ProcessorSandboxConfig>;
|
|
4584
|
+
/** Optional resolver service configuration */
|
|
4585
|
+
resolverConfig?: Partial<ConflictResolverServiceConfig>;
|
|
4507
4586
|
}
|
|
4508
4587
|
/**
|
|
4509
|
-
*
|
|
4510
|
-
*/
|
|
4511
|
-
type SendUpdateCallback = (clientId: string, subscriptionId: string, key: string, value: unknown, score: number, matchedTerms: string[], type: SearchUpdateType) => void;
|
|
4512
|
-
/**
|
|
4513
|
-
* Batched update for a single document change.
|
|
4588
|
+
* Result of merge operation with resolver.
|
|
4514
4589
|
*/
|
|
4515
|
-
interface
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4590
|
+
interface MergeWithResolverResult<V> {
|
|
4591
|
+
/** Whether the merge was applied */
|
|
4592
|
+
applied: boolean;
|
|
4593
|
+
/** The merge result details */
|
|
4594
|
+
result: MergeResult<V>;
|
|
4595
|
+
/** The final record if applied */
|
|
4596
|
+
record?: LWWRecord<V>;
|
|
4597
|
+
/** Rejection details if rejected */
|
|
4598
|
+
rejection?: MergeRejection;
|
|
4521
4599
|
}
|
|
4522
4600
|
/**
|
|
4523
|
-
*
|
|
4524
|
-
*/
|
|
4525
|
-
type SendBatchUpdateCallback = (clientId: string, subscriptionId: string, updates: BatchedUpdate[]) => void;
|
|
4526
|
-
/**
|
|
4527
|
-
* SearchCoordinator manages full-text search indexes for the server.
|
|
4601
|
+
* Server-side handler for Conflict Resolver operations.
|
|
4528
4602
|
*
|
|
4529
4603
|
* Responsibilities:
|
|
4530
|
-
* -
|
|
4531
|
-
* - Execute
|
|
4532
|
-
* -
|
|
4533
|
-
*
|
|
4534
|
-
* @example
|
|
4535
|
-
* ```typescript
|
|
4536
|
-
* const searchCoordinator = new SearchCoordinator();
|
|
4537
|
-
*
|
|
4538
|
-
* // Enable FTS for a map
|
|
4539
|
-
* searchCoordinator.enableSearch('articles', {
|
|
4540
|
-
* fields: ['title', 'body'],
|
|
4541
|
-
* tokenizer: { minLength: 2 },
|
|
4542
|
-
* bm25: { k1: 1.2, b: 0.75 }
|
|
4543
|
-
* });
|
|
4544
|
-
*
|
|
4545
|
-
* // Search
|
|
4546
|
-
* const results = searchCoordinator.search('articles', 'machine learning', {
|
|
4547
|
-
* limit: 20,
|
|
4548
|
-
* boost: { title: 2.0 }
|
|
4549
|
-
* });
|
|
4550
|
-
* ```
|
|
4604
|
+
* - Manage conflict resolver registrations
|
|
4605
|
+
* - Execute resolvers during merge operations
|
|
4606
|
+
* - Provide merge rejection notifications
|
|
4551
4607
|
*/
|
|
4552
|
-
declare class
|
|
4553
|
-
|
|
4554
|
-
private
|
|
4555
|
-
/**
|
|
4556
|
-
private readonly
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
/** Subscription ID → SearchSubscription */
|
|
4560
|
-
private readonly subscriptions;
|
|
4561
|
-
/** Map name → Set of subscription IDs */
|
|
4562
|
-
private readonly subscriptionsByMap;
|
|
4563
|
-
/** Client ID → Set of subscription IDs */
|
|
4564
|
-
private readonly subscriptionsByClient;
|
|
4565
|
-
/** Callback for sending updates to clients */
|
|
4566
|
-
private sendUpdate?;
|
|
4567
|
-
/** Callback for sending batched updates to clients */
|
|
4568
|
-
private sendBatchUpdate?;
|
|
4569
|
-
/** Queue of pending notifications per map */
|
|
4570
|
-
private readonly pendingNotifications;
|
|
4571
|
-
/** Timer for batching notifications */
|
|
4572
|
-
private notificationTimer;
|
|
4573
|
-
/** Batch interval in milliseconds (~1 frame at 60fps) */
|
|
4574
|
-
private readonly BATCH_INTERVAL;
|
|
4575
|
-
constructor();
|
|
4608
|
+
declare class ConflictResolverHandler {
|
|
4609
|
+
private sandbox;
|
|
4610
|
+
private resolverService;
|
|
4611
|
+
/** Reserved for future use (server-side resolver identification) */
|
|
4612
|
+
private readonly nodeId;
|
|
4613
|
+
private rejectionListeners;
|
|
4614
|
+
constructor(config: ConflictResolverHandlerConfig);
|
|
4576
4615
|
/**
|
|
4577
|
-
*
|
|
4578
|
-
*
|
|
4616
|
+
* Register a conflict resolver for a map.
|
|
4617
|
+
*
|
|
4618
|
+
* @param mapName The map name
|
|
4619
|
+
* @param resolver The resolver definition
|
|
4620
|
+
* @param clientId Optional client ID that registered this resolver
|
|
4621
|
+
*/
|
|
4622
|
+
registerResolver<V>(mapName: string, resolver: ConflictResolverDef<V>, clientId?: string): void;
|
|
4623
|
+
/**
|
|
4624
|
+
* Unregister a conflict resolver.
|
|
4625
|
+
*
|
|
4626
|
+
* @param mapName The map name
|
|
4627
|
+
* @param resolverName The resolver name
|
|
4628
|
+
* @param clientId Optional - only unregister if registered by this client
|
|
4629
|
+
*/
|
|
4630
|
+
unregisterResolver(mapName: string, resolverName: string, clientId?: string): boolean;
|
|
4631
|
+
/**
|
|
4632
|
+
* List registered resolvers.
|
|
4633
|
+
*
|
|
4634
|
+
* @param mapName Optional - filter by map name
|
|
4635
|
+
*/
|
|
4636
|
+
listResolvers(mapName?: string): Array<{
|
|
4637
|
+
mapName: string;
|
|
4638
|
+
name: string;
|
|
4639
|
+
priority?: number;
|
|
4640
|
+
keyPattern?: string;
|
|
4641
|
+
}>;
|
|
4642
|
+
/**
|
|
4643
|
+
* Apply a merge with conflict resolution.
|
|
4644
|
+
*
|
|
4645
|
+
* Deletions (tombstones) are also passed through resolvers to allow
|
|
4646
|
+
* protection via IMMUTABLE, OWNER_ONLY, or similar resolvers.
|
|
4647
|
+
* If no custom resolvers are registered, deletions use standard LWW.
|
|
4648
|
+
*
|
|
4649
|
+
* @param map The LWWMap to merge into
|
|
4650
|
+
* @param mapName The map name (for resolver lookup)
|
|
4651
|
+
* @param key The key being merged
|
|
4652
|
+
* @param record The incoming record
|
|
4653
|
+
* @param remoteNodeId The source node ID
|
|
4654
|
+
* @param auth Optional authentication context
|
|
4655
|
+
*/
|
|
4656
|
+
mergeWithResolver<V>(map: LWWMap<string, V>, mapName: string, key: string, record: LWWRecord<V>, remoteNodeId: string, auth?: MergeContext['auth']): Promise<MergeWithResolverResult<V>>;
|
|
4657
|
+
/**
|
|
4658
|
+
* Check if a map has custom resolvers registered.
|
|
4579
4659
|
*/
|
|
4580
|
-
|
|
4660
|
+
hasResolvers(mapName: string): boolean;
|
|
4581
4661
|
/**
|
|
4582
|
-
*
|
|
4583
|
-
* When set, notifications are batched within BATCH_INTERVAL (16ms) window.
|
|
4584
|
-
* Called by ServerCoordinator during initialization.
|
|
4585
|
-
*
|
|
4586
|
-
* @param callback - Function to call with batched updates
|
|
4662
|
+
* Add a listener for merge rejections.
|
|
4587
4663
|
*/
|
|
4588
|
-
|
|
4664
|
+
onRejection(listener: (rejection: MergeRejection) => void): () => void;
|
|
4589
4665
|
/**
|
|
4590
|
-
*
|
|
4591
|
-
* Called by ServerCoordinator during initialization.
|
|
4666
|
+
* Clear resolvers registered by a specific client.
|
|
4592
4667
|
*/
|
|
4593
|
-
|
|
4668
|
+
clearByClient(clientId: string): number;
|
|
4594
4669
|
/**
|
|
4595
|
-
*
|
|
4596
|
-
*
|
|
4597
|
-
* @param mapName - Name of the map to enable FTS for
|
|
4598
|
-
* @param config - FTS configuration (fields, tokenizer, bm25 options)
|
|
4670
|
+
* Get the number of registered resolvers.
|
|
4599
4671
|
*/
|
|
4600
|
-
|
|
4672
|
+
get resolverCount(): number;
|
|
4601
4673
|
/**
|
|
4602
|
-
*
|
|
4603
|
-
*
|
|
4604
|
-
* @param mapName - Name of the map to disable FTS for
|
|
4674
|
+
* Check if sandbox is in secure mode.
|
|
4605
4675
|
*/
|
|
4606
|
-
|
|
4676
|
+
isSecureMode(): boolean;
|
|
4607
4677
|
/**
|
|
4608
|
-
*
|
|
4678
|
+
* Dispose of the handler.
|
|
4609
4679
|
*/
|
|
4610
|
-
|
|
4680
|
+
dispose(): void;
|
|
4681
|
+
}
|
|
4682
|
+
|
|
4683
|
+
/**
|
|
4684
|
+
* IndexConfig Types
|
|
4685
|
+
*
|
|
4686
|
+
* Configuration types for server-side index management.
|
|
4687
|
+
* Used to define indexes per map at server startup.
|
|
4688
|
+
*
|
|
4689
|
+
* @module config/IndexConfig
|
|
4690
|
+
*/
|
|
4691
|
+
/**
|
|
4692
|
+
* Definition of a single index on a map.
|
|
4693
|
+
*/
|
|
4694
|
+
interface IndexDefinition {
|
|
4695
|
+
/** Attribute name (supports dot notation for nested attributes, e.g., "user.email") */
|
|
4696
|
+
attribute: string;
|
|
4697
|
+
/** Index type */
|
|
4698
|
+
type: 'hash' | 'navigable';
|
|
4611
4699
|
/**
|
|
4612
|
-
*
|
|
4700
|
+
* Comparator type for navigable indexes.
|
|
4701
|
+
* Defaults to natural ordering (string/number).
|
|
4613
4702
|
*/
|
|
4614
|
-
|
|
4703
|
+
comparator?: 'number' | 'string' | 'date';
|
|
4704
|
+
}
|
|
4705
|
+
/**
|
|
4706
|
+
* Index configuration for a specific map.
|
|
4707
|
+
*/
|
|
4708
|
+
interface MapIndexConfig {
|
|
4709
|
+
/** Map name */
|
|
4710
|
+
mapName: string;
|
|
4711
|
+
/** Indexes to create on this map */
|
|
4712
|
+
indexes: IndexDefinition[];
|
|
4713
|
+
}
|
|
4714
|
+
/**
|
|
4715
|
+
* Server-wide index configuration.
|
|
4716
|
+
*/
|
|
4717
|
+
interface ServerIndexConfig {
|
|
4615
4718
|
/**
|
|
4616
|
-
*
|
|
4617
|
-
*
|
|
4618
|
-
*
|
|
4619
|
-
* @param query - Search query text
|
|
4620
|
-
* @param options - Search options (limit, minScore, boost)
|
|
4621
|
-
* @returns Search response payload
|
|
4719
|
+
* Auto-create indexes based on query patterns.
|
|
4720
|
+
* When enabled, the server will analyze query patterns and suggest/create indexes.
|
|
4721
|
+
* Default: false
|
|
4622
4722
|
*/
|
|
4623
|
-
|
|
4723
|
+
autoIndex?: boolean;
|
|
4624
4724
|
/**
|
|
4625
|
-
*
|
|
4626
|
-
*
|
|
4627
|
-
*
|
|
4628
|
-
* @param mapName - Name of the map
|
|
4629
|
-
* @param key - Document key
|
|
4630
|
-
* @param value - Document value
|
|
4725
|
+
* Maximum number of auto-created indexes per map.
|
|
4726
|
+
* Prevents unbounded memory growth from auto-indexing.
|
|
4727
|
+
* Default: 10
|
|
4631
4728
|
*/
|
|
4632
|
-
|
|
4729
|
+
maxAutoIndexesPerMap?: number;
|
|
4633
4730
|
/**
|
|
4634
|
-
*
|
|
4635
|
-
*
|
|
4636
|
-
*
|
|
4637
|
-
* @param mapName - Name of the map
|
|
4638
|
-
* @param entries - Iterator of [key, value] tuples
|
|
4731
|
+
* Pre-configured indexes per map.
|
|
4732
|
+
* These indexes are created at map initialization.
|
|
4639
4733
|
*/
|
|
4640
|
-
|
|
4734
|
+
maps?: MapIndexConfig[];
|
|
4641
4735
|
/**
|
|
4642
|
-
*
|
|
4736
|
+
* Whether to log index usage statistics.
|
|
4737
|
+
* Default: false
|
|
4643
4738
|
*/
|
|
4644
|
-
|
|
4645
|
-
documentCount: number;
|
|
4646
|
-
fields: string[];
|
|
4647
|
-
} | null;
|
|
4739
|
+
logStats?: boolean;
|
|
4648
4740
|
/**
|
|
4649
|
-
*
|
|
4741
|
+
* Interval in milliseconds for logging index statistics.
|
|
4742
|
+
* Only used if logStats is true.
|
|
4743
|
+
* Default: 60000 (1 minute)
|
|
4650
4744
|
*/
|
|
4651
|
-
|
|
4745
|
+
statsLogInterval?: number;
|
|
4746
|
+
}
|
|
4747
|
+
/**
|
|
4748
|
+
* Default index configuration.
|
|
4749
|
+
*/
|
|
4750
|
+
declare const DEFAULT_INDEX_CONFIG: ServerIndexConfig;
|
|
4751
|
+
/**
|
|
4752
|
+
* Validate a ServerIndexConfig object.
|
|
4753
|
+
*
|
|
4754
|
+
* @param config - Config to validate
|
|
4755
|
+
* @returns Array of validation errors (empty if valid)
|
|
4756
|
+
*/
|
|
4757
|
+
declare function validateIndexConfig(config: ServerIndexConfig): string[];
|
|
4758
|
+
/**
|
|
4759
|
+
* Merge user config with defaults.
|
|
4760
|
+
*
|
|
4761
|
+
* @param userConfig - User-provided config
|
|
4762
|
+
* @returns Merged config with defaults
|
|
4763
|
+
*/
|
|
4764
|
+
declare function mergeWithDefaults(userConfig: Partial<ServerIndexConfig>): ServerIndexConfig;
|
|
4765
|
+
|
|
4766
|
+
/**
|
|
4767
|
+
* MapFactory Implementation
|
|
4768
|
+
*
|
|
4769
|
+
* Factory for creating LWWMap or IndexedLWWMap based on configuration.
|
|
4770
|
+
* Used by ServerCoordinator to create maps with proper indexes.
|
|
4771
|
+
*
|
|
4772
|
+
* @module config/MapFactory
|
|
4773
|
+
*/
|
|
4774
|
+
|
|
4775
|
+
/**
|
|
4776
|
+
* Factory for creating indexed or regular CRDT maps.
|
|
4777
|
+
*/
|
|
4778
|
+
declare class MapFactory {
|
|
4779
|
+
private readonly config;
|
|
4780
|
+
private readonly mapConfigs;
|
|
4652
4781
|
/**
|
|
4653
|
-
*
|
|
4654
|
-
* Returns initial results and tracks the subscription for delta updates.
|
|
4782
|
+
* Create a MapFactory.
|
|
4655
4783
|
*
|
|
4656
|
-
* @param
|
|
4657
|
-
* @param subscriptionId - Unique subscription identifier
|
|
4658
|
-
* @param mapName - Name of the map to search
|
|
4659
|
-
* @param query - Search query text
|
|
4660
|
-
* @param options - Search options (limit, minScore, boost)
|
|
4661
|
-
* @returns Initial search results
|
|
4784
|
+
* @param config - Server index configuration
|
|
4662
4785
|
*/
|
|
4663
|
-
|
|
4786
|
+
constructor(config?: Partial<ServerIndexConfig>);
|
|
4664
4787
|
/**
|
|
4665
|
-
*
|
|
4788
|
+
* Create an LWWMap or IndexedLWWMap based on configuration.
|
|
4666
4789
|
*
|
|
4667
|
-
* @param
|
|
4790
|
+
* @param mapName - Name of the map
|
|
4791
|
+
* @param hlc - Hybrid Logical Clock instance
|
|
4792
|
+
* @returns LWWMap or IndexedLWWMap depending on configuration
|
|
4668
4793
|
*/
|
|
4669
|
-
|
|
4794
|
+
createLWWMap<V>(mapName: string, hlc: HLC): LWWMap<string, V> | IndexedLWWMap<string, V>;
|
|
4670
4795
|
/**
|
|
4671
|
-
*
|
|
4672
|
-
* Called when a client disconnects.
|
|
4796
|
+
* Create an ORMap or IndexedORMap based on configuration.
|
|
4673
4797
|
*
|
|
4674
|
-
* @param
|
|
4798
|
+
* @param mapName - Name of the map
|
|
4799
|
+
* @param hlc - Hybrid Logical Clock instance
|
|
4800
|
+
* @returns ORMap or IndexedORMap depending on configuration
|
|
4675
4801
|
*/
|
|
4676
|
-
|
|
4802
|
+
createORMap<V>(mapName: string, hlc: HLC): ORMap<string, V> | IndexedORMap<string, V>;
|
|
4677
4803
|
/**
|
|
4678
|
-
*
|
|
4804
|
+
* Add an index to an IndexedLWWMap based on definition.
|
|
4679
4805
|
*/
|
|
4680
|
-
|
|
4806
|
+
private addIndexToLWWMap;
|
|
4681
4807
|
/**
|
|
4682
|
-
*
|
|
4683
|
-
* Computes delta (ENTER/UPDATE/LEAVE) for each affected subscription.
|
|
4684
|
-
*
|
|
4685
|
-
* @param mapName - Name of the map that changed
|
|
4686
|
-
* @param key - Document key that changed
|
|
4687
|
-
* @param value - New document value (null if removed)
|
|
4688
|
-
* @param changeType - Type of change
|
|
4808
|
+
* Add an index to an IndexedORMap based on definition.
|
|
4689
4809
|
*/
|
|
4690
|
-
private
|
|
4810
|
+
private addIndexToORMap;
|
|
4691
4811
|
/**
|
|
4692
|
-
*
|
|
4693
|
-
*
|
|
4694
|
-
* OPTIMIZED: O(Q × D) complexity instead of O(N) full index scan.
|
|
4695
|
-
* Uses pre-tokenized queryTerms and FullTextIndex.scoreSingleDocument().
|
|
4696
|
-
*
|
|
4697
|
-
* @param subscription - The subscription containing query and cached queryTerms
|
|
4698
|
-
* @param key - Document key
|
|
4699
|
-
* @param value - Document value
|
|
4700
|
-
* @param index - The FullTextIndex for this map
|
|
4701
|
-
* @returns Scored result or null if document doesn't match
|
|
4812
|
+
* Create an Attribute for extracting values from records.
|
|
4813
|
+
* Supports dot notation for nested paths.
|
|
4702
4814
|
*/
|
|
4703
|
-
private
|
|
4815
|
+
private createAttribute;
|
|
4704
4816
|
/**
|
|
4705
|
-
*
|
|
4706
|
-
* Notifications are collected and processed together after BATCH_INTERVAL.
|
|
4817
|
+
* Get a nested value from an object using dot notation.
|
|
4707
4818
|
*
|
|
4708
|
-
* @param
|
|
4709
|
-
* @param
|
|
4710
|
-
* @
|
|
4711
|
-
* @param changeType - Type of change
|
|
4819
|
+
* @param obj - Object to extract value from
|
|
4820
|
+
* @param path - Dot-notation path (e.g., "user.email")
|
|
4821
|
+
* @returns Value at the path or undefined
|
|
4712
4822
|
*/
|
|
4713
|
-
|
|
4823
|
+
private getNestedValue;
|
|
4714
4824
|
/**
|
|
4715
|
-
*
|
|
4716
|
-
* Uses setTimeout to batch notifications within BATCH_INTERVAL window.
|
|
4825
|
+
* Create a comparator function for navigable indexes.
|
|
4717
4826
|
*/
|
|
4718
|
-
private
|
|
4827
|
+
private createComparator;
|
|
4719
4828
|
/**
|
|
4720
|
-
*
|
|
4721
|
-
*
|
|
4829
|
+
* Check if a map should be indexed based on configuration.
|
|
4830
|
+
*
|
|
4831
|
+
* @param mapName - Name of the map
|
|
4832
|
+
* @returns true if map has index configuration
|
|
4722
4833
|
*/
|
|
4723
|
-
|
|
4834
|
+
hasIndexConfig(mapName: string): boolean;
|
|
4724
4835
|
/**
|
|
4725
|
-
*
|
|
4726
|
-
* Computes updates for each subscription and sends as a batch.
|
|
4836
|
+
* Get index configuration for a map.
|
|
4727
4837
|
*
|
|
4728
4838
|
* @param mapName - Name of the map
|
|
4729
|
-
* @
|
|
4839
|
+
* @returns Map index config or undefined
|
|
4730
4840
|
*/
|
|
4731
|
-
|
|
4841
|
+
getMapConfig(mapName: string): MapIndexConfig | undefined;
|
|
4732
4842
|
/**
|
|
4733
|
-
*
|
|
4734
|
-
* Returns null if no update is needed.
|
|
4843
|
+
* Get all configured map names.
|
|
4735
4844
|
*
|
|
4736
|
-
* @
|
|
4737
|
-
* @param key - Document key
|
|
4738
|
-
* @param value - Document value (null if removed)
|
|
4739
|
-
* @param changeType - Type of change
|
|
4740
|
-
* @param index - The FullTextIndex for this map
|
|
4741
|
-
* @returns BatchedUpdate or null
|
|
4845
|
+
* @returns Array of map names with index configuration
|
|
4742
4846
|
*/
|
|
4743
|
-
|
|
4847
|
+
getConfiguredMaps(): string[];
|
|
4848
|
+
/**
|
|
4849
|
+
* Get the full server index configuration.
|
|
4850
|
+
*/
|
|
4851
|
+
getConfig(): ServerIndexConfig;
|
|
4744
4852
|
}
|
|
4745
4853
|
|
|
4746
4854
|
export { BufferPool, type BufferPoolConfig, type BufferPoolStats, type ClusterConfig, ClusterCoordinator, type ClusterCoordinatorConfig, type ClusterCoordinatorEvents, ClusterManager, type ClusterMember, type ClusterMessage, type CoalescingPreset, type CoalescingWriterMetrics, type CoalescingWriterOptions, ConflictResolverHandler, type ConflictResolverHandlerConfig, ConflictResolverService, type ConflictResolverServiceConfig, type ConnectionContext, ConnectionRateLimiter, DEFAULT_CLUSTER_COORDINATOR_CONFIG, DEFAULT_CONFLICT_RESOLVER_CONFIG, DEFAULT_FAILURE_DETECTOR_CONFIG, DEFAULT_INDEX_CONFIG, DEFAULT_JOURNAL_SERVICE_CONFIG, DEFAULT_LAG_TRACKER_CONFIG, DEFAULT_MERKLE_TREE_CONFIG, DEFAULT_READ_REPLICA_CONFIG, DEFAULT_REASSIGNER_CONFIG, DEFAULT_REPAIR_CONFIG, DEFAULT_SANDBOX_CONFIG, EntryProcessorHandler, type EntryProcessorHandlerConfig, EventJournalService, type EventJournalServiceConfig, type ExportOptions, type FailoverStatus, FailureDetector, type FailureDetectorConfig, type FailureDetectorEvents, FilterTasklet, ForEachTasklet, type IInterceptor, type IServerStorage, type IndexDefinition, IteratorTasklet, type IteratorTaskletConfig, type LagInfo, LagTracker, type LagTrackerConfig, LockManager, type Logger, MapFactory, type MapIndexConfig, MapTasklet, MapWithResolver, type MapWithResolverConfig, MemoryServerAdapter, type MergeWithResolverResult, type MerkleComparisonResult, MerkleTreeManager, type MerkleTreeManagerConfig, MigrationManager, type NativeModuleStatus, type NativeStats, type NodeState, type ORMapTombstones, type ORMapValue, ObjectPool, type ObjectPoolConfig, type ObjectPoolStats, type OpContext, type PartitionDistribution, type PartitionMerkleInfo, PartitionReassigner, type PartitionReassignerConfig, PartitionService, type PartitionServiceConfig, type PartitionServiceEvents, type PooledEventPayload, type PooledMessage, type PooledRecord, type PooledTimestamp, PostgresAdapter, type PostgresAdapterOptions, ProcessorSandbox, type ProcessorSandboxConfig, type ProgressState, RateLimitInterceptor, type RateLimiterConfig, type RateLimiterStats, type ReadReplicaConfig, ReadReplicaHandler, type ReadRequest, type ReadResult, type ReassignmentEvent, ReduceTasklet, type RepairConfig, type RepairMetrics, type RepairResult, RepairScheduler, type RepairTask, ReplicationPipeline, type SearchConfig, SearchCoordinator, SecurityManager, ServerCoordinator, type ServerCoordinatorConfig, type ServerIndexConfig, type ServerOp, type ServerSearchResult, type SetWithResolverResult, type StorageValue, type Tasklet, TaskletScheduler, type TaskletSchedulerConfig, type TaskletSchedulerStats, TimestampInterceptor, coalescingPresets, createEventPayloadPool, createMessagePool, createRecordPool, createTimestampPool, getCoalescingPreset, getGlobalBufferPool, getGlobalEventPayloadPool, getGlobalMessagePool, getGlobalRecordPool, getGlobalTimestampPool, getNativeModuleStatus, getNativeStats, logNativeStatus, logger, mergeWithDefaults, setGlobalBufferPool, setGlobalEventPayloadPool, setGlobalMessagePool, setGlobalRecordPool, setGlobalTimestampPool, validateIndexConfig };
|