| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You 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. |
| */ |
| package org.apache.geode.internal.offheap; |
| |
| import org.apache.logging.log4j.Logger; |
| |
| import org.apache.geode.internal.offheap.FreeListManager.LongStack; |
| |
| /** |
| * A "stack" of addresses of OffHeapStoredObject instances. The stored objects are not kept in java |
| * object form but instead each one is just an off-heap address. This class is used for each "tiny" |
| * free-list of the FreeListManager. This class is thread safe. |
| */ |
| public class OffHeapStoredObjectAddressStack implements LongStack { |
| // Ok to read without sync but must be synced on write |
| private volatile long topAddr; |
| |
| public OffHeapStoredObjectAddressStack(long addr) { |
| if (addr != 0L) |
| MemoryAllocatorImpl.validateAddress(addr); |
| this.topAddr = addr; |
| } |
| |
| public OffHeapStoredObjectAddressStack() { |
| this.topAddr = 0L; |
| } |
| |
| public boolean isEmpty() { |
| return this.topAddr == 0L; |
| } |
| |
| public void offer(long e) { |
| assert e != 0; |
| MemoryAllocatorImpl.validateAddress(e); |
| synchronized (this) { |
| OffHeapStoredObject.setNext(e, this.topAddr); |
| this.topAddr = e; |
| } |
| } |
| |
| @Override |
| public long poll() { |
| long result; |
| synchronized (this) { |
| result = this.topAddr; |
| if (result != 0L) { |
| this.topAddr = OffHeapStoredObject.getNext(result); |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Returns the address of the "top" item in this stack. |
| */ |
| public long getTopAddress() { |
| return this.topAddr; |
| } |
| |
| /** |
| * Removes all the addresses from this stack and returns the top address. The caller owns all the |
| * addresses after this call. |
| */ |
| public long clear() { |
| long result; |
| synchronized (this) { |
| result = this.topAddr; |
| if (result != 0L) { |
| this.topAddr = 0L; |
| } |
| } |
| return result; |
| } |
| |
| public void logSizes(Logger logger, String msg) { |
| long headAddr = this.topAddr; |
| long addr; |
| boolean concurrentModDetected; |
| do { |
| concurrentModDetected = false; |
| addr = headAddr; |
| while (addr != 0L) { |
| int curSize = OffHeapStoredObject.getSize(addr); |
| addr = OffHeapStoredObject.getNext(addr); |
| testHookDoConcurrentModification(); |
| long curHead = this.topAddr; |
| if (curHead != headAddr) { |
| headAddr = curHead; |
| concurrentModDetected = true; |
| // Someone added or removed from the stack. |
| // So we break out of the inner loop and start |
| // again at the new head. |
| break; |
| } |
| // TODO construct a single log msg |
| // that gets reset when concurrentModDetected. |
| logger.info(msg + curSize); |
| } |
| } while (concurrentModDetected); |
| } |
| |
| public long computeTotalSize() { |
| long result; |
| long headAddr = this.topAddr; |
| long addr; |
| boolean concurrentModDetected; |
| do { |
| concurrentModDetected = false; |
| result = 0; |
| addr = headAddr; |
| while (addr != 0L) { |
| result += OffHeapStoredObject.getSize(addr); |
| addr = OffHeapStoredObject.getNext(addr); |
| testHookDoConcurrentModification(); |
| long curHead = this.topAddr; |
| if (curHead != headAddr) { |
| headAddr = curHead; |
| concurrentModDetected = true; |
| // Someone added or removed from the stack. |
| // So we break out of the inner loop and start |
| // again at the new head. |
| break; |
| } |
| } |
| } while (concurrentModDetected); |
| return result; |
| } |
| |
| /** |
| * This method allows tests to override it and do a concurrent modification to the stack. For |
| * production code it will be a noop. |
| */ |
| protected void testHookDoConcurrentModification() { |
| // nothing needed in production code |
| } |
| } |