@@ -6,7 +6,11 @@ const ltgt = require('ltgt')
66const createRBT = require ( 'functional-red-black-tree' )
77const { Buffer } = require ( 'buffer' )
88
9- const NONE = Symbol ( 'none' )
9+ const rangeOptions = [ 'gt' , 'gte' , 'lt' , 'lte' ]
10+ const kNone = Symbol ( 'none' )
11+ const kKeys = Symbol ( 'keys' )
12+ const kValues = Symbol ( 'values' )
13+ const kIncrement = Symbol ( 'increment' )
1014
1115// TODO (perf): replace ltgt.compare with a simpler, buffer-only comparator
1216function gt ( value ) {
@@ -35,24 +39,26 @@ function MemIterator (db, options) {
3539
3640 this . keyAsBuffer = options . keyAsBuffer !== false
3741 this . valueAsBuffer = options . valueAsBuffer !== false
42+ this [ kKeys ] = options . keys
43+ this [ kValues ] = options . values
3844 this . _reverse = options . reverse
3945 this . _options = options
4046 this . _done = 0
4147
4248 if ( ! this . _reverse ) {
4349 this . _incr = 'next'
44- this . _lowerBound = ltgt . lowerBound ( options , NONE )
45- this . _upperBound = ltgt . upperBound ( options , NONE )
50+ this . _lowerBound = ltgt . lowerBound ( options , kNone )
51+ this . _upperBound = ltgt . upperBound ( options , kNone )
4652
47- if ( this . _lowerBound === NONE ) {
53+ if ( this . _lowerBound === kNone ) {
4854 this . _tree = tree . begin
4955 } else if ( ltgt . lowerBoundInclusive ( options ) ) {
5056 this . _tree = tree . ge ( this . _lowerBound )
5157 } else {
5258 this . _tree = tree . gt ( this . _lowerBound )
5359 }
5460
55- if ( this . _upperBound !== NONE ) {
61+ if ( this . _upperBound !== kNone ) {
5662 if ( ltgt . upperBoundInclusive ( options ) ) {
5763 this . _test = lte
5864 } else {
@@ -61,18 +67,18 @@ function MemIterator (db, options) {
6167 }
6268 } else {
6369 this . _incr = 'prev'
64- this . _lowerBound = ltgt . upperBound ( options , NONE )
65- this . _upperBound = ltgt . lowerBound ( options , NONE )
70+ this . _lowerBound = ltgt . upperBound ( options , kNone )
71+ this . _upperBound = ltgt . lowerBound ( options , kNone )
6672
67- if ( this . _lowerBound === NONE ) {
73+ if ( this . _lowerBound === kNone ) {
6874 this . _tree = tree . end
6975 } else if ( ltgt . upperBoundInclusive ( options ) ) {
7076 this . _tree = tree . le ( this . _lowerBound )
7177 } else {
7278 this . _tree = tree . lt ( this . _lowerBound )
7379 }
7480
75- if ( this . _upperBound !== NONE ) {
81+ if ( this . _upperBound !== kNone ) {
7682 if ( ltgt . lowerBoundInclusive ( options ) ) {
7783 this . _test = gte
7884 } else {
@@ -85,30 +91,23 @@ function MemIterator (db, options) {
8591inherits ( MemIterator , AbstractIterator )
8692
8793MemIterator . prototype . _next = function ( callback ) {
88- let key
89- let value
90-
91- if ( this . _done ++ >= this . _limit ) return this . _nextTick ( callback )
94+ if ( ! this [ kIncrement ] ( ) ) return this . _nextTick ( callback )
9295 if ( ! this . _tree . valid ) return this . _nextTick ( callback )
9396
94- key = this . _tree . key
95- value = this . _tree . value
97+ let key = this . _tree . key
98+ let value = this . _tree . value
9699
97100 if ( ! this . _test ( key ) ) return this . _nextTick ( callback )
98101
99- if ( ! this . keyAsBuffer ) {
100- key = key . toString ( )
101- }
102-
103- if ( ! this . valueAsBuffer ) {
104- value = value . toString ( )
105- }
102+ key = ! this [ kKeys ] ? undefined : this . keyAsBuffer ? key : key . toString ( )
103+ value = ! this [ kValues ] ? undefined : this . valueAsBuffer ? value : value . toString ( )
106104
107105 this . _tree [ this . _incr ] ( )
106+ this . _nextTick ( callback , null , key , value )
107+ }
108108
109- this . _nextTick ( function callNext ( ) {
110- callback ( null , key , value )
111- } )
109+ MemIterator . prototype [ kIncrement ] = function ( ) {
110+ return this . _done ++ < this . _limit
112111}
113112
114113MemIterator . prototype . _test = function ( ) {
@@ -118,7 +117,7 @@ MemIterator.prototype._test = function () {
118117MemIterator . prototype . _outOfRange = function ( target ) {
119118 if ( ! this . _test ( target ) ) {
120119 return true
121- } else if ( this . _lowerBound === NONE ) {
120+ } else if ( this . _lowerBound === kNone ) {
122121 return false
123122 } else if ( ! this . _reverse ) {
124123 if ( ltgt . lowerBoundInclusive ( this . _options ) ) {
@@ -168,9 +167,7 @@ function MemDOWN () {
168167inherits ( MemDOWN , AbstractLevelDOWN )
169168
170169MemDOWN . prototype . _open = function ( options , callback ) {
171- this . _nextTick ( ( ) => {
172- callback ( null , this )
173- } )
170+ this . _nextTick ( callback )
174171}
175172
176173MemDOWN . prototype . _serializeKey = function ( key ) {
@@ -207,9 +204,7 @@ MemDOWN.prototype._get = function (key, options, callback) {
207204 value = value . toString ( )
208205 }
209206
210- this . _nextTick ( function callNext ( ) {
211- callback ( null , value )
212- } )
207+ this . _nextTick ( callback , null , value )
213208}
214209
215210MemDOWN . prototype . _getMany = function ( keys , options , callback ) {
@@ -248,6 +243,39 @@ MemDOWN.prototype._batch = function (array, options, callback) {
248243 this . _nextTick ( callback )
249244}
250245
246+ MemDOWN . prototype . _clear = function ( options , callback ) {
247+ if ( ! hasLimit ( options ) && ! Object . keys ( options ) . some ( isRangeOption ) ) {
248+ // Delete everything by creating a new empty tree.
249+ this . _store = createRBT ( ltgt . compare )
250+ return this . _nextTick ( callback )
251+ }
252+
253+ const iterator = this . _iterator ( {
254+ ...options ,
255+ keys : true ,
256+ values : false ,
257+ keyAsBuffer : true
258+ } )
259+
260+ const loop = ( ) => {
261+ // TODO: add option to control "batch size"
262+ for ( let i = 0 ; i < 500 ; i ++ ) {
263+ if ( ! iterator [ kIncrement ] ( ) ) return callback ( )
264+ if ( ! iterator . _tree . valid ) return callback ( )
265+ if ( ! iterator . _test ( iterator . _tree . key ) ) return callback ( )
266+
267+ // Must also include changes made in parallel to clear()
268+ this . _store = this . _store . remove ( iterator . _tree . key )
269+ iterator . _tree [ iterator . _incr ] ( )
270+ }
271+
272+ // Some time to breathe
273+ this . _nextTick ( loop )
274+ }
275+
276+ this . _nextTick ( loop )
277+ }
278+
251279MemDOWN . prototype . _iterator = function ( options ) {
252280 return new MemIterator ( this , options )
253281}
@@ -269,3 +297,13 @@ if (typeof process !== 'undefined' && !process.browser && typeof global !== 'und
269297 }
270298 }
271299}
300+
301+ function isRangeOption ( k ) {
302+ return rangeOptions . includes ( k )
303+ }
304+
305+ function hasLimit ( options ) {
306+ return options . limit != null &&
307+ options . limit >= 0 &&
308+ options . limit < Infinity
309+ }
0 commit comments