Merge branch 'ct' of git.pipapo.org:cinelerra-ct into ct
[cinelerra_cv/ct.git] / cinelerra / cache.C
blob7b1fac69c11a5efea8b538ea09c5fe1ea109c1fc
1 #include "cinelerra.h"
3 #include "asset.h"
4 #include "assets.h"
5 #include "bcsignals.h"
6 #include "cache.h"
7 #include "condition.h"
8 #include "datatype.h"
9 #include "edl.h"
10 #include "edlsession.h"
11 #include "file.h"
12 #include "filesystem.h"
13 #include "mutex.h"
14 #include "preferences.h"
16 #include <string.h>
18 // edl came from a command which won't exist anymore
19 CICache::CICache(Preferences *preferences,
20         ArrayList<PluginServer*> *plugindb)
21  : List<CICacheItem>()
23         this->plugindb = plugindb;
24         this->preferences = preferences;
25         check_out_lock = new Condition(0, "CICache::check_out_lock", 0);
26         total_lock = new Mutex("CICache::total_lock");
29 CICache::~CICache()
31         while(last)
32         {
33                 CICacheItem *item = last;
34 //printf("CICache::~CICache: %s\n", item->asset->path);
35                 remove_pointer(item);
36                 Garbage::delete_object(item);
37         }
38         delete check_out_lock;
39         delete total_lock;
47 File* CICache::check_out(Asset_GC asset, EDL *edl, int block)
49         CICacheItem *current, *new_item = 0;
51         while(1)
52         {
53 // Scan directory for item
54                 int got_it = 0;
55                 total_lock->lock("CICache::check_out");
56                 for(current = first; current && !got_it; current = NEXT)
57                 {
58                         if(!strcmp(current->asset->path, asset->path))
59                         {
60                                 got_it = 1;
61                                 break;
62                         }
63                 }
65 // Test availability
66                 if(got_it)
67                 {
68                         if(!current->checked_out)
69                         {
70 // Return it
71                                 current->age = EDL::next_id();
72                                 current->checked_out = 1;
73                                 current->GarbageObject::add_user();
74                                 total_lock->unlock();
75                                 return current->file;
76                         }
77                 }
78                 else
79                 {
80 // Create new item
81                         new_item = append(new CICacheItem(this, edl, asset));
83                         if(new_item->file)
84                         {
85 // opened successfully.
86                                 new_item->age = EDL::next_id();
87                                 new_item->checked_out = 1;
88                                 new_item->GarbageObject::add_user();
89                                 total_lock->unlock();
90                                 return new_item->file;
91                         }
92 // Failed to open
93                         else
94                         {
95                                 remove_pointer(new_item);
96                                 Garbage::delete_object(new_item);
97                                 total_lock->unlock();
98                                 return 0;
99                         }
100                 }
102 // Try again after blocking
103                 total_lock->unlock();
104                 if(block)
105                         check_out_lock->lock("CICache::check_out");
106                 else
107                         return 0;
108         }
110         return 0;
113 int CICache::check_in(Asset_GC asset)
115         CICacheItem *current;
116         int got_it = 0;
118         total_lock->lock("CICache::check_in");
119         for(current = first; current; current = NEXT)
120         {
121 // Need to compare paths because
122 // asset pointers are different
123                 if(!strcmp(current->asset->path, asset->path))
124                 {
125                         current->checked_out = 0;
126                         current->GarbageObject::remove_user();
127 // Pointer no longer valid here
128                         break;
129                 }
130         }
131         total_lock->unlock();
133 // Release for blocking check_out operations
134         check_out_lock->unlock();
136         age();
137         return 0;
140 void CICache::remove_all()
142         total_lock->lock("CICache::remove_all");
143         CICacheItem *current, *temp;
144         for(current = first; current; current = temp)
145         {
146                 temp = current->next;
147 // Must not be checked out because we need the pointer to check back in.
148 // Really need to give the user the CacheItem.
149                 if(!current->checked_out)
150                 {
151 //printf("CICache::remove_all: %s\n", current->asset->path);
152                         remove_pointer(current);
153                         Garbage::delete_object(current);
154                 }
155         }
156         total_lock->unlock();
159 int CICache::delete_entry(char *path)
161         total_lock->lock("CICache::delete_entry");
162         for(CICacheItem *current = first; current; current = NEXT)
163         {
164                 if(!strcmp(current->asset->path, path))
165                 {
166                         if(!current->checked_out)
167                         {
168 //printf("CICache::delete_entry: %s\n", current->asset->path);
169                                 remove_pointer(current);
170                                 Garbage::delete_object(current);
171                                 break;
172                         }
173                 }
174         }
175         total_lock->unlock();
176         return 0;
179 int CICache::delete_entry(Asset_GC asset)
181         total_lock->lock("CICache::delete_entry");
182         int result = 0;
183         CICacheItem *current, *temp;
185         for(current = first; current; current = NEXT)
186         {
187                 if(!strcmp(current->asset->path, asset->path))
188                 {
189                         if(!current->checked_out)
190                         {
191 //printf("CICache::delete_entry: %s\n", current->asset->path);
192                                 remove_pointer(current);
193                                 Garbage::delete_object(current);
194                                 break;
195                         }
196                 }
197         }
199         total_lock->unlock();
200         return 0;
203 int CICache::age()
205         CICacheItem *current;
207 // delete old assets if memory usage is exceeded
208         int64_t prev_memory_usage;
209         int64_t memory_usage;
210         int result = 0;
211         do
212         {
213                 memory_usage = get_memory_usage(1);
214                 
215                 if(memory_usage > preferences->cache_size)
216                 {
217 //printf("CICache::age 3 %p %lld %lld\n", this, memory_usage, preferences->cache_size);
218                         result = delete_oldest();
219                 }
220                 prev_memory_usage = memory_usage;
221                 memory_usage = get_memory_usage(0);
222         }while(prev_memory_usage != memory_usage &&
223                 memory_usage > preferences->cache_size && 
224                 !result);
228 int64_t CICache::get_memory_usage(int use_lock)
230         CICacheItem *current;
231         int64_t result = 0;
232         if(use_lock) total_lock->lock("CICache::get_memory_usage");
233         for(current = first; current; current = NEXT)
234         {
235                 File *file = current->file;
236                 if(file) result += file->get_memory_usage();
237         }
238         if(use_lock) total_lock->unlock();
239         return result;
242 int CICache::get_oldest()
244         CICacheItem *current;
245         int oldest = 0x7fffffff;
246         total_lock->lock("CICache::get_oldest");
247         for(current = last; current; current = PREVIOUS)
248         {
249                 if(current->age < oldest)
250                 {
251                         oldest = current->age;
252                 }
253         }
254         total_lock->unlock();
256         return oldest;
259 int CICache::delete_oldest()
261         CICacheItem *current;
262         int lowest_age = 0x7fffffff;
263         CICacheItem *oldest = 0;
265         total_lock->lock("CICache::delete_oldest");
267         for(current = last; current; current = PREVIOUS)
268         {
269                 if(current->age < lowest_age)
270                 {
271                         oldest = current;
272                         lowest_age = current->age;
273                 }
274         }
277         if(oldest)
278         {
279 // Got the oldest file.  Try requesting cache purge.
281                 if(!oldest->file || oldest->file->purge_cache())
282                 {
284 // Delete the file if cache already empty and not checked out.
285                         if(!oldest->checked_out)
286                         {
288                                 remove_pointer(oldest);
290                                 Garbage::delete_object(oldest);
292                         }
294                 }
296                 total_lock->unlock();
297 // success
298                 return 0;    
299         }
300         else
301         {
302                 total_lock->unlock();
303 // nothing was old enough to delete
304                 return 1;   
305         }
308 int CICache::dump()
310         CICacheItem *current;
311         total_lock->lock("CICache::dump");
312         printf("CICache::dump total size %lld\n", get_memory_usage(0));
313         for(current = first; current; current = NEXT)
314         {
315                 printf("cache item %x asset %x %s age=%d\n", 
316                         current, 
317                         current->asset.get(),
318                         current->asset->path, 
319                         current->age);
320         }
321         total_lock->unlock();
332 CICacheItem::CICacheItem()
333 : ListItem<CICacheItem>(), GarbageObject("CICacheItem")
338 CICacheItem::CICacheItem(CICache *cache, EDL *edl, Asset_GC asset)
339  : ListItem<CICacheItem>(), GarbageObject("CICacheItem")
341         int result = 0;
342         age = EDL::next_id();
344         this->asset = Asset_GC(new Asset);
346         item_lock = new Condition(1, "CICacheItem::item_lock", 0);
347         
349 // Must copy Asset since this belongs to an EDL which won't exist forever.
350         *this->asset = *asset;
351         this->cache = cache;
352         checked_out = 0;
355         file = new File;
356         file->set_processors(cache->preferences->processors);
357         file->set_preload(edl->session->playback_preload);
358         file->set_subtitle(edl->session->decode_subtitles ? 
359                 edl->session->subtitle_number : -1);
360         file->set_interpolate_raw(edl->session->interpolate_raw);
361         file->set_white_balance_raw(edl->session->white_balance_raw);
364 // Copy decoding parameters from session to asset so file can see them.
365         this->asset->divx_use_deblocking = edl->session->mpeg4_deblock;
369         if(result = file->open_file(cache->preferences, this->asset, 1, 0, -1, -1))
370         {
371 SET_TRACE
372                 delete file;
373 SET_TRACE
374                 file = 0;
375         }
379 CICacheItem::~CICacheItem()
381         if(file) delete file;
382         if(item_lock) delete item_lock;
385 //      Local Variables:
386 //      mode: C++
387 //      c-file-style: "linux"
388 //      End: