@Override public synchronized long getMaximumAvailableSpace() { if (_head == null) { // closed return -1L; } // First: how much room do we have in the current write segment? long space = _head.availableForAppend(); // and how many more segments could we allocate? int canAllocate = (_maxSegmentsToAllocate - _usedSegmentsCount); if (canAllocate > 0) { space += (long) canAllocate * (long) _segmentSize; } return space; }
S next = old.finishReading(); --_usedSegmentsCount; _tail = next.initForReading(); _freeSegmentCount = 1; } else { _firstFreeSegment = old.relink(_firstFreeSegment); ++_freeSegmentCount; old.markFree(); _segmentAllocator.releaseSegment(old);
protected MemBufferBase(SegmentAllocator<S> allocator, int minSegmentsToAllocate, int maxSegmentsToAllocate, S initialSegments) { _segmentAllocator = allocator; _segmentSize = allocator.getSegmentSize(); _maxSegmentsForReuse = minSegmentsToAllocate; _maxSegmentsToAllocate = maxSegmentsToAllocate; // all but one of segments goes to the free list _firstFreeSegment = initialSegments.getNext(); // and first one is used as both head and tail initialSegments.relink(null); _head = _tail = initialSegments; // also, better initialize initial segment for writing and reading _head.initForWriting(); _head.initForReading(); _usedSegmentsCount = 1; // Sanity checks? if yes, uncomment this... /* int count = count(_firstFreeSegment); if (count != _freeSegmentCount) { throw new IllegalStateException("Bad initial _freeSegmentCount ("+_freeSegmentCount+"): but only got "+count+" linked"); } */ _freeSegmentCount = minSegmentsToAllocate-1; }
@Override // from Closeable -- note, does NOT throw IOException public synchronized final void close() { // first do regular cleanup clear(); // then free the head/tail node as well _usedSegmentsCount = 0; // 24-Apr-2013, tatu: As per #16, must ensure proper cleaning if (_head != null) { _head.markFree(); _segmentAllocator.releaseSegment(_head); _head = _tail = null; } // and any locally recycled buffers as well S seg = _firstFreeSegment; _firstFreeSegment = null; _freeSegmentCount = 0; while (seg != null) { S next = seg.getNext(); _segmentAllocator.releaseSegment(seg); seg = next; } // one more thing: wake up thread(s) that are blocked (if any) this.notifyAll(); }
/** * Method called by {@link MemBuffer} instances when they have consumed * contents of a segment and do not want to hold on to it for local * reuse. */ @Override public synchronized void releaseSegment(S segToRelease) { if (--_bufferOwnedSegmentCount < 0) { // sanity check; not needed in perfect world int count = _bufferOwnedSegmentCount; _bufferOwnedSegmentCount = 0; // "fix" throw new IllegalStateException("Bugger! Corruption Maximus: _bufferOwnedSegmentCount went below 0 (" +count+")"); } // Can we reuse it? if (_reusableSegmentCount < _maxReusableSegments) { _firstReusableSegment = segToRelease.relink(_firstReusableSegment); ++_reusableSegmentCount; } }
/** * Helper method for reusing a segment from free-segments list. * Caller must guarantee there is such a segment available; this is * done in advance to achieve atomicity of multi-segment-allocation. */ protected final S _reuseFree() { S freeSeg = _firstFreeSegment; if (freeSeg == null) { // sanity check throw new IllegalStateException("Internal error: no free segments available"); } //int oldCount = count(_firstFreeSegment); _firstFreeSegment = freeSeg.getNext(); --_freeSegmentCount; _head = freeSeg; ++_usedSegmentsCount; // optional sanity check, if we are tracking hard-to-find bugs... /* int count = count(_firstFreeSegment); System.err.print("[r="+oldCount+"->"+_freeSegmentCount+"(c="+count+")/u="+_usedSegmentsCount+"]"); if (count != _freeSegmentCount) { System.err.println("ERROR: free seg "+_freeSegmentCount+"; but saw "+count+" actual!"); } */ return freeSeg; }
@Override public synchronized final int skip(int skipCount) { if (_head == null) { _reportClosed(); } if (skipCount > _totalPayloadLength) { skipCount = (int) _totalPayloadLength; } int remaining = skipCount; String error = null; if (remaining > 0) { while (true) { int count = _tail.skip(remaining); remaining -= count; _totalPayloadLength -= count; if (remaining == 0) { // all skipped? break; } error = _freeReadSegment(error); } } if (error != null) { throw new IllegalStateException(error); } return skipCount; }
/** * Method intended to be called from "clear()", after sub-class has done * its own cleanup. Not marked as synchronized as sub-class is expected * to do that if necessary. */ protected void _clear() { if (_head == null) { // closed; nothing to do return; } // first: reset various counters (since this can't fail) _totalPayloadLength = 0L; _clearPeeked(); // then free all segments except for head: note, may get an internal error: String error = null; while (_tail != _head) { error = _freeReadSegment(error); } // then re-init head/tail _tail.clear(); // and finally, indicate error, if any if (error != null) { // sanity check after everything else throw new IllegalStateException(error); } }
@Override // from Closeable -- note, does NOT throw IOException public synchronized final void close() { // first do regular cleanup clear(); // then free the head/tail node as well _usedSegmentsCount = 0; // 24-Apr-2013, tatu: As per #16, must ensure proper cleaning if (_head != null) { _head.markFree(); _segmentAllocator.releaseSegment(_head); _head = _tail = null; } // and any locally recycled buffers as well S seg = _firstFreeSegment; _firstFreeSegment = null; _freeSegmentCount = 0; while (seg != null) { S next = seg.getNext(); _segmentAllocator.releaseSegment(seg); seg = next; } // one more thing: wake up thread(s) that are blocked (if any) this.notifyAll(); }
/** * Method called by {@link MemBuffer} instances when they have consumed * contents of a segment and do not want to hold on to it for local * reuse. */ @Override public synchronized void releaseSegment(S segToRelease) { if (--_bufferOwnedSegmentCount < 0) { // sanity check; not needed in perfect world int count = _bufferOwnedSegmentCount; _bufferOwnedSegmentCount = 0; // "fix" throw new IllegalStateException("Bugger! Corruption Maximus: _bufferOwnedSegmentCount went below 0 (" +count+")"); } // Can we reuse it? if (_reusableSegmentCount < _maxReusableSegments) { _firstReusableSegment = segToRelease.relink(_firstReusableSegment); ++_reusableSegmentCount; } }
/** * Helper method for reusing a segment from free-segments list. * Caller must guarantee there is such a segment available; this is * done in advance to achieve atomicity of multi-segment-allocation. */ protected final S _reuseFree() { S freeSeg = _firstFreeSegment; if (freeSeg == null) { // sanity check throw new IllegalStateException("Internal error: no free segments available"); } //int oldCount = count(_firstFreeSegment); _firstFreeSegment = freeSeg.getNext(); --_freeSegmentCount; _head = freeSeg; ++_usedSegmentsCount; // optional sanity check, if we are tracking hard-to-find bugs... /* int count = count(_firstFreeSegment); System.err.print("[r="+oldCount+"->"+_freeSegmentCount+"(c="+count+")/u="+_usedSegmentsCount+"]"); if (count != _freeSegmentCount) { System.err.println("ERROR: free seg "+_freeSegmentCount+"; but saw "+count+" actual!"); } */ return freeSeg; }
@Override public synchronized final int skip(int skipCount) { if (_head == null) { _reportClosed(); } if (skipCount > _totalPayloadLength) { skipCount = (int) _totalPayloadLength; } int remaining = skipCount; String error = null; if (remaining > 0) { while (true) { int count = _tail.skip(remaining); remaining -= count; _totalPayloadLength -= count; if (remaining == 0) { // all skipped? break; } error = _freeReadSegment(error); } } if (error != null) { throw new IllegalStateException(error); } return skipCount; }
/** * Method intended to be called from "clear()", after sub-class has done * its own cleanup. Not marked as synchronized as sub-class is expected * to do that if necessary. */ protected void _clear() { if (_head == null) { // closed; nothing to do return; } // first: reset various counters (since this can't fail) _totalPayloadLength = 0L; _clearPeeked(); // then free all segments except for head: note, may get an internal error: String error = null; while (_tail != _head) { error = _freeReadSegment(error); } // then re-init head/tail _tail.clear(); // and finally, indicate error, if any if (error != null) { // sanity check after everything else throw new IllegalStateException(error); } }
protected MemBufferBase(SegmentAllocator<S> allocator, int minSegmentsToAllocate, int maxSegmentsToAllocate, S initialSegments) { _segmentAllocator = allocator; _segmentSize = allocator.getSegmentSize(); _maxSegmentsForReuse = minSegmentsToAllocate; _maxSegmentsToAllocate = maxSegmentsToAllocate; // all but one of segments goes to the free list _firstFreeSegment = initialSegments.getNext(); // and first one is used as both head and tail initialSegments.relink(null); _head = _tail = initialSegments; // also, better initialize initial segment for writing and reading _head.initForWriting(); _head.initForReading(); _usedSegmentsCount = 1; // Sanity checks? if yes, uncomment this... /* int count = count(_firstFreeSegment); if (count != _freeSegmentCount) { throw new IllegalStateException("Bad initial _freeSegmentCount ("+_freeSegmentCount+"): but only got "+count+" linked"); } */ _freeSegmentCount = minSegmentsToAllocate-1; }
S next = old.finishReading(); --_usedSegmentsCount; _tail = next.initForReading(); _freeSegmentCount = 1; } else { _firstFreeSegment = old.relink(_firstFreeSegment); ++_freeSegmentCount; old.markFree(); _segmentAllocator.releaseSegment(old);
/** * Method that will try to allocate specified number of segments * (and exactly that number; no less). * If this can be done, segments are allocated and prepended into * given segment list; otherwise nothing is allocated and * null is returned. * * @param count Number of segments to allocate * * @return Head of segment list (with newly allocated entries as first * entries) if allocation succeeded; null if not */ @Override public synchronized S allocateSegments(int count, S segmentList) { if (count < 1) { throw new IllegalArgumentException("Must allocate at least one segment (count = "+count+")"); } if (!_canAllocate(count)) { return null; } for (int i = 0; i < count; ++i) { segmentList = _allocateSegment().relink(segmentList); } return segmentList; }
@Override public synchronized long getMaximumAvailableSpace() { if (_head == null) { // closed return -1L; } // First: how much room do we have in the current write segment? long space = _head.availableForAppend(); // and how many more segments could we allocate? int canAllocate = (_maxSegmentsToAllocate - _usedSegmentsCount); if (canAllocate > 0) { space += (long) canAllocate * (long) _segmentSize; } return space; }
/** * Method that will try to allocate specified number of segments * (and exactly that number; no less). * If this can be done, segments are allocated and prepended into * given segment list; otherwise nothing is allocated and * null is returned. * * @param count Number of segments to allocate * * @return Head of segment list (with newly allocated entries as first * entries) if allocation succeeded; null if not */ @Override public synchronized S allocateSegments(int count, S segmentList) { if (count < 1) { throw new IllegalArgumentException("Must allocate at least one segment (count = "+count+")"); } if (!_canAllocate(count)) { return null; } for (int i = 0; i < count; ++i) { segmentList = _allocateSegment().relink(segmentList); } return segmentList; }