package com.codecademy.eventhub.index; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.cache.RemovalListener; import com.google.common.cache.RemovalNotification; import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.codecademy.eventhub.base.ByteBufferUtil; import com.codecademy.eventhub.list.DmaList; import javax.inject.Named; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.nio.MappedByteBuffer; public class UserEventIndexModule extends AbstractModule { @Override protected void configure() {} @Provides @Named("eventhub.usereventindex.directory") public String getUserEventIndexDirectory(@Named("eventhub.directory") String directory) { return directory + "/user_event_index/"; } @Provides public DmaList<UserEventIndex.IndexEntry> getIndexEntryDmaList( @Named("eventhub.usereventindex.directory") String directory, @Named("eventhub.usereventindex.numPointersPerIndexEntry") int numPointers, @Named("eventhub.usereventindex.numIndexEntryPerFile") int numIndexEntryPerFile, @Named("eventhub.usereventindex.indexEntryFileCacheSize") int indexEntryFileCacheSize) { return DmaList.build(new UserEventIndex.IndexEntry.Schema(numPointers), directory, numIndexEntryPerFile, indexEntryFileCacheSize); } @Provides public UserEventIndex.IndexEntry.Factory getIndexEntryFactory( @Named("eventhub.usereventindex.numPointersPerIndexEntry") int numPointers) { return new UserEventIndex.IndexEntry.Factory(numPointers); } @Provides public UserEventIndex.Block.Factory getBlockFactory( final @Named("eventhub.usereventindex.directory") String directory, @Named("eventhub.usereventindex.blockCacheSize") int blockCacheSize, @Named("eventhub.usereventindex.numRecordsPerBlock") int numRecordsPerBlock, @Named("eventhub.usereventindex.numBlocksPerFile") int numBlocksPerFile) { final int fileSize = numBlocksPerFile * ( numRecordsPerBlock * UserEventIndex.ID_SIZE + UserEventIndex.Block.MetaData.SIZE); LoadingCache<Integer, MappedByteBuffer> buffers = CacheBuilder.newBuilder() .maximumSize(blockCacheSize) .recordStats() .removalListener(new RemovalListener<Integer, MappedByteBuffer>() { @Override public void onRemoval(RemovalNotification<Integer, MappedByteBuffer> notification) { MappedByteBuffer value = notification.getValue(); if (value != null) { value.force(); } }}) .build(new CacheLoader<Integer, MappedByteBuffer>() { @Override public MappedByteBuffer load(Integer key) throws Exception { return ByteBufferUtil.createNewBuffer( String.format("%s/block_%d.mem", directory, key), fileSize); } }); String filename = directory + "block_factory.ser"; File file = new File(filename); if (file.exists()) { try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) { long currentPointer = ois.readLong(); return new UserEventIndex.Block.Factory(filename, buffers, numRecordsPerBlock, numBlocksPerFile, currentPointer); } catch (IOException e) { throw new RuntimeException(e); } } return new UserEventIndex.Block.Factory(filename, buffers, numRecordsPerBlock, numBlocksPerFile, 0); } @Provides public UserEventIndex getUserEventIndex( final @Named("eventhub.usereventindex.directory") String directory, DmaList<UserEventIndex.IndexEntry> index, UserEventIndex.IndexEntry.Factory indexEntryFactory, UserEventIndex.Block.Factory blockFactory) { return new UserEventIndex(index, indexEntryFactory, blockFactory); } }