package voldemort.server.storage; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicLong; public class ScanPermitWrapper { private final Semaphore scanPermits; private Map<String, AtomicLong> permitOwnersScanProgressMap; private Map<String, AtomicLong> permitOwnersDeleteProgressMap; private final int numPermits; private long totalEntriesScanned; private long totalEntriesDeleted; public ScanPermitWrapper(final int numPermits) { this.numPermits = numPermits; scanPermits = new Semaphore(numPermits); permitOwnersScanProgressMap = Collections.synchronizedMap(new HashMap<String, AtomicLong>()); permitOwnersDeleteProgressMap = Collections.synchronizedMap(new HashMap<String, AtomicLong>()); this.totalEntriesScanned = 0; this.totalEntriesDeleted = 0; } public void acquire(AtomicLong progress, String ownerName) throws InterruptedException { this.scanPermits.acquire(); synchronized(permitOwnersScanProgressMap) { permitOwnersScanProgressMap.put(ownerName, progress); } } private void initializeProgressMaps(AtomicLong scanProgress, AtomicLong deleteProgress, String ownerName) { synchronized(permitOwnersScanProgressMap) { permitOwnersScanProgressMap.put(ownerName, scanProgress); } synchronized(permitOwnersDeleteProgressMap) { permitOwnersDeleteProgressMap.put(ownerName, deleteProgress); } } public void acquire(AtomicLong scanProgress, AtomicLong deleteProgress, String ownerName) throws InterruptedException { this.scanPermits.acquire(); initializeProgressMaps(scanProgress, deleteProgress, ownerName); } public void release(String ownerName) { this.scanPermits.release(); synchronized(permitOwnersScanProgressMap) { AtomicLong scannedCount = permitOwnersScanProgressMap.get(ownerName); if(scannedCount != null) totalEntriesScanned += scannedCount.get(); permitOwnersScanProgressMap.remove(ownerName); } synchronized(permitOwnersDeleteProgressMap) { AtomicLong deletedCount = permitOwnersDeleteProgressMap.get(ownerName); if(deletedCount != null) totalEntriesDeleted += deletedCount.get(); permitOwnersDeleteProgressMap.remove(ownerName); } } public List<String> getPermitOwners() { List<String> ownerList = new ArrayList<String>(); synchronized(permitOwnersScanProgressMap) { Iterator<String> i = this.permitOwnersScanProgressMap.keySet().iterator(); while(i.hasNext()) ownerList.add(i.next()); } return ownerList; } public boolean tryAcquire(AtomicLong scanProgress, AtomicLong deleteProgress, String ownerName) { boolean gotPermit = this.scanPermits.tryAcquire(); if(gotPermit) { initializeProgressMaps(scanProgress, deleteProgress, ownerName); } return gotPermit; } public int availablePermits() { return this.scanPermits.availablePermits(); } public int getGrantedPermits() { return numPermits - availablePermits(); } public long getEntriesScanned() { long itemsScanned = 0; synchronized(permitOwnersScanProgressMap) { for(Map.Entry<String, AtomicLong> progressEntry: permitOwnersScanProgressMap.entrySet()) { AtomicLong progress = progressEntry.getValue(); // slops are not included since they are tracked separately if(progress != null) { itemsScanned += progress.get(); } } } return totalEntriesScanned + itemsScanned; } public long getEntriesDeleted() { long itemsDeleted = 0; synchronized(permitOwnersDeleteProgressMap) { for(Map.Entry<String, AtomicLong> progressEntry: permitOwnersDeleteProgressMap.entrySet()) { AtomicLong progress = progressEntry.getValue(); // slops are not included since they are tracked separately if(progress != null) { itemsDeleted += progress.get(); } } } return totalEntriesDeleted + itemsDeleted; } }