Package com.orientechnologies.orient.core.storage.impl.memory

Source Code of com.orientechnologies.orient.core.storage.impl.memory.ODirectMemoryOnlyDiskCache$MemoryFile

/*
  *
  *  *  Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
  *  *
  *  *  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.
  *  *
  *  * For more information: http://www.orientechnologies.com
  *
  */

package com.orientechnologies.orient.core.storage.impl.memory;

import com.orientechnologies.common.directmemory.ODirectMemoryPointer;
import com.orientechnologies.orient.core.command.OCommandOutputListener;
import com.orientechnologies.orient.core.exception.OStorageException;
import com.orientechnologies.orient.core.index.hashindex.local.cache.OCacheEntry;
import com.orientechnologies.orient.core.index.hashindex.local.cache.OCachePointer;
import com.orientechnologies.orient.core.index.hashindex.local.cache.ODiskCache;
import com.orientechnologies.orient.core.index.hashindex.local.cache.OPageDataVerificationError;
import com.orientechnologies.orient.core.storage.impl.local.paginated.base.ODurablePage;
import com.orientechnologies.orient.core.storage.impl.local.paginated.wal.ODirtyPage;
import com.orientechnologies.orient.core.storage.impl.local.paginated.wal.OLogSequenceNumber;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
* @author Andrey Lomakin <a href="mailto:lomakin.andrey@gmail.com">Andrey Lomakin</a>
* @since 6/24/14
*/
public class ODirectMemoryOnlyDiskCache implements ODiskCache {
  private final Lock                            metadataLock  = new ReentrantLock();

  private final Map<String, Long>               fileNameIdMap = new HashMap<String, Long>();
  private final Map<Long, String>               fileIdNameMap = new HashMap<Long, String>();

  private final ConcurrentMap<Long, MemoryFile> files         = new ConcurrentHashMap<Long, MemoryFile>();

  private long                                  counter       = 0;

  private final int                             pageSize;

  public ODirectMemoryOnlyDiskCache(int pageSize) {
    this.pageSize = pageSize;
  }

  @Override
  public long openFile(String fileName) throws IOException {
    metadataLock.lock();
    try {
      Long fileId = fileNameIdMap.get(fileName);

      if (fileId == null) {
        final long id = counter++;

        files.put(id, new MemoryFile(id, pageSize));
        fileNameIdMap.put(fileName, id);

        fileId = id;

        fileIdNameMap.put(fileId, fileName);
      }

      return fileId;
    } finally {
      metadataLock.unlock();
    }
  }

  @Override
  public void openFile(long fileId) throws IOException {
    final MemoryFile memoryFile = files.get(fileId);
    if (memoryFile == null)
      throw new OStorageException("File with id " + fileId + " does not exist");
  }

  @Override
  public void openFile(String fileName, long fileId) throws IOException {
    throw new UnsupportedOperationException();
  }

  @Override
  public OCacheEntry load(long fileId, long pageIndex, boolean checkPinnedPages) throws IOException {
    final MemoryFile memoryFile = getFile(fileId);
    final OCacheEntry cacheEntry = memoryFile.loadPage(pageIndex);

    synchronized (cacheEntry) {
      cacheEntry.incrementUsages();
    }

    return cacheEntry;
  }

  @Override
  public void pinPage(OCacheEntry cacheEntry) throws IOException {
  }

  @Override
  public void loadPinnedPage(OCacheEntry cacheEntry) throws IOException {
    synchronized (cacheEntry) {
      cacheEntry.incrementUsages();
    }
  }

  @Override
  public OCacheEntry allocateNewPage(long fileId) throws IOException {
    final MemoryFile memoryFile = getFile(fileId);
    final OCacheEntry cacheEntry = memoryFile.addNewPage();

    synchronized (cacheEntry) {
      cacheEntry.incrementUsages();
    }

    return cacheEntry;
  }

  private MemoryFile getFile(long fileId) {
    final MemoryFile memoryFile = files.get(fileId);

    if (memoryFile == null)
      throw new OStorageException("File with id " + fileId + " does not exist");

    return memoryFile;
  }

  @Override
  public void release(OCacheEntry cacheEntry) {
    synchronized (cacheEntry) {
      cacheEntry.decrementUsages();
    }
  }

  @Override
  public long getFilledUpTo(long fileId) throws IOException {
    final MemoryFile memoryFile = getFile(fileId);
    return memoryFile.size();
  }

  @Override
  public void flushFile(long fileId) throws IOException {
  }

  @Override
  public void closeFile(long fileId) throws IOException {
  }

  @Override
  public void closeFile(long fileId, boolean flush) throws IOException {
  }

  @Override
  public void deleteFile(long fileId) throws IOException {
    metadataLock.lock();
    try {
      final String fileName = fileIdNameMap.remove(fileId);
      if (fileName == null)
        return;

      fileNameIdMap.remove(fileName);
      MemoryFile file = files.remove(fileId);
      if (file != null)
        file.clear();
    } finally {
      metadataLock.unlock();
    }
  }

  @Override
  public void renameFile(long fileId, String oldFileName, String newFileName) throws IOException {
    metadataLock.lock();
    try {
      String fileName = fileIdNameMap.get(fileId);
      if (fileName == null)
        return;

      fileNameIdMap.remove(fileName);

      fileName = newFileName + fileName.substring(fileName.lastIndexOf(oldFileName) + fileName.length());

      fileIdNameMap.put(fileId, fileName);
      fileNameIdMap.put(fileName, fileId);
    } finally {
      metadataLock.unlock();
    }
  }

