Code coverage report for lib\common\streams\chunkallocator.js

Statements: 65% (26 / 40)      Branches: 45% (9 / 20)      Functions: 60% (3 / 5)      Lines: 66.67% (26 / 39)      Ignored: none     

All files » lib/common/streams/ » chunkallocator.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121                                        1   46 46     46     46     46             1                             1                                           1 46     46     46     46 46 46 46             1 43   42 42       1 1           1     1 1       1  
// 
// Copyright (c) Microsoft and contributors.  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.
// 
/**
* Chunked memory pool allocator.
* It could dramatically reduce the memory usage.
* However, it can't dramatically reduce the CPU time since GC in v8 is very efficient.
*/
function ChunkAllocator(chunkSize, maxCount) {
  // Track the unused buffers and number of used buffers
  this._pool = [];
  this._inuse = 0;
 
  // Buffer size
  this._chunkSize = chunkSize;
 
  // If total memory is larger than this._chunkSize * this._maxCount, the buffer pool is not used.
  this._maxCount = maxCount || 10;
 
  // Immediately add a buffer to the pool.
  this._extendMemoryPool();
}
 
/**
* Synchronously require a buffer
* Caller should be aware of that the content of buffer is random since the Buffer.fill is Time-consumed opreation.
*/
ChunkAllocator.prototype.getBuffer = function(size) {
  var buffer = this._getBufferFromPool(size);
  if (buffer === null) {
    // Either the total memory is larger than this._chunkSize * this._maxCount
    // Or, the size does not match the chunk size of the pool
    buffer = new Buffer(size);
  }
 
  this._inuse++;
  return buffer;
};
 
/**
* Get buffer from the current memory pool.
*/
ChunkAllocator.prototype._getBufferFromPool = function(size) {
  // Return null if the given size does not match the chunk size of the buffer pool.
  if(size !== this._chunkSize) {
    return null;
  } 
 
  // Extend the memory pool if it is empty.
  if(this._pool.length === 0) {
    this._extendMemoryPool();
  }
 
  // If the pool is not empty, return a buffer.
  if(this._pool.length !== 0) {
    return this._pool.pop();
  } else {
    return null;
  }
};
 
/**
* Extend the memory pool if the maximum size has not been reached.
*/
ChunkAllocator.prototype._extendMemoryPool = function() {
  var total = this._pool.length + this._inuse;
 
  // If the total is larger than the max, do not allocate more memory.
  Iif(total >= this._maxCount) return;
 
  // Calculate the new number of buffers, equal to the total*2 bounded by 1 and the maxCount
  var nextSize = Math.min(total * 2, this._maxCount) || 1;
 
  // Add more buffers.
  var increment = nextSize - total;
  for(var i = 0; i < increment; i++) {
    var buffer = new Buffer(this._chunkSize);
    this._pool.push(buffer);
  }
};
 
/**
* Release the buffer.
*/
ChunkAllocator.prototype.releaseBuffer = function(buffer) {
  if(buffer.length !== this._chunkSize) {
    // Directly delete the buffer if bufferSize is invalid and wait for GC.
    buffer = null;
    return;
  }
 
  // Add the buffer to the pool if it is not full, otherwise delete it
  Eif (this._pool.length < this._maxCount) {
    this._pool.push(buffer);
  } else {
    buffer = null;
  }
 
  // Decrement _inuse 
  this._inuse--;
 
  // _inuse could be below zero if a buffer is released which was not returned by getBuffer
  Eif(this._inuse < 0) {
    this._inuse = 0;
  }
};
 
module.exports = ChunkAllocator;