package org.red5.io; /* * RED5 Open Source Flash Server - http://code.google.com/p/red5/ * * Copyright (c) 2006-2010 by respective authors (see below). All rights reserved. * * 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., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.red5.io.flv.IKeyFrameDataAnalyzer.KeyFrameMeta; public class CachingFileKeyFrameMetaCache extends FileKeyFrameMetaCache { private Map<String, KeyFrameMeta> inMemoryMetaCache = new HashMap<String, KeyFrameMeta>(); private ReadWriteLock rwLock = new ReentrantReadWriteLock(); private int maxCacheEntry = 500; private Random random = new Random(); public void setMaxCacheEntry(int maxCacheEntry) { this.maxCacheEntry = maxCacheEntry; } @Override public KeyFrameMeta loadKeyFrameMeta(File file) { rwLock.readLock().lock(); try { String canonicalPath = file.getCanonicalPath(); if (!inMemoryMetaCache.containsKey(canonicalPath)) { rwLock.readLock().unlock(); rwLock.writeLock().lock(); try { if (inMemoryMetaCache.size() >= maxCacheEntry) { freeCachingMetadata(); } KeyFrameMeta keyFrameMeta = super.loadKeyFrameMeta(file); if (keyFrameMeta != null) { inMemoryMetaCache.put(canonicalPath, keyFrameMeta); } else { return null; } } finally { rwLock.writeLock().unlock(); rwLock.readLock().lock(); } } return inMemoryMetaCache.get(canonicalPath); } catch (IOException e) { return null; } finally { rwLock.readLock().unlock(); } } @Override public void saveKeyFrameMeta(File file, KeyFrameMeta meta) { rwLock.writeLock().lock(); try { String canonicalPath = file.getCanonicalPath(); if (inMemoryMetaCache.containsKey(canonicalPath)) { inMemoryMetaCache.remove(canonicalPath); } } catch (IOException e) { // ignore the exception here, let super class to handle it. } finally { rwLock.writeLock().unlock(); } super.saveKeyFrameMeta(file, meta); } private void freeCachingMetadata() { int cacheSize = inMemoryMetaCache.size(); int randomIndex = random.nextInt(cacheSize); Map.Entry<String, KeyFrameMeta> entryToRemove = null; for (Map.Entry<String, KeyFrameMeta> cacheEntry : inMemoryMetaCache.entrySet()) { if (randomIndex == 0) { entryToRemove = cacheEntry; break; } randomIndex--; } if (entryToRemove != null) { inMemoryMetaCache.remove(entryToRemove.getKey()); } } }