Browse Source

types: TxEventBuffer.Flush now uses capacity preserving slice clearing idiom

Fixes https://github.com/tendermint/tendermint/issues/1189

For every TxEventBuffer.Flush() invoking, we were invoking
a:
  b.events = make([]EventDataTx, 0, b.capacity)
whose intention is to innocently clear the events slice but
maintain the underlying capacity.

However, unfortunately this is memory and garbage collection intensive
which is linear in the number of events added. If an attack had access
to our code somehow, invoking .Flush() in tight loops would be a sure
way to cause huge GC pressure, and say if they added about 1e9
events maliciously, every Flush() would take at least 3.2seconds
which is enough to now control our application.

The new using of the capacity preserving slice clearing idiom
takes a constant time regardless of the number of elements with zero
allocations so we are killing many birds with one stone i.e
  b.events = b.events[:0]

For benchmarking results, please see
https://gist.github.com/odeke-em/532c14ab67d71c9c0b95518a7a526058
for a reference on how things can get out of hand easily.
pull/1191/head
Emmanuel Odeke 7 years ago
parent
commit
15ef57c6d0
No known key found for this signature in database GPG Key ID: 1CA47A292F89DD40
1 changed files with 5 additions and 1 deletions
  1. +5
    -1
      types/event_buffer.go

+ 5
- 1
types/event_buffer.go View File

@ -41,6 +41,10 @@ func (b *TxEventBuffer) Flush() error {
return err
}
}
b.events = make([]EventDataTx, 0, b.capacity)
// Clear out the elements and set the length to 0
// but maintain the underlying slice's capacity.
// See Issue https://github.com/tendermint/tendermint/issues/1189
b.events = b.events[:0]
return nil
}

Loading…
Cancel
Save