ListNode.coffee | |
---|---|
EventEmitter = (require 'events').EventEmitter
Addr64 = (require '../log/Addr64.coffee').Addr64
DataIterator = (require '../log/DataIterator.coffee').DataIterator
LoggableToWrite = (require '../log/LoggableToWrite.coffee').LoggableToWrite
LightOutputStream =
(require '../database/impl/iterate/LightOutputStream.coffee').
LightOutputStream
RandomAccessLoggable =
(require '../log/RandomAccessLoggable.coffee').RandomAccessLoggable
CompressedUnsignedLongByteIterable =
(require '../log/iterate/CompressedUnsignedLongByteIterable.coffee').
CompressedUnsignedLongByteIterable
Log = (require '../log/Log.coffee').Log
LogUtil = (require '../log/LogUtil.coffee').LogUtil
ArrayByteIterable =
(require '../database/impl/iterate/ArrayByteIterable.coffee').
ArrayByteIterable
FixedLengthByteIterable =
(require '../log/iterate/FixedLengthByteIterable.coffee').
FixedLengthByteIterable | |
This class provides logical node of List. In fact value and virtual addresses are be stored separately. | class ListNode extends EventEmitter
@NODE_TYPE: 3
@KEY_TYPE: 5
@VALUE_TYPE: 7 |
@private | maxInt32: undefined |
@private | nullAddr: undefined |
@private | log: undefined |
@private | keyAddr: undefined |
@private | valueAddr: undefined |
@private | nextAddr: undefined |
@private | ownAddr: undefined |
@private | key: undefined |
@private | keyLength: undefined |
@private | value: undefined |
@private | valueLength: undefined |
@private | next: undefined |
@private | structureId: undefined |
@private | prev: undefined |
@private | addrsAreInMemory: undefined |
Constructor. @param log. | @create$Log: (log, o) ->
if !o? then o = new ListNode
o.maxInt32 = (Math.pow 2, 32) - 1
o.nullAddr = Addr64.create$int$int o.maxInt32, o.maxInt32
o.log = log
o.keyAddr = o.nullAddr
o.valueAddr = o.nullAddr
o.nextAddr = o.nullAddr
o.ownAddr = o.nullAddr
o.setMaxListeners 0
o.addrsAreInMemory = true
return o |
Constructor. @param log. @param key. @param value. @param next can be undefined. | @create$Log$ByteIterable$ByteIterable$int$ListNode: (log, key, value, structureId, next, o) ->
if !o? then o = new ListNode
o = ListNode.create$Log log, o
o.key = key
o.keyLength = key.getLength()
o.value = value
o.valueLength = value.getLength()
o.structureId = structureId
o.next = next
o.prev = undefined
o.addrsAreInMemory = false
return o |
Check whether node is uploaded. @return true if node is defined and it's key and value are defined or do not exist. | nodeIsUploaded: () ->
return !@addrsAreInMemory &&
(@next? || @nextAddr.equals$Addr64 @nullAddr) &&
(@key? || @keyAddr.equals$Addr64 @nullAddr) &&
(@value? || @valueAddr.equals$Addr64 @nullAddr) |
Wrap the node into LogGable object. @return loggable. | toLoggable: () ->
length =
(CompressedUnsignedLongByteIterable.getCompressedSize$int @nextAddr.left) +
(CompressedUnsignedLongByteIterable.getCompressedSize$int @nextAddr.right) +
(CompressedUnsignedLongByteIterable.getCompressedSize$int @keyAddr.left) +
(CompressedUnsignedLongByteIterable.getCompressedSize$int @keyAddr.right) +
(CompressedUnsignedLongByteIterable.getCompressedSize$int @valueAddr.left) +
(CompressedUnsignedLongByteIterable.getCompressedSize$int @valueAddr.right)
stream = LightOutputStream.create$int length
CompressedUnsignedLongByteIterable.
fillBytes$int$LightOutputStream @nextAddr.left, stream
CompressedUnsignedLongByteIterable.
fillBytes$int$LightOutputStream @nextAddr.right, stream
CompressedUnsignedLongByteIterable.
fillBytes$int$LightOutputStream @keyAddr.left, stream
CompressedUnsignedLongByteIterable.
fillBytes$int$LightOutputStream @keyAddr.right, stream
CompressedUnsignedLongByteIterable.
fillBytes$int$LightOutputStream @valueAddr.left, stream
CompressedUnsignedLongByteIterable.
fillBytes$int$LightOutputStream @valueAddr.right, stream
loggable = LoggableToWrite.create$int$ByteIterable$int ListNode.NODE_TYPE,
stream.asArrayByteIterable(), @structureId
return loggable |
Wrap the key that is stored in the node into Logable object. @return loggable. | keyToLoggable: () ->
return LoggableToWrite.create$int$ByteIterable$int ListNode.KEY_TYPE, @key,
@structureId |
Wrap the value that is stored in the node into Logable object. @return loggable. | valueToLoggable: () ->
return LoggableToWrite.create$int$ByteIterable$int ListNode.VALUE_TYPE,
@value, @structureId |
Save to Log this node and all the nodes before him (in reversed order) if it is necessary. This function doesn't commit data to Log. @return address of this node in log. | flush$emit: () ->
if @next? && @nextAddr.equals$Addr64 @nullAddr
@nextAddr = @next.flush$emit()
if @key? && @keyAddr.equals$Addr64 @nullAddr
@keyAddr = @log.write$Loggable @keyToLoggable()
if @value? && @valueAddr.equals$Addr64 @nullAddr
@valueAddr = @log.write$Loggable @valueToLoggable()
if @ownAddr.equals$Addr64 @nullAddr
@ownAddr = @log.write$Loggable @toLoggable()
return @ownAddr
isEmpty: () ->
return (!@next? && @nextAddr.equals$Addr64 @nullAddr) &&
(!@key? && @keyAddr.equals$Addr64 @nullAddr) &&
(!@value? && @valueAddr.equals$Addr64 @nullAddr) |
Get node itself - all adresses but not key and value. @return always emits 'getSelf' when done. | getSelf: () ->
if @nodeIsUploaded()
@emit 'getSelf'
else
if @ownAddr.equals$Addr64(@nullAddr) ||
@ownAddr.equals$Addr64 Addr64.create$int$int(-1, -1)
@emit 'getSelf'
else
addrStr = Addr64.addr64ToString$Addr64$int @ownAddr, LogUtil.LOG_NAME_BASE
@log.on 'read' + addrStr, (loggable) =>
it = loggable.getData().iterator()
nums = new Object()
n = 0
onRead = (value) =>
n += 1
nums[n] = value
if n == 6
@nextAddr = Addr64.create$int$int nums[1], nums[2]
@keyAddr = Addr64.create$int$int nums[3], nums[4]
@valueAddr = Addr64.create$int$int nums[5], nums[6]
@addrsAreInMemory = false
@emit 'getSelf'
else
value = CompressedUnsignedLongByteIterable.
getInt$ByteIterator$emit it
if value?
onRead value
CompressedUnsignedLongByteIterable.EMITTER.on 'getInt', (value) =>
onRead value
value = CompressedUnsignedLongByteIterable.getInt$ByteIterator$emit it
if value?
onRead value
@log.read$Addr64$emit @ownAddr |
Get node key. @return always emits 'getKey' when done. | getKey: () ->
if @key?
@emit 'getKey', @key
else if @keyAddr.equals$Addr64 @nullAddr
@emit 'getKey', undefined
else
addrStr = Addr64.addr64ToString$Addr64$int @keyAddr, LogUtil.LOG_NAME_BASE
@log.on 'read' + addrStr, (loggable) =>
@key = FixedLengthByteIterable.
create$ByteIterable$int loggable.getData(), loggable.getDataLength()
@emit 'getKey', @key
@log.read$Addr64$emit @keyAddr |
Get node value. @return always emits 'getValue' when done. | getValue: () ->
if @value?
@emit 'getValue', @value
else if @valueAddr.equals$Addr64 @nullAddr
@emit 'getValue', undefined
else
addrStr = Addr64.addr64ToString$Addr64$int @valueAddr, LogUtil.LOG_NAME_BASE
@log.on 'read' + addrStr, (loggable) =>
@value = FixedLengthByteIterable.
create$ByteIterable$int loggable.getData(), loggable.getDataLength()
@emit 'getValue', @value
@log.read$Addr64$emit @valueAddr |
Get next node. @return next. | getNext: () ->
if !@next?
if !@nextAddr.equals$Addr64 @nullAddr
node = ListNode.create$Log @log
node.ownAddr = @nextAddr
return node
else
return undefined
else
return @next |
Get all node data - all addresses, key and value. @return always emits 'getNode' when done. If true, node is got, otherwise node is empty. | getNode: () ->
this.once 'getSelf', () =>
if @isEmpty()
@emit 'getNode', false, this
else
@next = @getNext()
getKey = false
getValue = false
this.once 'getKey', (key) =>
getKey = true
if getKey && getValue
@emit 'getNode', true, this
this.once 'getValue', (value) =>
getValue = true
if getKey && getValue
@emit 'getNode', true, this
if !@keyAddr.equals$Addr64 @nullAddr
@getKey()
else
getKey = true
if !@valueAddr.equals$Addr64 @nullAddr
@getValue()
else
getValue = true
if getKey && getValue
@emit 'getNode', true, this
if @ownAddr?
@getSelf()
else
@emit 'getNode', false, this
exports.ListNode = ListNode
|