UNPKG

hazelcast-client

Version:

Hazelcast - open source In-Memory Data Grid - client for NodeJS

238 lines 9.71 kB
"use strict"; /* * Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); var Config_1 = require("../Config"); var Util_1 = require("../Util"); var DataStoreHashMap_1 = require("../DataStoreHashMap"); var AlwaysFreshStaleReadDetectorImpl = require("./AlwaysFreshStaleReadDetectorImpl"); var DataRecord_1 = require("./DataRecord"); var Long = require("long"); var NearCacheImpl = /** @class */ (function () { function NearCacheImpl(nearCacheConfig, serializationService) { this.staleReadDetector = AlwaysFreshStaleReadDetectorImpl.INSTANCE; this.reservationCounter = Long.ZERO; this.evictedCount = 0; this.expiredCount = 0; this.missCount = 0; this.hitCount = 0; this.serializationService = serializationService; this.name = nearCacheConfig.name; this.invalidateOnChange = nearCacheConfig.invalidateOnChange; this.maxIdleSeconds = nearCacheConfig.maxIdleSeconds; this.inMemoryFormat = nearCacheConfig.inMemoryFormat; this.timeToLiveSeconds = nearCacheConfig.timeToLiveSeconds; this.evictionPolicy = nearCacheConfig.evictionPolicy; this.evictionMaxSize = nearCacheConfig.evictionMaxSize; this.evictionSamplingCount = nearCacheConfig.evictionSamplingCount; this.evictionSamplingPoolSize = nearCacheConfig.evictionSamplingPoolSize; if (this.evictionPolicy === Config_1.EvictionPolicy.LFU) { this.compareFunc = DataRecord_1.DataRecord.lfuComp; } else if (this.evictionPolicy === Config_1.EvictionPolicy.LRU) { this.compareFunc = DataRecord_1.DataRecord.lruComp; } else if (this.evictionPolicy === Config_1.EvictionPolicy.RANDOM) { this.compareFunc = DataRecord_1.DataRecord.randomComp; } else { this.compareFunc = undefined; } this.evictionCandidatePool = []; this.internalStore = new DataStoreHashMap_1.DataKeyedHashMap(); } NearCacheImpl.prototype.nextReservationId = function () { var res = this.reservationCounter; this.reservationCounter = this.reservationCounter.add(1); return res; }; NearCacheImpl.prototype.tryReserveForUpdate = function (key) { var internalRecord = this.internalStore.get(key); var resId = this.nextReservationId(); if (internalRecord === undefined) { this.doEvictionIfRequired(); var dr = new DataRecord_1.DataRecord(key, undefined, undefined, this.timeToLiveSeconds); dr.casStatus(DataRecord_1.DataRecord.READ_PERMITTED, resId); this.internalStore.set(key, dr); return resId; } if (internalRecord.casStatus(DataRecord_1.DataRecord.READ_PERMITTED, resId)) { return resId; } return DataRecord_1.DataRecord.NOT_RESERVED; }; NearCacheImpl.prototype.tryPublishReserved = function (key, value, reservationId) { var internalRecord = this.internalStore.get(key); if (internalRecord && internalRecord.casStatus(reservationId, DataRecord_1.DataRecord.READ_PERMITTED)) { if (this.inMemoryFormat === Config_1.InMemoryFormat.OBJECT) { internalRecord.value = this.serializationService.toObject(value); } else { internalRecord.value = this.serializationService.toData(value); } internalRecord.setCreationTime(); this.initInvalidationMetadata(internalRecord); } else if (internalRecord === undefined) { return undefined; } else { if (this.inMemoryFormat === Config_1.InMemoryFormat.BINARY) { return this.serializationService.toObject(internalRecord.value); } else { return internalRecord.value; } } }; NearCacheImpl.prototype.setStaleReadDetector = function (staleReadDetector) { this.staleReadDetector = staleReadDetector; }; /** * Creates a new {DataRecord} for given key and value. Then, puts the record in near cache. * If the number of records in near cache exceeds {evictionMaxSize}, it removes expired items first. * If there is no expired item, it triggers an invalidation process to create free space. * @param key * @param value */ NearCacheImpl.prototype.put = function (key, value) { this.doEvictionIfRequired(); if (this.inMemoryFormat === Config_1.InMemoryFormat.OBJECT) { value = this.serializationService.toObject(value); } else { value = this.serializationService.toData(value); } var dr = new DataRecord_1.DataRecord(key, value, undefined, this.timeToLiveSeconds); this.initInvalidationMetadata(dr); this.internalStore.set(key, dr); }; NearCacheImpl.prototype.initInvalidationMetadata = function (dr) { if (this.staleReadDetector === AlwaysFreshStaleReadDetectorImpl.INSTANCE) { return; } var partitionId = this.staleReadDetector.getPartitionId(dr.key); var metadataContainer = this.staleReadDetector.getMetadataContainer(partitionId); dr.setInvalidationSequence(metadataContainer.getSequence()); dr.setUuid(metadataContainer.getUuid()); }; /** * * @param key * @returns the value if present in near cache, 'undefined' if not */ NearCacheImpl.prototype.get = function (key) { var dr = this.internalStore.get(key); if (dr === undefined) { this.missCount++; return undefined; } if (this.staleReadDetector.isStaleRead(key, dr)) { this.internalStore.delete(key); this.missCount++; return undefined; } if (dr.isExpired(this.maxIdleSeconds)) { this.expireRecord(key); this.missCount++; return undefined; } dr.setAccessTime(); dr.hitRecord(); this.hitCount++; if (this.inMemoryFormat === Config_1.InMemoryFormat.BINARY) { return this.serializationService.toObject(dr.value); } else { return dr.value; } }; NearCacheImpl.prototype.invalidate = function (key) { this.internalStore.delete(key); }; NearCacheImpl.prototype.clear = function () { this.internalStore.clear(); }; NearCacheImpl.prototype.isEvictionRequired = function () { return this.evictionPolicy !== Config_1.EvictionPolicy.NONE && this.evictionMaxSize <= this.internalStore.size; }; NearCacheImpl.prototype.doEvictionIfRequired = function () { if (!this.isEvictionRequired()) { return; } var internalSize = this.internalStore.size; if (this.recomputeEvictionPool() > 0) { return; } else { this.evictRecord(this.evictionCandidatePool[0].key); this.evictionCandidatePool = this.evictionCandidatePool.slice(1); } }; /** * @returns number of expired elements. */ NearCacheImpl.prototype.recomputeEvictionPool = function () { var arr = Array.from(this.internalStore.values()); Util_1.shuffleArray(arr); var newCandidates = arr.slice(0, this.evictionSamplingCount); var cleanedNewCandidates = newCandidates.filter(this.filterExpiredRecord, this); var expiredCount = newCandidates.length - cleanedNewCandidates.length; if (expiredCount > 0) { return expiredCount; } (_a = this.evictionCandidatePool).push.apply(_a, cleanedNewCandidates); this.evictionCandidatePool.sort(this.compareFunc); this.evictionCandidatePool = this.evictionCandidatePool.slice(0, this.evictionSamplingPoolSize); return 0; var _a; }; NearCacheImpl.prototype.filterExpiredRecord = function (candidate) { if (candidate.isExpired(this.maxIdleSeconds)) { this.expireRecord(candidate.key); return false; } else { return true; } }; NearCacheImpl.prototype.expireRecord = function (key) { if (this.internalStore.delete(key)) { this.expiredCount++; } }; NearCacheImpl.prototype.evictRecord = function (key) { if (this.internalStore.delete(key)) { this.evictedCount++; } }; NearCacheImpl.prototype.isInvalidatedOnChange = function () { return this.invalidateOnChange; }; NearCacheImpl.prototype.getStatistics = function () { var stats = { evictedCount: this.evictedCount, expiredCount: this.expiredCount, missCount: this.missCount, hitCount: this.hitCount, entryCount: this.internalStore.size }; return stats; }; return NearCacheImpl; }()); exports.NearCacheImpl = NearCacheImpl; //# sourceMappingURL=NearCache.js.map