1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.buffer;
18
19 import io.netty.util.internal.LongCounter;
20 import io.netty.util.internal.PlatformDependent;
21 import io.netty.util.internal.StringUtil;
22
23 import java.nio.ByteBuffer;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.concurrent.atomic.AtomicInteger;
28 import java.util.concurrent.atomic.AtomicReference;
29 import java.util.concurrent.atomic.LongAdder;
30 import java.util.concurrent.locks.ReentrantLock;
31
32 import static io.netty.buffer.PoolChunk.isSubpage;
33 import static java.lang.Math.max;
34
35 abstract class PoolArena<T> implements PoolArenaMetric {
36 private static final boolean HAS_UNSAFE = PlatformDependent.hasUnsafe();
37
38 enum SizeClass {
39 Small,
40 Normal
41 }
42
43 final PooledByteBufAllocator parent;
44
45 final PoolSubpage<T>[] smallSubpagePools;
46
47 private final PoolChunkList<T> q050;
48 private final PoolChunkList<T> q025;
49 private final PoolChunkList<T> q000;
50 private final PoolChunkList<T> qInit;
51 private final PoolChunkList<T> q075;
52 private final PoolChunkList<T> q100;
53
54 private final List<PoolChunkListMetric> chunkListMetrics;
55
56
57 private long allocationsNormal;
58
59 private final LongAdder allocationsSmall = new LongAdder();
60 private final LongAdder allocationsHuge = new LongAdder();
61 private final LongAdder activeBytesHuge = new LongAdder();
62
63 private long deallocationsSmall;
64 private long deallocationsNormal;
65
66 private long pooledChunkAllocations;
67 private long pooledChunkDeallocations;
68
69
70 private final LongAdder deallocationsHuge = new LongAdder();
71
72
73 final AtomicInteger numThreadCaches = new AtomicInteger();
74
75
76
77
78 private final ReentrantLock lock = new ReentrantLock();
79
80 final SizeClasses sizeClass;
81
82 protected PoolArena(PooledByteBufAllocator parent, SizeClasses sizeClass) {
83 assert null != sizeClass;
84 this.parent = parent;
85 this.sizeClass = sizeClass;
86 smallSubpagePools = newSubpagePoolArray(sizeClass.nSubpages);
87 for (int i = 0; i < smallSubpagePools.length; i ++) {
88 smallSubpagePools[i] = newSubpagePoolHead(i);
89 }
90
91 q100 = new PoolChunkList<T>(this, null, 100, Integer.MAX_VALUE, sizeClass.chunkSize);
92 q075 = new PoolChunkList<T>(this, q100, 75, 100, sizeClass.chunkSize);
93 q050 = new PoolChunkList<T>(this, q100, 50, 100, sizeClass.chunkSize);
94 q025 = new PoolChunkList<T>(this, q050, 25, 75, sizeClass.chunkSize);
95 q000 = new PoolChunkList<T>(this, q025, 1, 50, sizeClass.chunkSize);
96 qInit = new PoolChunkList<T>(this, q000, Integer.MIN_VALUE, 25, sizeClass.chunkSize);
97
98 q100.prevList(q075);
99 q075.prevList(q050);
100 q050.prevList(q025);
101 q025.prevList(q000);
102 q000.prevList(null);
103 qInit.prevList(qInit);
104
105 List<PoolChunkListMetric> metrics = new ArrayList<PoolChunkListMetric>(6);
106 metrics.add(qInit);
107 metrics.add(q000);
108 metrics.add(q025);
109 metrics.add(q050);
110 metrics.add(q075);
111 metrics.add(q100);
112 chunkListMetrics = Collections.unmodifiableList(metrics);
113 }
114
115 private PoolSubpage<T> newSubpagePoolHead(int index) {
116 PoolSubpage<T> head = new PoolSubpage<T>(index);
117 head.prev = head;
118 head.next = head;
119 return head;
120 }
121
122 @SuppressWarnings("unchecked")
123 private PoolSubpage<T>[] newSubpagePoolArray(int size) {
124 return new PoolSubpage[size];
125 }
126
127 abstract boolean isDirect();
128
129 PooledByteBuf<T> allocate(PoolThreadCache cache, int reqCapacity, int maxCapacity) {
130 PooledByteBuf<T> buf = newByteBuf(maxCapacity);
131 allocate(cache, buf, reqCapacity);
132 return buf;
133 }
134
135 private void allocate(PoolThreadCache cache, PooledByteBuf<T> buf, final int reqCapacity) {
136 final int sizeIdx = sizeClass.size2SizeIdx(reqCapacity);
137
138 if (sizeIdx <= sizeClass.smallMaxSizeIdx) {
139 tcacheAllocateSmall(cache, buf, reqCapacity, sizeIdx);
140 } else if (sizeIdx < sizeClass.nSizes) {
141 tcacheAllocateNormal(cache, buf, reqCapacity, sizeIdx);
142 } else {
143 int normCapacity = sizeClass.directMemoryCacheAlignment > 0
144 ? sizeClass.normalizeSize(reqCapacity) : reqCapacity;
145
146 allocateHuge(buf, normCapacity);
147 }
148 }
149
150 private void tcacheAllocateSmall(PoolThreadCache cache, PooledByteBuf<T> buf, final int reqCapacity,
151 final int sizeIdx) {
152
153 if (cache.allocateSmall(this, buf, reqCapacity, sizeIdx)) {
154
155 return;
156 }
157
158
159
160
161
162 final PoolSubpage<T> head = smallSubpagePools[sizeIdx];
163 final boolean needsNormalAllocation;
164 head.lock();
165 try {
166 final PoolSubpage<T> s = head.next;
167 needsNormalAllocation = s == head;
168 if (!needsNormalAllocation) {
169 assert s.doNotDestroy && s.elemSize == sizeClass.sizeIdx2size(sizeIdx) : "doNotDestroy=" +
170 s.doNotDestroy + ", elemSize=" + s.elemSize + ", sizeIdx=" + sizeIdx;
171 long handle = s.allocate();
172 assert handle >= 0;
173 s.chunk.initBufWithSubpage(buf, null, handle, reqCapacity, cache);
174 }
175 } finally {
176 head.unlock();
177 }
178
179 if (needsNormalAllocation) {
180 lock();
181 try {
182 allocateNormal(buf, reqCapacity, sizeIdx, cache);
183 } finally {
184 unlock();
185 }
186 }
187
188 incSmallAllocation();
189 }
190
191 private void tcacheAllocateNormal(PoolThreadCache cache, PooledByteBuf<T> buf, final int reqCapacity,
192 final int sizeIdx) {
193 if (cache.allocateNormal(this, buf, reqCapacity, sizeIdx)) {
194
195 return;
196 }
197 lock();
198 try {
199 allocateNormal(buf, reqCapacity, sizeIdx, cache);
200 ++allocationsNormal;
201 } finally {
202 unlock();
203 }
204 }
205
206 private void allocateNormal(PooledByteBuf<T> buf, int reqCapacity, int sizeIdx, PoolThreadCache threadCache) {
207 assert lock.isHeldByCurrentThread();
208 if (q050.allocate(buf, reqCapacity, sizeIdx, threadCache) ||
209 q025.allocate(buf, reqCapacity, sizeIdx, threadCache) ||
210 q000.allocate(buf, reqCapacity, sizeIdx, threadCache) ||
211 qInit.allocate(buf, reqCapacity, sizeIdx, threadCache) ||
212 q075.allocate(buf, reqCapacity, sizeIdx, threadCache)) {
213 return;
214 }
215
216
217 PoolChunk<T> c = newChunk(sizeClass.pageSize, sizeClass.nPSizes, sizeClass.pageShifts, sizeClass.chunkSize);
218 boolean success = c.allocate(buf, reqCapacity, sizeIdx, threadCache);
219 assert success;
220 qInit.add(c);
221 ++pooledChunkAllocations;
222 }
223
224 private void incSmallAllocation() {
225 allocationsSmall.increment();
226 }
227
228 private void allocateHuge(PooledByteBuf<T> buf, int reqCapacity) {
229 PoolChunk<T> chunk = newUnpooledChunk(reqCapacity);
230 activeBytesHuge.add(chunk.chunkSize());
231 buf.initUnpooled(chunk, reqCapacity);
232 allocationsHuge.increment();
233 }
234
235 void free(PoolChunk<T> chunk, ByteBuffer nioBuffer, long handle, int normCapacity, PoolThreadCache cache) {
236 chunk.decrementPinnedMemory(normCapacity);
237 if (chunk.unpooled) {
238 int size = chunk.chunkSize();
239 destroyChunk(chunk);
240 activeBytesHuge.add(-size);
241 deallocationsHuge.increment();
242 } else {
243 SizeClass sizeClass = sizeClass(handle);
244 if (cache != null && cache.add(this, chunk, nioBuffer, handle, normCapacity, sizeClass)) {
245
246 return;
247 }
248
249 freeChunk(chunk, handle, normCapacity, sizeClass, nioBuffer, false);
250 }
251 }
252
253 private static SizeClass sizeClass(long handle) {
254 return isSubpage(handle) ? SizeClass.Small : SizeClass.Normal;
255 }
256
257 void freeChunk(PoolChunk<T> chunk, long handle, int normCapacity, SizeClass sizeClass, ByteBuffer nioBuffer,
258 boolean finalizer) {
259 final boolean destroyChunk;
260 lock();
261 try {
262
263
264 if (!finalizer) {
265 switch (sizeClass) {
266 case Normal:
267 ++deallocationsNormal;
268 break;
269 case Small:
270 ++deallocationsSmall;
271 break;
272 default:
273 throw new Error();
274 }
275 }
276 destroyChunk = !chunk.parent.free(chunk, handle, normCapacity, nioBuffer);
277 if (destroyChunk) {
278
279 ++pooledChunkDeallocations;
280 }
281 } finally {
282 unlock();
283 }
284 if (destroyChunk) {
285
286 destroyChunk(chunk);
287 }
288 }
289
290 void reallocate(PooledByteBuf<T> buf, int newCapacity) {
291 assert newCapacity >= 0 && newCapacity <= buf.maxCapacity();
292
293 final int oldCapacity;
294 final PoolChunk<T> oldChunk;
295 final ByteBuffer oldNioBuffer;
296 final long oldHandle;
297 final T oldMemory;
298 final int oldOffset;
299 final int oldMaxLength;
300 final PoolThreadCache oldCache;
301
302
303
304
305
306
307
308
309
310
311 synchronized (buf) {
312 oldCapacity = buf.length;
313 if (oldCapacity == newCapacity) {
314 return;
315 }
316
317 oldChunk = buf.chunk;
318 oldNioBuffer = buf.tmpNioBuf;
319 oldHandle = buf.handle;
320 oldMemory = buf.memory;
321 oldOffset = buf.offset;
322 oldMaxLength = buf.maxLength;
323 oldCache = buf.cache;
324
325
326 allocate(parent.threadCache(), buf, newCapacity);
327 }
328 int bytesToCopy;
329 if (newCapacity > oldCapacity) {
330 bytesToCopy = oldCapacity;
331 } else {
332 buf.trimIndicesToCapacity(newCapacity);
333 bytesToCopy = newCapacity;
334 }
335 memoryCopy(oldMemory, oldOffset, buf, bytesToCopy);
336 free(oldChunk, oldNioBuffer, oldHandle, oldMaxLength, oldCache);
337 }
338
339 @Override
340 public int numThreadCaches() {
341 return numThreadCaches.get();
342 }
343
344 @Override
345 public int numTinySubpages() {
346 return 0;
347 }
348
349 @Override
350 public int numSmallSubpages() {
351 return smallSubpagePools.length;
352 }
353
354 @Override
355 public int numChunkLists() {
356 return chunkListMetrics.size();
357 }
358
359 @Override
360 public List<PoolSubpageMetric> tinySubpages() {
361 return Collections.emptyList();
362 }
363
364 @Override
365 public List<PoolSubpageMetric> smallSubpages() {
366 return subPageMetricList(smallSubpagePools);
367 }
368
369 @Override
370 public List<PoolChunkListMetric> chunkLists() {
371 return chunkListMetrics;
372 }
373
374 private static List<PoolSubpageMetric> subPageMetricList(PoolSubpage<?>[] pages) {
375 List<PoolSubpageMetric> metrics = new ArrayList<PoolSubpageMetric>();
376 for (PoolSubpage<?> head : pages) {
377 if (head.next == head) {
378 continue;
379 }
380 PoolSubpage<?> s = head.next;
381 for (;;) {
382 metrics.add(s);
383 s = s.next;
384 if (s == head) {
385 break;
386 }
387 }
388 }
389 return metrics;
390 }
391
392 @Override
393 public long numAllocations() {
394 final long allocsNormal;
395 lock();
396 try {
397 allocsNormal = allocationsNormal;
398 } finally {
399 unlock();
400 }
401 return allocationsSmall.sum() + allocsNormal + allocationsHuge.sum();
402 }
403
404 @Override
405 public long numTinyAllocations() {
406 return 0;
407 }
408
409 @Override
410 public long numSmallAllocations() {
411 return allocationsSmall.sum();
412 }
413
414 @Override
415 public long numNormalAllocations() {
416 lock();
417 try {
418 return allocationsNormal;
419 } finally {
420 unlock();
421 }
422 }
423
424 @Override
425 public long numChunkAllocations() {
426 lock();
427 try {
428 return pooledChunkAllocations;
429 } finally {
430 unlock();
431 }
432 }
433
434 @Override
435 public long numDeallocations() {
436 final long deallocs;
437 lock();
438 try {
439 deallocs = deallocationsSmall + deallocationsNormal;
440 } finally {
441 unlock();
442 }
443 return deallocs + deallocationsHuge.sum();
444 }
445
446 @Override
447 public long numTinyDeallocations() {
448 return 0;
449 }
450
451 @Override
452 public long numSmallDeallocations() {
453 lock();
454 try {
455 return deallocationsSmall;
456 } finally {
457 unlock();
458 }
459 }
460
461 @Override
462 public long numNormalDeallocations() {
463 lock();
464 try {
465 return deallocationsNormal;
466 } finally {
467 unlock();
468 }
469 }
470
471 @Override
472 public long numChunkDeallocations() {
473 lock();
474 try {
475 return pooledChunkDeallocations;
476 } finally {
477 unlock();
478 }
479 }
480
481 @Override
482 public long numHugeAllocations() {
483 return allocationsHuge.sum();
484 }
485
486 @Override
487 public long numHugeDeallocations() {
488 return deallocationsHuge.sum();
489 }
490
491 @Override
492 public long numActiveAllocations() {
493 long val = allocationsSmall.sum() + allocationsHuge.sum()
494 - deallocationsHuge.sum();
495 lock();
496 try {
497 val += allocationsNormal - (deallocationsSmall + deallocationsNormal);
498 } finally {
499 unlock();
500 }
501 return max(val, 0);
502 }
503
504 @Override
505 public long numActiveTinyAllocations() {
506 return 0;
507 }
508
509 @Override
510 public long numActiveSmallAllocations() {
511 return max(numSmallAllocations() - numSmallDeallocations(), 0);
512 }
513
514 @Override
515 public long numActiveNormalAllocations() {
516 final long val;
517 lock();
518 try {
519 val = allocationsNormal - deallocationsNormal;
520 } finally {
521 unlock();
522 }
523 return max(val, 0);
524 }
525
526 @Override
527 public long numActiveChunks() {
528 final long val;
529 lock();
530 try {
531 val = pooledChunkAllocations - pooledChunkDeallocations;
532 } finally {
533 unlock();
534 }
535 return max(val, 0);
536 }
537
538 @Override
539 public long numActiveHugeAllocations() {
540 return max(numHugeAllocations() - numHugeDeallocations(), 0);
541 }
542
543 @Override
544 public long numActiveBytes() {
545 long val = activeBytesHuge.sum();
546 lock();
547 try {
548 for (int i = 0; i < chunkListMetrics.size(); i++) {
549 for (PoolChunkMetric m: chunkListMetrics.get(i)) {
550 val += m.chunkSize();
551 }
552 }
553 } finally {
554 unlock();
555 }
556 return max(0, val);
557 }
558
559
560
561
562
563 public long numPinnedBytes() {
564 long val = activeBytesHuge.sum();
565 for (int i = 0; i < chunkListMetrics.size(); i++) {
566 for (PoolChunkMetric m: chunkListMetrics.get(i)) {
567 val += ((PoolChunk<?>) m).pinnedBytes();
568 }
569 }
570 return max(0, val);
571 }
572
573 protected abstract PoolChunk<T> newChunk(int pageSize, int maxPageIdx, int pageShifts, int chunkSize);
574 protected abstract PoolChunk<T> newUnpooledChunk(int capacity);
575 protected abstract PooledByteBuf<T> newByteBuf(int maxCapacity);
576 protected abstract void memoryCopy(T src, int srcOffset, PooledByteBuf<T> dst, int length);
577 protected abstract void destroyChunk(PoolChunk<T> chunk);
578
579 @Override
580 public String toString() {
581 lock();
582 try {
583 StringBuilder buf = new StringBuilder()
584 .append("Chunk(s) at 0~25%:")
585 .append(StringUtil.NEWLINE)
586 .append(qInit)
587 .append(StringUtil.NEWLINE)
588 .append("Chunk(s) at 0~50%:")
589 .append(StringUtil.NEWLINE)
590 .append(q000)
591 .append(StringUtil.NEWLINE)
592 .append("Chunk(s) at 25~75%:")
593 .append(StringUtil.NEWLINE)
594 .append(q025)
595 .append(StringUtil.NEWLINE)
596 .append("Chunk(s) at 50~100%:")
597 .append(StringUtil.NEWLINE)
598 .append(q050)
599 .append(StringUtil.NEWLINE)
600 .append("Chunk(s) at 75~100%:")
601 .append(StringUtil.NEWLINE)
602 .append(q075)
603 .append(StringUtil.NEWLINE)
604 .append("Chunk(s) at 100%:")
605 .append(StringUtil.NEWLINE)
606 .append(q100)
607 .append(StringUtil.NEWLINE)
608 .append("small subpages:");
609 appendPoolSubPages(buf, smallSubpagePools);
610 buf.append(StringUtil.NEWLINE);
611 return buf.toString();
612 } finally {
613 unlock();
614 }
615 }
616
617 private static void appendPoolSubPages(StringBuilder buf, PoolSubpage<?>[] subpages) {
618 for (int i = 0; i < subpages.length; i ++) {
619 PoolSubpage<?> head = subpages[i];
620 if (head.next == head || head.next == null) {
621 continue;
622 }
623
624 buf.append(StringUtil.NEWLINE)
625 .append(i)
626 .append(": ");
627 PoolSubpage<?> s = head.next;
628 while (s != null) {
629 buf.append(s);
630 s = s.next;
631 if (s == head) {
632 break;
633 }
634 }
635 }
636 }
637
638 @Override
639 protected final void finalize() throws Throwable {
640 try {
641 super.finalize();
642 } finally {
643 destroyPoolSubPages(smallSubpagePools);
644 destroyPoolChunkLists(qInit, q000, q025, q050, q075, q100);
645 }
646 }
647
648 private static void destroyPoolSubPages(PoolSubpage<?>[] pages) {
649 for (PoolSubpage<?> page : pages) {
650 page.destroy();
651 }
652 }
653
654 private void destroyPoolChunkLists(PoolChunkList<T>... chunkLists) {
655 for (PoolChunkList<T> chunkList: chunkLists) {
656 chunkList.destroy(this);
657 }
658 }
659
660 static final class HeapArena extends PoolArena<byte[]> {
661 private final AtomicReference<PoolChunk<byte[]>> lastDestroyedChunk;
662
663 HeapArena(PooledByteBufAllocator parent, SizeClasses sizeClass) {
664 super(parent, sizeClass);
665 lastDestroyedChunk = new AtomicReference<>();
666 }
667
668 private static byte[] newByteArray(int size) {
669 return PlatformDependent.allocateUninitializedArray(size);
670 }
671
672 @Override
673 boolean isDirect() {
674 return false;
675 }
676
677 @Override
678 protected PoolChunk<byte[]> newChunk(int pageSize, int maxPageIdx, int pageShifts, int chunkSize) {
679 PoolChunk<byte[]> chunk = lastDestroyedChunk.getAndSet(null);
680 if (chunk != null) {
681 assert chunk.chunkSize == chunkSize &&
682 chunk.pageSize == pageSize &&
683 chunk.maxPageIdx == maxPageIdx &&
684 chunk.pageShifts == pageShifts;
685 return chunk;
686 }
687 return new PoolChunk<byte[]>(
688 this, null, newByteArray(chunkSize), pageSize, pageShifts, chunkSize, maxPageIdx);
689 }
690
691 @Override
692 protected PoolChunk<byte[]> newUnpooledChunk(int capacity) {
693 return new PoolChunk<byte[]>(this, null, newByteArray(capacity), capacity);
694 }
695
696 @Override
697 protected void destroyChunk(PoolChunk<byte[]> chunk) {
698
699 if (!chunk.unpooled && lastDestroyedChunk.get() == null) {
700 lastDestroyedChunk.set(chunk);
701 }
702 }
703
704 @Override
705 protected PooledByteBuf<byte[]> newByteBuf(int maxCapacity) {
706 return HAS_UNSAFE ? PooledUnsafeHeapByteBuf.newUnsafeInstance(maxCapacity)
707 : PooledHeapByteBuf.newInstance(maxCapacity);
708 }
709
710 @Override
711 protected void memoryCopy(byte[] src, int srcOffset, PooledByteBuf<byte[]> dst, int length) {
712 if (length == 0) {
713 return;
714 }
715
716 System.arraycopy(src, srcOffset, dst.memory, dst.offset, length);
717 }
718 }
719
720 static final class DirectArena extends PoolArena<ByteBuffer> {
721
722 DirectArena(PooledByteBufAllocator parent, SizeClasses sizeClass) {
723 super(parent, sizeClass);
724 }
725
726 @Override
727 boolean isDirect() {
728 return true;
729 }
730
731 @Override
732 protected PoolChunk<ByteBuffer> newChunk(int pageSize, int maxPageIdx, int pageShifts, int chunkSize) {
733 if (sizeClass.directMemoryCacheAlignment == 0) {
734 ByteBuffer memory = allocateDirect(chunkSize);
735 return new PoolChunk<ByteBuffer>(this, memory, memory, pageSize, pageShifts,
736 chunkSize, maxPageIdx);
737 }
738
739 final ByteBuffer base = allocateDirect(chunkSize + sizeClass.directMemoryCacheAlignment);
740 final ByteBuffer memory = PlatformDependent.alignDirectBuffer(base, sizeClass.directMemoryCacheAlignment);
741 return new PoolChunk<ByteBuffer>(this, base, memory, pageSize,
742 pageShifts, chunkSize, maxPageIdx);
743 }
744
745 @Override
746 protected PoolChunk<ByteBuffer> newUnpooledChunk(int capacity) {
747 if (sizeClass.directMemoryCacheAlignment == 0) {
748 ByteBuffer memory = allocateDirect(capacity);
749 return new PoolChunk<ByteBuffer>(this, memory, memory, capacity);
750 }
751
752 final ByteBuffer base = allocateDirect(capacity + sizeClass.directMemoryCacheAlignment);
753 final ByteBuffer memory = PlatformDependent.alignDirectBuffer(base, sizeClass.directMemoryCacheAlignment);
754 return new PoolChunk<ByteBuffer>(this, base, memory, capacity);
755 }
756
757 private static ByteBuffer allocateDirect(int capacity) {
758 return PlatformDependent.useDirectBufferNoCleaner() ?
759 PlatformDependent.allocateDirectNoCleaner(capacity) : ByteBuffer.allocateDirect(capacity);
760 }
761
762 @Override
763 protected void destroyChunk(PoolChunk<ByteBuffer> chunk) {
764 if (PlatformDependent.useDirectBufferNoCleaner()) {
765 PlatformDependent.freeDirectNoCleaner((ByteBuffer) chunk.base);
766 } else {
767 PlatformDependent.freeDirectBuffer((ByteBuffer) chunk.base);
768 }
769 }
770
771 @Override
772 protected PooledByteBuf<ByteBuffer> newByteBuf(int maxCapacity) {
773 if (HAS_UNSAFE) {
774 return PooledUnsafeDirectByteBuf.newInstance(maxCapacity);
775 } else {
776 return PooledDirectByteBuf.newInstance(maxCapacity);
777 }
778 }
779
780 @Override
781 protected void memoryCopy(ByteBuffer src, int srcOffset, PooledByteBuf<ByteBuffer> dstBuf, int length) {
782 if (length == 0) {
783 return;
784 }
785
786 if (HAS_UNSAFE) {
787 PlatformDependent.copyMemory(
788 PlatformDependent.directBufferAddress(src) + srcOffset,
789 PlatformDependent.directBufferAddress(dstBuf.memory) + dstBuf.offset, length);
790 } else {
791
792 src = src.duplicate();
793 ByteBuffer dst = dstBuf.internalNioBuffer();
794 src.position(srcOffset).limit(srcOffset + length);
795 dst.position(dstBuf.offset);
796 dst.put(src);
797 }
798 }
799 }
800
801 void lock() {
802 lock.lock();
803 }
804
805 void unlock() {
806 lock.unlock();
807 }
808
809 @Override
810 public int sizeIdx2size(int sizeIdx) {
811 return sizeClass.sizeIdx2size(sizeIdx);
812 }
813
814 @Override
815 public int sizeIdx2sizeCompute(int sizeIdx) {
816 return sizeClass.sizeIdx2sizeCompute(sizeIdx);
817 }
818
819 @Override
820 public long pageIdx2size(int pageIdx) {
821 return sizeClass.pageIdx2size(pageIdx);
822 }
823
824 @Override
825 public long pageIdx2sizeCompute(int pageIdx) {
826 return sizeClass.pageIdx2sizeCompute(pageIdx);
827 }
828
829 @Override
830 public int size2SizeIdx(int size) {
831 return sizeClass.size2SizeIdx(size);
832 }
833
834 @Override
835 public int pages2pageIdx(int pages) {
836 return sizeClass.pages2pageIdx(pages);
837 }
838
839 @Override
840 public int pages2pageIdxFloor(int pages) {
841 return sizeClass.pages2pageIdxFloor(pages);
842 }
843
844 @Override
845 public int normalizeSize(int size) {
846 return sizeClass.normalizeSize(size);
847 }
848 }