package org.wonderdb.metadata; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.wonderdb.cache.impl.CacheEntryPinner; import org.wonderdb.core.collection.ResultIterator; import org.wonderdb.core.collection.WonderDBList; import org.wonderdb.file.FilePointerFactory; import org.wonderdb.freeblock.FreeBlockFactory; import org.wonderdb.serialize.SerializerManager; import org.wonderdb.server.WonderDBPropertyManager; import org.wonderdb.storage.FileBlockManager; import org.wonderdb.txnlogger.LogManager; import org.wonderdb.txnlogger.TransactionId; import org.wonderdb.types.BlockPtr; import org.wonderdb.types.ColumnSerializerMetadata; import org.wonderdb.types.DBType; import org.wonderdb.types.FileBlockEntry; import org.wonderdb.types.SingleBlockPtr; import org.wonderdb.types.record.ListRecord; import org.wonderdb.types.record.ObjectListRecord; public class StorageMetadata { private Map<Byte, FileBlockEntry> fileIdToEntryMap = new ConcurrentHashMap<Byte, FileBlockEntry>(); private ConcurrentMap<String, FileBlockEntry> fileNameToEntryMap = new ConcurrentHashMap<String, FileBlockEntry>(); private WonderDBList storageList = null; private boolean initialized = false; private byte defaultFileId = 0; private static final StorageMetadata instance = new StorageMetadata(); private StorageMetadata() { } public void init(boolean isNew) { StorageMetadata.getInstance().initialized = true; if (isNew) { create(); } else { load(); } } public void add(FileBlockEntry entry) { if (!initialized) { throw new RuntimeException("Please initialize StorageMetadata by calling StorageMetadata.init(..)"); } TransactionId txnId = LogManager.getInstance().startTxn(); Set<Object> pinnedBlocks = new HashSet<Object>(); try { entry.setFileId((byte) fileIdToEntryMap.size()); addMeta(entry); ObjectListRecord record = new ObjectListRecord(entry); storageList.add(record, txnId, new ColumnSerializerMetadata(SerializerManager.FILE_BLOCK_ENRTY_TYPE), pinnedBlocks); if (entry.isDefaultFile()) { FileBlockEntry defEntry = fileIdToEntryMap.get(defaultFileId); defEntry.setDefaultFile(false); if (defEntry != null && defEntry.getFileId() != 0) { ListRecord rec = new ObjectListRecord(defEntry); storageList.update(rec, rec, txnId, new ColumnSerializerMetadata(SerializerManager.FILE_BLOCK_ENRTY_TYPE), pinnedBlocks); } defaultFileId = entry.getFileId(); } } finally { LogManager.getInstance().commitTxn(txnId); CacheEntryPinner.getInstance().unpin(pinnedBlocks, pinnedBlocks); } } public List<FileBlockEntry> getStorageEntries() { if (!initialized) { throw new RuntimeException("Please initialize StorageMetadata by calling StorageMetadata.init(..)"); } return new ArrayList<FileBlockEntry>(fileIdToEntryMap.values()); } public String getDefaultFileName() { FileBlockEntry entry = fileIdToEntryMap.get(defaultFileId); return entry.getFileName(); } public void shutdown() { FilePointerFactory.getInstance().closAll(); } private void create() { Set<Object> pinnedBlocks = new HashSet<Object>(); try { FileBlockEntry entry = getDefaultFileBlockEntry(); addMeta(entry); BlockPtr ptr = new SingleBlockPtr((byte) 0, 0); storageList = WonderDBList.create("_storage", ptr, 1, null, pinnedBlocks); defaultFileId = 0; // // FileBlockEntry fbe = null; // fbe = new FileBlockEntry(); // fbe.setBlockSize(2048); // fbe.setFileName("cacheIndex.data"); // StorageMetadata.getInstance().add(fbe); } finally { CacheEntryPinner.getInstance().unpin(pinnedBlocks, pinnedBlocks); } } private FileBlockEntry getDefaultFileBlockEntry() { String systemFileName = WonderDBPropertyManager.getInstance().getSystemFile(); int defaultBlockSize = WonderDBPropertyManager.getInstance().getDefaultBlockSize(); FileBlockEntry entry = new FileBlockEntry(); entry.setBlockSize(defaultBlockSize); // entry.setDefaultFile(true); entry.setFileId((byte) 0); entry.setFileName(systemFileName); return entry; } private void load() { Set<Object> pinnedBlocks = new HashSet<Object>(); FileBlockEntry entry = null; try { entry = getDefaultFileBlockEntry(); addMeta(entry); BlockPtr ptr = new SingleBlockPtr((byte) 0, 0); storageList = WonderDBList.load("_storage", ptr, 1, new ColumnSerializerMetadata(SerializerManager.BLOCK_PTR_LIST_TYPE), pinnedBlocks); ResultIterator iter = storageList.iterator(new ColumnSerializerMetadata(SerializerManager.FILE_BLOCK_ENRTY_TYPE), pinnedBlocks); try { while (iter.hasNext()) { ObjectListRecord record = (ObjectListRecord) iter.next(); DBType column = record.getColumn(); entry = (FileBlockEntry) column; if (entry.isDefaultFile()) { defaultFileId = entry.getFileId(); } entry.setRecordId(record.getRecordId()); addMeta(entry); } } finally { iter.unlock(true); } } finally { CacheEntryPinner.getInstance().unpin(pinnedBlocks, pinnedBlocks); } } public byte getFileId(String fileName) { FileBlockEntry entry = fileNameToEntryMap.get(fileName); return entry != null ? entry.getFileId() : -1; } public byte getDefaultFileId() { return defaultFileId; } public void setDefaultFileId(byte defaultFileId) { this.defaultFileId = defaultFileId; } public String getFileName(byte fileId) { FileBlockEntry entry = fileIdToEntryMap.get(fileId); if (entry != null) { return entry.getFileName(); } return null; } private void addMeta(FileBlockEntry entry) { FileBlockEntry oldValue = fileNameToEntryMap.putIfAbsent(entry.getFileName(), entry); if (oldValue != null) { throw new RuntimeException("Entry already present"); } fileIdToEntryMap.put(entry.getFileId(), entry); FilePointerFactory.getInstance().create(entry); FileBlockManager.getInstance().addFileBlockEntry(entry); FreeBlockFactory.getInstance().createNewMgr(entry.getFileId(), 0, 0); } public static final StorageMetadata getInstance() { return instance; } }