  @Override
  public void truncateFile(long fileId) throws IOException {
    final MemoryFile file = getFile(fileId);
    file.clear();
  }

  @Override
  public boolean wasSoftlyClosed(long fileId) throws IOException {
    return true;
  }

  @Override
  public void setSoftlyClosed(long fileId, boolean softlyClosed) throws IOException {
  }

  @Override
  public void setSoftlyClosed(boolean softlyClosed) throws IOException {
  }

  @Override
  public void flushBuffer() throws IOException {
  }

  @Override
  public void close() throws IOException {
  }

  @Override
  public void delete() throws IOException {
    metadataLock.lock();
    try {
      for (MemoryFile file : files.values())
        file.clear();

      files.clear();
      fileIdNameMap.clear();
      fileNameIdMap.clear();
    } finally {
      metadataLock.unlock();
    }
  }

  @Override
  public OPageDataVerificationError[] checkStoredPages(OCommandOutputListener commandOutputListener) {
    return new OPageDataVerificationError[0];
  }

  @Override
  public Set<ODirtyPage> logDirtyPagesTable() throws IOException {
    return Collections.emptySet();
  }

  @Override
  public boolean isOpen(long fileId) {
    return files.get(fileId) != null;
  }

  @Override
  public boolean exists(String name) {
    metadataLock.lock();
    try {
      final Long fileId = fileNameIdMap.get(name);
      if (fileId == null)
        return false;

      final MemoryFile memoryFile = files.get(fileId);
      return memoryFile != null;
    } finally {
      metadataLock.unlock();
    }
  }

  @Override
  public boolean exists(long fileId) {
    metadataLock.lock();
    try {
      final MemoryFile memoryFile = files.get(fileId);
      return memoryFile != null;
    } finally {
      metadataLock.unlock();
    }
  }

  @Override
  public String fileNameById(long fileId) {
    metadataLock.lock();
    try {
      return fileIdNameMap.get(fileId);
    } finally {
      metadataLock.unlock();
    }
  }

  @Override
  public void lock() throws IOException {
  }

  @Override
  public void unlock() throws IOException {
  }

  private static final class MemoryFile {
    private final long                                     id;

    private final int                                      pageSize;
    private final ReadWriteLock                            clearLock = new ReentrantReadWriteLock();

    private final ConcurrentSkipListMap<Long, OCacheEntry> content   = new ConcurrentSkipListMap<Long, OCacheEntry>();

    private MemoryFile(long id, int pageSize) {
      this.id = id;
      this.pageSize = pageSize;
    }

    private OCacheEntry loadPage(long index) {
      clearLock.readLock().lock();
      try {
        OCacheEntry cacheEntry = content.get(index);
        if (cacheEntry != null)
          return cacheEntry;

        ODirectMemoryPointer directMemoryPointer = new ODirectMemoryPointer(new byte[pageSize + 2 * ODurablePage.PAGE_PADDING]);
        OCachePointer cachePointer = new OCachePointer(directMemoryPointer, new OLogSequenceNumber(0, 0));
        cachePointer.incrementReferrer();

        cacheEntry = new OCacheEntry(id, index, cachePointer, false);

        OCacheEntry oldCacheEntry = content.putIfAbsent(index, cacheEntry);

        if (oldCacheEntry != null) {
          cacheEntry.getCachePointer().decrementReferrer();
          cacheEntry = oldCacheEntry;
        }

        return cacheEntry;
      } finally {
        clearLock.readLock().unlock();
      }
    }

    private OCacheEntry addNewPage() {
      clearLock.readLock().lock();
      try {
        OCacheEntry cacheEntry;

        long index = -1;
        do {
          if (content.isEmpty())
            index = 0;
          else {
            long lastIndex = content.lastKey();
            index = lastIndex + 1;
          }

          final ODirectMemoryPointer directMemoryPointer = new ODirectMemoryPointer(new byte[pageSize + 2
              * ODurablePage.PAGE_PADDING]);
          final OCachePointer cachePointer = new OCachePointer(directMemoryPointer, new OLogSequenceNumber(0, 0));
          cachePointer.incrementReferrer();

          cacheEntry = new OCacheEntry(id, index, cachePointer, false);

          OCacheEntry oldCacheEntry = content.putIfAbsent(index, cacheEntry);

          if (oldCacheEntry != null) {
            cacheEntry.getCachePointer().decrementReferrer();
            index = -1;
          }
        } while (index < 0);

        return cacheEntry;
      } finally {
        clearLock.readLock().unlock();
      }
    }

    private long size() {
      clearLock.readLock().lock();
      try {
        if (content.isEmpty())
          return 0;

        try {
          return content.lastKey() + 1;
        } catch (NoSuchElementException e) {
          return 0;
        }

      } finally {
        clearLock.readLock().unlock();
      }
    }

    private void clear() {
      boolean thereAreNotReleased = false;

      clearLock.writeLock().lock();
      try {
        for (OCacheEntry entry : content.values()) {
          synchronized (entry) {
            thereAreNotReleased |= entry.getUsagesCount() > 0;
            entry.getCachePointer().decrementReferrer();
          }
        }

        content.clear();
      } finally {
        clearLock.writeLock().unlock();
      }

      if (thereAreNotReleased)
        throw new IllegalStateException("Some cache entries were not released. Storage may be in invalid state.");
    }
  }
}
TOP

Related Classes of com.orientechnologies.orient.core.storage.impl.memory.ODirectMemoryOnlyDiskCache$MemoryFile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.