package org.wonderdb.cache.impl; /******************************************************************************* * Copyright 2013 Vilas Athavale * * 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. *******************************************************************************/ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Future; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.apache.log4j.Logger; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.wonderdb.cache.CacheDestinationWriter; import org.wonderdb.cache.Cacheable; import org.wonderdb.server.WonderDBPropertyManager; import org.wonderdb.txnlogger.LogManager; public class CacheWriter<Key, Data> extends Thread{ MemoryCacheMap<Key, Data> cacheMap = null; int writerFrequency = -1; Lock threadPoolFullLock = new ReentrantLock(); Condition threadPoolFullCondition = threadPoolFullLock.newCondition(); long syncTime = -1; long inprocessSyncTime = -1; CacheDestinationWriter<Key, Data> writer = null; boolean isShutdown = false; boolean shutdownOver = false; Thread currentThread = null; Object shutdownLock = new Object(); int shutc = 0; public CacheWriter(MemoryCacheMap<Key, Data> cacheMap, int writerFrequency, CacheDestinationWriter<Key, Data> writer) { this.cacheMap = cacheMap; this.writerFrequency = writerFrequency; this.writer = writer; } public long getSyncTime() { return syncTime; } public void shutdown() { isShutdown = true; // currentThread.interrupt(); synchronized (shutdownLock) { while(true) { try { shutdownLock.wait(20); if (shutdownOver) { break; } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } // public void forceStartWriting() { // if (writerFrequency > 0) { // currentThread.interrupt(); // } // } // @Override public void run() { // currentThread = Thread.currentThread(); long timeTaken = 0; while (true) { try { if (!isShutdown) { if (writerFrequency < 0) { synchronized (cacheMap.writtenBlocks) { try { cacheMap.writtenBlocks.wait(); } catch (InterruptedException e) { } } } else { try { if (timeTaken < writerFrequency) { Thread.sleep((writerFrequency-timeTaken)); } } catch (InterruptedException e) { } } } Iterator<Key> iter = cacheMap.writtenBlocks.keySet().iterator(); Set<Object> pinnedBlocks = new HashSet<Object>(); inprocessSyncTime = -1; // Set<Key> writtenBlocks = new HashSet<Key>(); Map<Key, Data> bufferMap = new HashMap<Key, Data>(); long start = System.currentTimeMillis(); while (iter.hasNext()) { Key ptr = iter.next(); cacheMap.getBucket(ptr, true); try { // if (!CacheEntryPinner.getInstance().isPinned(ptr) && cacheMap.writtenBlocks.get(ptr) != 1) { if (!CacheEntryPinner.getInstance().isPinned(ptr)) { CacheEntryPinner.getInstance().pin(ptr, pinnedBlocks); Cacheable<Key, Data> block = cacheMap.get(ptr); if (block == null) { continue; } cacheMap.writtenBlocks.put(ptr, 1); Data data = null; // if (flag) { data = writer.copy(ptr, block.getFull()); bufferMap.put(ptr, data); // flag = cacheMap.writtenBlocks.replace(ptr, 1, 2); // } // if (flag) { // while (true) { // try { // writer.write(block.getPtr(), data); // break; // } catch (RejectedExecutionException e) { // waitForThreadPoolNotFullCondition(); // } // } // } } // writtenBlocks.add(ptr); } finally { cacheMap.returnBucket(ptr, true); CacheEntryPinner.getInstance().unpin(ptr, pinnedBlocks); // pinnedBlocks.clear(); } Set<Key> writtenBlocks = new HashSet<Key>(); int size = WonderDBPropertyManager.getInstance().getDiskAsyncWriterThreadPoolSize(); if (bufferMap.size() >= size || isShutdown) { Iterator<Key> iter1 = bufferMap.keySet().iterator(); List<Future<Integer>> futures = new ArrayList<Future<Integer>>(); while (iter1.hasNext()) { Key key = iter1.next(); Data data = bufferMap.get(key); boolean flag = cacheMap.writtenBlocks.replace(key, 1, 2); if (flag) { while (true) { try { Future<Integer> future = writer.write(key, data); futures.add(future); break; } catch (Throwable e) { for (int i = 0; i < futures.size(); i++) { futures.get(i).get(); } // Thread.sleep(100); } } writtenBlocks.add(key); } } for (int i = 0; i < futures.size(); i++) { futures.get(i).get(); } iter1 = writtenBlocks.iterator(); while (iter1.hasNext()) { Key ptr1 = iter1.next(); boolean flag = cacheMap.writtenBlocks.remove(ptr1, 2); if (flag) { bufferMap.remove(ptr1); } } bufferMap.clear(); writtenBlocks.clear(); } } timeTaken = System.currentTimeMillis()-start; syncTime = Math.max(syncTime, inprocessSyncTime); LogManager.getInstance().resetLogs(syncTime); if (isShutdown) { Logger.getLogger(getClass()).info("didnt write: "+cacheMap.writtenBlocks.size()); if (cacheMap.writtenBlocks.size()>0) { continue; } else { shutdownOver = true; synchronized (shutdownLock) { shutdownLock.notifyAll(); } return; } } } catch (Exception e) { e.printStackTrace(); } } } public ByteBuffer copy(ChannelBuffer data) { data.clear(); data.writerIndex(data.capacity()); ChannelBuffer b = ChannelBuffers.copiedBuffer(data); b.clear(); b.writerIndex(b.capacity()); return b.toByteBuffer(); } // // private void waitForThreadPoolNotFullCondition() { // try { // threadPoolFullLock.lock(); // while (true) { // try { // threadPoolFullCondition.await(20, TimeUnit.MILLISECONDS); // break; // } catch (InterruptedException e) { // } // } // } finally { // threadPoolFullLock.unlock(); // } // } // // private void notifyThreadPoolNotFull() { // try { // threadPoolFullLock.lock(); // threadPoolFullCondition.signalAll(); // } finally { // threadPoolFullLock.unlock(); // } // } }