/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.services; import java.io.File; import java.io.IOException; import java.io.Serializable; import org.teiid.common.buffer.BufferManager; import org.teiid.common.buffer.StorageManager; import org.teiid.common.buffer.TupleBufferCache; import org.teiid.common.buffer.impl.BufferFrontedFileStoreCache; import org.teiid.common.buffer.impl.BufferManagerImpl; import org.teiid.common.buffer.impl.EncryptedStorageManager; import org.teiid.common.buffer.impl.FileStorageManager; import org.teiid.common.buffer.impl.MemoryStorageManager; import org.teiid.common.buffer.impl.SplittableStorageManager; import org.teiid.core.TeiidComponentException; import org.teiid.core.TeiidRuntimeException; import org.teiid.core.util.FileUtils; import org.teiid.dqp.service.BufferService; import org.teiid.logging.LogConstants; import org.teiid.logging.LogManager; import org.teiid.runtime.RuntimePlugin; /** * Implements the BufferService. This implementation * may use either an all-memory model (which is typically only for testing) or * a mixed disk/memory model which requires use of a directory on the disk * for file service access. */ public class BufferServiceImpl implements BufferService, Serializable { private static final long serialVersionUID = -6217808623863643531L; private static final long MB = 1<<20; // Instance private BufferManagerImpl bufferMgr; private File bufferDir; private boolean useDisk = true; private boolean encryptFiles = false; private int processorBatchSize = BufferManager.DEFAULT_PROCESSOR_BATCH_SIZE; private int maxOpenFiles = FileStorageManager.DEFAULT_MAX_OPEN_FILES; private long maxFileSize = SplittableStorageManager.DEFAULT_MAX_FILESIZE; // 2GB private int maxProcessingKb = BufferManager.DEFAULT_MAX_PROCESSING_KB; private int maxReserveKb = BufferManager.DEFAULT_RESERVE_BUFFER_KB; private long maxBufferSpace = FileStorageManager.DEFAULT_MAX_BUFFERSPACE>>20; private boolean inlineLobs = true; private long memoryBufferSpace = -1; private int maxStorageObjectSize = BufferFrontedFileStoreCache.DEFAuLT_MAX_OBJECT_SIZE; private boolean memoryBufferOffHeap; private FileStorageManager fsm; private BufferFrontedFileStoreCache fsc; private int workingMaxReserveKb; /** * Clean the file storage directory on startup * @param dir * @since 4.3 */ void cleanDirectory(File file) { FileUtils.removeChildrenRecursively(file); } public void start(){ try { // Construct and initialize the buffer manager this.bufferMgr = new BufferManagerImpl(); this.bufferMgr.setProcessorBatchSize(processorBatchSize); this.bufferMgr.setMaxReserveKB(this.maxReserveKb); this.bufferMgr.setMaxProcessingKB(this.maxProcessingKb); this.bufferMgr.setInlineLobs(inlineLobs); this.bufferMgr.initialize(); // If necessary, add disk storage manager if(useDisk) { LogManager.logDetail(LogConstants.CTX_DQP, "Starting BufferManager using", bufferDir); //$NON-NLS-1$ if (!bufferDir.exists()) { this.bufferDir.mkdirs(); } // start the file storage manager in clean state // wise FileStorageManager is smart enough to clean up after itself cleanDirectory(bufferDir); // Get the properties for FileStorageManager and create. fsm = new FileStorageManager(); fsm.setStorageDirectory(bufferDir.getCanonicalPath()); fsm.setMaxOpenFiles(maxOpenFiles); fsm.setMaxBufferSpace(maxBufferSpace*MB); SplittableStorageManager ssm = new SplittableStorageManager(fsm); ssm.setMaxFileSize(maxFileSize); StorageManager sm = ssm; if (encryptFiles) { sm = new EncryptedStorageManager(ssm); } fsc = new BufferFrontedFileStoreCache(); fsc.setBufferManager(this.bufferMgr); fsc.setMaxStorageObjectSize(maxStorageObjectSize); fsc.setDirect(memoryBufferOffHeap); //use approximately 40% of what's set aside for the reserved accounting for conversion from kb to bytes long autoMaxBufferSpace = 4*(((long)this.bufferMgr.getMaxReserveKB())<<10)/10; //estimate inode/batch overhead if (memoryBufferSpace < 0) { fsc.setMemoryBufferSpace(autoMaxBufferSpace); } else { //scale from MB to bytes fsc.setMemoryBufferSpace(memoryBufferSpace << 20); } long batchAndInodeOverheadKB = fsc.getMemoryBufferSpace()>>(memoryBufferOffHeap?19:17); this.bufferMgr.setMaxReserveKB((int)Math.max(0, this.bufferMgr.getMaxReserveKB() - batchAndInodeOverheadKB)); if (this.maxReserveKb < 0) { if (memoryBufferOffHeap) { //the default is too large if off heap this.bufferMgr.setMaxReserveKB(8*this.bufferMgr.getMaxReserveKB()/10); } else { //adjust the value for the main memory buffer this.bufferMgr.setMaxReserveKB((int)Math.max(0, this.bufferMgr.getMaxReserveKB() - (fsc.getMemoryBufferSpace()>>10))); } } fsc.setStorageManager(sm); fsc.initialize(); this.bufferMgr.setCache(fsc); this.workingMaxReserveKb = this.bufferMgr.getMaxReserveKB(); } else { MemoryStorageManager msm = new MemoryStorageManager(); SplittableStorageManager ssm = new SplittableStorageManager(msm); ssm.setMaxFileSizeDirect(MemoryStorageManager.MAX_FILE_SIZE); this.bufferMgr.setCache(msm); this.bufferMgr.setStorageManager(ssm); } } catch(TeiidComponentException e) { throw new TeiidRuntimeException(RuntimePlugin.Event.TEIID40039, e, RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40039)); } catch(IOException e) { throw new TeiidRuntimeException(RuntimePlugin.Event.TEIID40039, e, RuntimePlugin.Util.gs(RuntimePlugin.Event.TEIID40039)); } } public void stop() { LogManager.logDetail(LogConstants.CTX_DQP, "Stopping BufferManager using", bufferDir); //$NON-NLS-1$ if (bufferMgr != null) { bufferMgr.shutdown(); bufferMgr = null; } // Delete the buffer directory if (bufferDir != null) { cleanDirectory(bufferDir); bufferDir.delete(); } } public BufferManagerImpl getBufferManager() { return this.bufferMgr; } @Override public TupleBufferCache getTupleBufferCache() { return this.bufferMgr; } public void setUseDisk(boolean flag) { this.useDisk = flag; } public void setDiskDirectory(String dir) { this.bufferDir = new File(dir, "buffer"); //$NON-NLS-1$ } public void setProcessorBatchSize(int size) { this.processorBatchSize = size; } public void setInlineLobs(boolean inlineLobs) { this.inlineLobs = inlineLobs; } public File getBufferDirectory() { return bufferDir; } public boolean isUseDisk() { return this.useDisk; } public boolean isInlineLobs() { return inlineLobs; } public int getProcessorBatchSize() { return this.processorBatchSize; } public void setMaxFileSize(long maxFileSize) { this.maxFileSize = maxFileSize; } public long getMaxFileSize() { return maxFileSize; } public void setMaxOpenFiles(int maxOpenFiles) { this.maxOpenFiles = maxOpenFiles; } public int getMaxProcessingKb() { return maxProcessingKb; } public int getMaxReservedKb() { return maxReserveKb; } public void setMaxProcessingKb(int maxProcessingKb) { this.maxProcessingKb = maxProcessingKb; } public void setMaxReserveKb(int maxReserveKb) { this.maxReserveKb = maxReserveKb; } public long getMaxBufferSpace() { return maxBufferSpace; } public void setMaxBufferSpace(long maxBufferSpace) { this.maxBufferSpace = maxBufferSpace; } public void setMemoryBufferOffHeap(boolean memoryBufferOffHeap) { this.memoryBufferOffHeap = memoryBufferOffHeap; } public void setMemoryBufferSpace(int memoryBufferSpace) { this.memoryBufferSpace = memoryBufferSpace; } public void setMaxStorageObjectSize(int maxStorageObjectSize) { this.maxStorageObjectSize = maxStorageObjectSize; } public long getUsedDiskBufferSpaceMB() { if (fsm != null) { return fsm.getUsedBufferSpace()/MB; } return 0; } public long getHeapCacheMemoryInUseKB() { return bufferMgr.getActiveBatchBytes()/1024; } public long getHeapMemoryInUseByActivePlansKB() { return workingMaxReserveKb - bufferMgr.getReserveBatchBytes()/1024; } public long getDiskReadCount() { if (fsc != null) { return fsc.getStorageReads(); } return 0; } public long getDiskWriteCount() { if (fsc != null) { return fsc.getStorageWrites(); } return 0; } public long getMemoryBufferUsedKB() { if (fsc != null) { return fsc.getMemoryInUseBytes() >> 10; } return 0; } public long getCacheReadCount() { return bufferMgr.getReadCount(); } public long getCacheWriteCount() { return bufferMgr.getWriteCount(); } public long getReadAttempts() { return bufferMgr.getReadAttempts(); } public int getMemoryBufferSpace() { return (int)memoryBufferSpace; } public int getMaxStorageObjectSize() { return maxStorageObjectSize; } public boolean isMemoryBufferOffHeap() { return memoryBufferOffHeap; } public boolean isEncryptFiles() { return encryptFiles; } public void setEncryptFiles(boolean encryptFiles) { this.encryptFiles = encryptFiles; } }