node_cache.coffee | |
---|---|
_ = require( "underscore" ) | |
generate superclass | module.exports = class NodeCache
constructor: ( @options = {} )-> |
container for cached dtaa | @data = {} |
module options | @options = _.extend( |
convert all elements to string | forceString: false |
used standard size for calculating value size | objectValueSize: 80
arrayValueSize: 40 |
standard time to live in seconds. 0 = infinity; | stdTTL: 0 |
time in seconds to check all data and delete expired keys | checkperiod: 600
, @options ) |
statistics container | @stats =
hits: 0
misses: 0
keys: 0
ksize: 0
vsize: 0
|
initalize checking period | @_checkData() |
getget a cached key and change the stats Parameters:
Example: | get: ( keys, cb )=> |
convert a string to an array of one key | if _.isString( keys )
keys = [ keys ]
|
define return | oRet = {}
for key in keys |
get data and incremet stats | if @data[ key ]? and @_check( key, @data[ key ] )
@stats.hits++
oRet[ key ] = @_unwrap( @data[ key ] )
else |
if not found return a error | @stats.misses++ |
return all found keys | cb( null, oRet )
return
|
setset a cached key and change the stats Parameters:
Example: | set: ( key, value, ttl, cb=-> )=> |
internal helper variables | existend = false
|
force the data to string | if @options.forceString and not _.isString( value )
value = JSON.stringify( value ) |
remap the arguments if | if arguments.length is 3 and _.isFunction( ttl )
cb = ttl
ttl = @options.stdTTL
|
remove existing data from stats | if @data[ key ]
existend = true
@stats.vsize -= @_getValLength( @_unwrap( @data[ key ] ) )
|
set the value | @data[ key ] = @_wrap( value, ttl )
@stats.vsize += @_getValLength( value ) |
only add the keys and key-size if the key is new | if not existend
@stats.ksize += @_getKeyLength( key )
@stats.keys++
|
return true | cb( null, true )
return
|
delremove a key Parameters:
Return ( Number ): Number of deleted keys Example: | del: ( keys, cb=-> )=> |
convert a string to an array of one key | if _.isString( keys )
keys = [ keys ]
delCount = 0
for key in keys |
only delete if existend | if @data[ key ]? |
calc the stats | @stats.vsize -= @_getValLength( @_unwrap( @data[ key ] ) )
@stats.ksize -= @_getKeyLength( key )
@stats.keys--
delCount++ |
delete the value | delete @data[ key ] |
return true | else |
if the key has not been found return an error | @stats.misses++
cb( null, delCount )
return
|
getStatsget the stats Parameters: - Return ( Object ): Stats data Example: | getStats: =>
@stats
|
flushAllflush the hole data and reset the stats Example: | flushAll: ( _startPeriod = true )=> |
parameter just for testing | |
set data empty | @data = {} |
reset stats | @stats =
hits: 0
misses: 0
keys: 0
ksize: 0
vsize: 0
|
reset check period | @_killCheckPeriod()
@_checkData( _startPeriod )
return
|
_checkDatainternal Housekeeping mehtod. Check all the cached data and delete the invalid values | _checkData: ( startPeriod = true )=> |
run the housekeeping method | for key, value of @data
@_check( key, value )
if startPeriod
@checkTimeout = setTimeout( @_checkData, ( @options.checkperiod * 1000 ) )
return
|
_killCheckPeriodstop the checkdata period. Only needed to abort the script in testing mode. | _killCheckPeriod: ->
clearTimeout( @checkTimeout ) if @checkTimeout?
|
_checkinternal method the check the value. If it's not valid any moe delete it | _check: ( key, data )=>
now = new Date().getTime() |
data is invalid if the ttl is to old and is not 0 | if data.t < now and data.t isnt 0
@del( key )
false
else
true
|
_wrapinternal method to wrap a value in an object with some metadata | _wrap: ( value, ttl )=> |
define the time to live | now = new Date().getTime()
livetime = 0
ttlMultiplicator = 1000 |
use given ttl | if ttl is 0
livetime = 0
else if ttl
livetime = now + ( ttl * ttlMultiplicator )
else |
use standard ttl | if @options.stdTTL is 0
livetime = @options.stdTTL
else
livetime = now + ( @options.stdTTL * ttlMultiplicator ) |
return teh wrapped value | oReturn =
t: livetime
v: value
|
_unwrapinternal method to extract get the value out of the wrapped value | _unwrap: ( value )=>
value.v or null
|
_getKeyLengthinternal method the calculate the key length | _getKeyLength: ( key )=>
key.length
|
_getValLengthinternal method to calculate the value length | _getValLength: ( value )=>
if _.isString( value ) |
if the value is a String get the real length | value.length
else if @options.forceString |
force string if it's defined and not passed | JSON.stringify( value ).length
else if _.isArray( value ) |
if the data is an Array multiply each element with a defined default length | @options.arrayValueSize * value.length
else |
if the data is an Object multiply each element with a defined default length | @options.objectValueSize * _.size( value )
|
_errorinternal method to handle an error message | _error: ( type, data = {}, cb )=> |
generate the error object | error =
errorcode: type
msg: "-"
data: data
if cb and _.isFunction( cb ) |
return the error | cb( error, null )
return
else |
if no callbach is defined return the error object | error
|