r1053: Add Russian translation.
[cinelerra_cv.git] / cinelerra / cache.C
blobe23a57f18b13526c76f6f9e62f3506caf3ed4e39
1 #include "asset.h"
2 #include "assets.h"
3 #include "bcsignals.h"
4 #include "cache.h"
5 #include "condition.h"
6 #include "datatype.h"
7 #include "edl.h"
8 #include "edlsession.h"
9 #include "file.h"
10 #include "filesystem.h"
11 #include "mutex.h"
12 #include "preferences.h"
14 #include <string.h>
16 // edl came from a command which won't exist anymore
17 CICache::CICache(Preferences *preferences,
18         ArrayList<PluginServer*> *plugindb)
19  : List<CICacheItem>()
21         this->plugindb = plugindb;
22         this->preferences = preferences;
23         check_out_lock = new Condition(0, "CICache::check_out_lock", 0);
24         total_lock = new Mutex("CICache::total_lock");
27 CICache::~CICache()
29         while(last)
30         {
31                 CICacheItem *item = last;
32 //printf("CICache::~CICache: %s\n", item->asset->path);
33                 remove_pointer(item);
34                 Garbage::delete_object(item);
35         }
36         delete check_out_lock;
37         delete total_lock;
45 File* CICache::check_out(Asset *asset, EDL *edl, int block)
47         CICacheItem *current, *new_item = 0;
49         while(1)
50         {
51 // Scan directory for item
52                 int got_it = 0;
53                 total_lock->lock("CICache::check_out");
54                 for(current = first; current && !got_it; current = NEXT)
55                 {
56                         if(!strcmp(current->asset->path, asset->path))
57                         {
58                                 got_it = 1;
59                                 break;
60                         }
61                 }
63 // Test availability
64                 if(got_it)
65                 {
66                         if(!current->checked_out)
67                         {
68 // Return it
69                                 current->age = EDL::next_id();
70                                 current->checked_out = 1;
71                                 current->GarbageObject::add_user();
72                                 total_lock->unlock();
73                                 return current->file;
74                         }
75                 }
76                 else
77                 {
78 // Create new item
79                         new_item = append(new CICacheItem(this, edl, asset));
81                         if(new_item->file)
82                         {
83 // opened successfully.
84                                 new_item->age = EDL::next_id();
85                                 new_item->checked_out = 1;
86                                 new_item->GarbageObject::add_user();
87                                 total_lock->unlock();
88                                 return new_item->file;
89                         }
90 // Failed to open
91                         else
92                         {
93                                 remove_pointer(new_item);
94                                 Garbage::delete_object(new_item);
95                                 total_lock->unlock();
96                                 return 0;
97                         }
98                 }
100 // Try again after blocking
101                 total_lock->unlock();
102                 if(block)
103                         check_out_lock->lock("CICache::check_out");
104                 else
105                         return 0;
106         }
108         return 0;
111 int CICache::check_in(Asset *asset)
113         CICacheItem *current;
114         int got_it = 0;
116         total_lock->lock("CICache::check_in");
117         for(current = first; current; current = NEXT)
118         {
119 // Need to compare paths because
120 // asset pointers are different
121                 if(!strcmp(current->asset->path, asset->path))
122                 {
123                         current->checked_out = 0;
124                         current->GarbageObject::remove_user();
125 // Pointer no longer valid here
126                         break;
127                 }
128         }
129         total_lock->unlock();
131 // Release for blocking check_out operations
132         check_out_lock->unlock();
134         age();
135         return 0;
138 void CICache::remove_all()
140         total_lock->lock("CICache::remove_all");
141         CICacheItem *current, *temp;
142         for(current = first; current; current = temp)
143         {
144                 temp = current->next;
145 // Must not be checked out because we need the pointer to check back in.
146 // Really need to give the user the CacheItem.
147                 if(!current->checked_out)
148                 {
149 //printf("CICache::remove_all: %s\n", current->asset->path);
150                         remove_pointer(current);
151                         Garbage::delete_object(current);
152                 }
153         }
154         total_lock->unlock();
157 int CICache::delete_entry(char *path)
159         total_lock->lock("CICache::delete_entry");
160         for(CICacheItem *current = first; current; current = NEXT)
161         {
162                 if(!strcmp(current->asset->path, path))
163                 {
164                         if(!current->checked_out)
165                         {
166 //printf("CICache::delete_entry: %s\n", current->asset->path);
167                                 remove_pointer(current);
168                                 Garbage::delete_object(current);
169                                 break;
170                         }
171                 }
172         }
173         total_lock->unlock();
174         return 0;
177 int CICache::delete_entry(Asset *asset)
179         total_lock->lock("CICache::delete_entry");
180         int result = 0;
181         CICacheItem *current, *temp;
183         for(current = first; current; current = NEXT)
184         {
185                 if(!strcmp(current->asset->path, asset->path))
186                 {
187                         if(!current->checked_out)
188                         {
189 //printf("CICache::delete_entry: %s\n", current->asset->path);
190                                 remove_pointer(current);
191                                 Garbage::delete_object(current);
192                                 break;
193                         }
194                 }
195         }
197         total_lock->unlock();
198         return 0;
201 int CICache::age()
203         CICacheItem *current;
205 // delete old assets if memory usage is exceeded
206         int64_t prev_memory_usage;
207         int64_t memory_usage;
208         int result = 0;
209         do
210         {
211                 memory_usage = get_memory_usage(1);
212                 
213                 if(memory_usage > preferences->cache_size)
214                 {
215 //printf("CICache::age 3 %p %lld %lld\n", this, memory_usage, preferences->cache_size);
216                         result = delete_oldest();
217                 }
218                 prev_memory_usage = memory_usage;
219                 memory_usage = get_memory_usage(0);
220         }while(prev_memory_usage != memory_usage &&
221                 memory_usage > preferences->cache_size && 
222                 !result);
226 int64_t CICache::get_memory_usage(int use_lock)
228         CICacheItem *current;
229         int64_t result = 0;
230         if(use_lock) total_lock->lock("CICache::get_memory_usage");
231         for(current = first; current; current = NEXT)
232         {
233                 File *file = current->file;
234                 if(file) result += file->get_memory_usage();
235         }
236         if(use_lock) total_lock->unlock();
237         return result;
240 int CICache::get_oldest()
242         CICacheItem *current;
243         int oldest = 0x7fffffff;
244         total_lock->lock("CICache::get_oldest");
245         for(current = last; current; current = PREVIOUS)
246         {
247                 if(current->age < oldest)
248                 {
249                         oldest = current->age;
250                 }
251         }
252         total_lock->unlock();
254         return oldest;
257 int CICache::delete_oldest()
259         CICacheItem *current;
260         int lowest_age = 0x7fffffff;
261         CICacheItem *oldest = 0;
263         total_lock->lock("CICache::delete_oldest");
265         for(current = last; current; current = PREVIOUS)
266         {
267                 if(current->age < lowest_age)
268                 {
269                         oldest = current;
270                         lowest_age = current->age;
271                 }
272         }
275         if(oldest)
276         {
277 // Got the oldest file.  Try requesting cache purge.
279                 if(!oldest->file || oldest->file->purge_cache())
280                 {
282 // Delete the file if cache already empty and not checked out.
283                         if(!oldest->checked_out)
284                         {
286                                 remove_pointer(oldest);
288                                 Garbage::delete_object(oldest);
290                         }
292                 }
294                 total_lock->unlock();
295 // success
296                 return 0;    
297         }
298         else
299         {
300                 total_lock->unlock();
301 // nothing was old enough to delete
302                 return 1;   
303         }
306 int CICache::dump()
308         CICacheItem *current;
309         total_lock->lock("CICache::dump");
310         printf("CICache::dump total size %lld\n", get_memory_usage(0));
311         for(current = first; current; current = NEXT)
312         {
313                 printf("cache item %x asset %x %s age=%d\n", 
314                         current, 
315                         current->asset,
316                         current->asset->path, 
317                         current->age);
318         }
319         total_lock->unlock();
330 CICacheItem::CICacheItem()
331 : ListItem<CICacheItem>(), GarbageObject("CICacheItem")
336 CICacheItem::CICacheItem(CICache *cache, EDL *edl, Asset *asset)
337  : ListItem<CICacheItem>(), GarbageObject("CICacheItem")
339         int result = 0;
340         age = EDL::next_id();
342         this->asset = new Asset;
344         item_lock = new Condition(1, "CICacheItem::item_lock", 0);
345         
347 // Must copy Asset since this belongs to an EDL which won't exist forever.
348         *this->asset = *asset;
349         this->cache = cache;
350         checked_out = 0;
353         file = new File;
354         file->set_processors(cache->preferences->processors);
355         file->set_preload(edl->session->playback_preload);
356         file->set_subtitle(edl->session->decode_subtitles ? 
357                 edl->session->subtitle_number : -1);
358         file->set_interpolate_raw(edl->session->interpolate_raw);
359         file->set_white_balance_raw(edl->session->white_balance_raw);
362 // Copy decoding parameters from session to asset so file can see them.
363         this->asset->divx_use_deblocking = edl->session->mpeg4_deblock;
367         if(result = file->open_file(cache->preferences, this->asset, 1, 0, -1, -1))
368         {
369 SET_TRACE
370                 delete file;
371 SET_TRACE
372                 file = 0;
373         }
377 CICacheItem::~CICacheItem()
379         if(file) delete file;
380         if(asset) Garbage::delete_object(asset);
381         if(item_lock) delete item_lock;