4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "bcsignals.h"
26 #include "condition.h"
29 #include "edlsession.h"
31 #include "filesystem.h"
35 #include "preferences.h"
39 // edl came from a command which won't exist anymore
40 CICache::CICache(Preferences *preferences)
43 this->preferences = preferences;
45 check_out_lock = new Condition(0, "CICache::check_out_lock", 0);
46 total_lock = new Mutex("CICache::total_lock");
53 CICacheItem *item = last;
54 //printf("CICache::~CICache: %s\n", item->asset->path);
56 item->Garbage::remove_user();
58 delete check_out_lock;
67 File* CICache::check_out(Asset *asset, EDL *edl, int block)
69 CICacheItem *current = 0;
70 long tid = (long)Thread::get_self();
76 total_lock->lock("CICache::check_out");
77 // Scan directory for item
79 while(current && strcmp(current->asset->path, asset->path) != 0)
81 if(!current) { // Create new item
82 current = new CICacheItem(this, edl, asset);
83 append(current); current->checked_out = tid;
86 int result = file->open_file(preferences, asset, 1, 0);
92 total_lock->lock("CICache::check_out 2");
94 remove_pointer(current);
96 current->Garbage::remove_user();
100 current->Garbage::add_user();
103 file = current->file;
104 if(!current->checked_out) {
105 // Return existing/new item
106 current->Garbage::add_user();
107 current->age = EDL::next_id();
108 current->checked_out = tid;
113 total_lock->unlock();
114 if(current || !file || !block) break;
115 // Try again after blocking
116 check_out_lock->lock("CICache::check_out");
119 //printf("check out %p %lx %s\n", current, tid, asset->path);
120 return current ? current->file : 0;
123 int CICache::check_in(Asset *asset)
125 total_lock->lock("CICache::check_in");
126 CICacheItem *current = first;
127 while(current && strcmp(current->asset->path, asset->path) != 0)
129 if(current && current->checked_out) {
130 current->checked_out = 0;
131 current->Garbage::remove_user();
133 total_lock->unlock();
135 // Release for blocking check_out operations
136 check_out_lock->unlock();
137 //printf("check in %p %lx %s\n", current, (long)Thread::get_self(), asset->path);
142 void CICache::remove_all()
144 CICacheItem *current, *temp;
145 List<CICacheItem> removed;
146 total_lock->lock("CICache::remove_all");
147 for(current=first; current; current=temp)
150 // Must not be checked out because we need the pointer to check back in.
151 // Really need to give the user the CacheItem.
152 if(!current->checked_out)
154 //printf("CICache::remove_all: %s\n", current->asset->path);
155 remove_pointer(current);
156 removed.append(current);
159 total_lock->unlock();
160 while( (current=removed.first) != 0 )
162 removed.remove_pointer(current);
163 current->Garbage::remove_user();
167 int CICache::delete_entry(char *path)
169 total_lock->lock("CICache::delete_entry");
170 CICacheItem *current = first;
171 while( current && strcmp(current->asset->path, path) !=0 )
173 if(current && !current->checked_out)
174 remove_pointer(current);
177 //printf("CICache::delete_entry: %s\n", current->asset->path);
178 total_lock->unlock();
180 current->Garbage::remove_user();
184 int CICache::delete_entry(Asset *asset)
186 return delete_entry(asset->path);
191 // delete old assets if memory usage is exceeded
192 int64_t prev_memory_usage = 0;
195 int64_t memory_usage = get_memory_usage(1);
196 if( prev_memory_usage == memory_usage ) break;
197 if( preferences->cache_size >= memory_usage ) break;
198 //printf("CICache::age 3 %p " _LD " " _LD "\n", this, memory_usage, preferences->cache_size);
199 prev_memory_usage = memory_usage;
200 result = delete_oldest();
205 int64_t CICache::get_memory_usage(int use_lock)
207 CICacheItem *current;
209 if(use_lock) total_lock->lock("CICache::get_memory_usage");
210 for(current = first; current; current = NEXT)
212 File *file = current->file;
213 if(file) result += file->get_memory_usage();
215 if(use_lock) total_lock->unlock();
219 int CICache::get_oldest()
221 CICacheItem *current;
222 int oldest = 0x7fffffff;
223 total_lock->lock("CICache::get_oldest");
224 for(current = last; current; current = PREVIOUS)
226 if(current->age < oldest)
228 oldest = current->age;
231 total_lock->unlock();
236 int CICache::delete_oldest()
239 total_lock->lock("CICache::delete_oldest");
240 CICacheItem *oldest = 0;
242 if( first != last ) {
243 CICacheItem *current = first;
245 while( (current=NEXT) != 0 ) {
246 if( current->age < oldest->age )
249 // Got the oldest file. Try requesting cache purge from it.
251 oldest->file->purge_cache();
252 // Delete the file if cache already empty and not checked out.
253 if( !oldest->checked_out )
254 remove_pointer(oldest);
258 // settle for just deleting one frame
260 result = first->file->delete_oldest();
261 total_lock->unlock();
263 oldest->Garbage::remove_user();
271 CICacheItem *current;
272 total_lock->lock("CICache::dump");
273 printf("CICache::dump total size " _LD "\n", get_memory_usage(0));
274 for(current = first; current; current = NEXT)
276 printf("cache item %p asset %p %s age=%d\n",
277 current, current->asset,
278 current->asset->path, current->age);
280 total_lock->unlock();
292 CICacheItem::CICacheItem()
293 : Garbage("CICacheItem"), ListItem<CICacheItem>()
298 CICacheItem::CICacheItem(CICache *cache, EDL *edl, Asset *asset)
299 : Garbage("CICacheItem"), ListItem<CICacheItem>()
301 age = EDL::next_id();
303 this->asset = new Asset;
305 item_lock = new Condition(1, "CICacheItem::item_lock", 0);
308 // Must copy Asset since this belongs to an EDL which won't exist forever.
309 this->asset->copy_from(asset, 1);
315 int cpus = cache->preferences->processors;
316 file->set_processors(cpus);
317 file->set_preload(edl->session->playback_preload);
318 file->set_subtitle(edl->session->decode_subtitles ?
319 edl->session->subtitle_number : -1);
320 file->set_program(edl->session->program_no);
321 file->set_interpolate_raw(edl->session->interpolate_raw);
322 file->set_white_balance_raw(edl->session->white_balance_raw);
327 CICacheItem::~CICacheItem()
329 if(file) delete file;
330 if(asset) asset->Garbage::remove_user();
331 if(item_lock) delete item_lock;