pdf_pages_cache.cpp

Go to the documentation of this file.
00001 /*
00002  * File Name: pdf_pages_cache.cpp
00003  */
00004 
00005 /*
00006  * This file is part of uds-plugin-pdf.
00007  *
00008  * uds-plugin-pdf is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * uds-plugin-pdf is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /**
00023  * Copyright (C) 2008 iRex Technologies B.V.
00024  * All rights reserved.
00025  */
00026 
00027 #include "pdf_pages_cache.h"
00028 #include "pdf_doc_controller.h"
00029 
00030 namespace pdf
00031 {
00032 
00033 PagesCache::PagesCache(void)
00034 : size_limit(0)
00035 , total_length(0)
00036 , pages()
00037 , cache_mutex()
00038 {
00039 }
00040 
00041 PagesCache::~PagesCache(void)
00042 {
00043     clear();
00044 }
00045 
00046 bool PagesCache::reset(const unsigned int size)
00047 {
00048     ScopeMutex m(&cache_mutex);
00049 
00050     int real_size = static_cast<int>(size);
00051 
00052     if (size_limit > static_cast<unsigned int>(real_size))
00053     {
00054         //remove the redundant pages
00055         while (total_length > real_size)
00056         {
00057             if (!remove_page())
00058             {
00059                 // cannot remove the needed page
00060                 return false;
00061             }
00062         }
00063     }
00064 
00065     size_limit = static_cast<unsigned int>(real_size);
00066     return true;
00067 }
00068 
00069 unsigned int PagesCache::size()
00070 {
00071     ScopeMutex m(&cache_mutex);
00072     return size_limit;
00073 }
00074 
00075 void PagesCache::clear()
00076 {
00077     ScopeMutex m(&cache_mutex);
00078 
00079     PagesIter begin = pages.begin();
00080     PagesIter end = pages.end();
00081     PagesIter iter = begin;
00082     for(; iter != end; ++iter)
00083     {
00084         delete iter->second;
00085     }
00086     pages.clear();
00087     total_length = 0;
00088 }
00089 
00090 /// Add a new page
00091 void PagesCache::add_page(PagePtr p)
00092 {
00093     ScopeMutex m(&cache_mutex);
00094     // insert the new page into cache
00095     pages[(*p)()] = p;
00096 }
00097 
00098 /// Remove the old pages to make sure the memory is enough
00099 /// NOTE: length might be less than 0
00100 bool PagesCache::make_enough_memory(const int page_num, const int length)
00101 {
00102     ScopeMutex m(&cache_mutex);
00103 
00104     int sum = total_length + length;
00105     if (sum <= static_cast<int>(size_limit))
00106     {
00107         return true;
00108     }
00109 
00110     // remove the most useless pages until the sum is less than
00111     // a quarter of the size limitation
00112     unsigned int size = (size_limit >> 1);
00113     while (sum > static_cast<int>(size))
00114     {
00115         if (!remove_page(page_num))
00116         {
00117             // remove fails, because:
00118             // 1. there is no any cached images any more
00119             // 2. the image is locked
00120             if ((total_length + length) <= static_cast<int>(size_limit))
00121             {
00122                 // if the total length plus with the length is less
00123                 // than the size limitation, it means there is enough
00124                 // space left, otherwise return false.
00125                 return true;
00126             }
00127             LOGPRINTF("Skip Page:%d", page_num);
00128             return false;
00129         }
00130         sum = total_length + length;
00131     }
00132 
00133     return true;
00134 }
00135 
00136 void PagesCache::clear_cached_bitmaps()
00137 {
00138     ScopeMutex m(&cache_mutex);
00139     // clear all cached bitmaps
00140     LOGPRINTF("Clear cached bitmaps due to out of memory\n\n");
00141     PagePtr page = 0;
00142     PagesIter iter = pages.begin();
00143     for (; iter != pages.end(); ++iter)
00144     {
00145         page = iter->second;
00146         if (page->get_bitmap() && !page->locked())
00147         {
00148             int delta = static_cast<int>(page->destroy());
00149 
00150             // update the total length
00151             total_length -= delta;
00152         }
00153     }
00154 }
00155 
00156 PagePtr PagesCache::get_page(const size_t idx)
00157 {
00158     ScopeMutex m(&cache_mutex);
00159 
00160     PagePtr page = 0;
00161     PagesIter iter = pages.find(idx);
00162     if (iter != pages.end())
00163     {
00164         page = iter->second;
00165     }
00166     return page;
00167 }
00168 
00169 void PagesCache::update_mem_usage(const int length)
00170 {
00171     ScopeMutex m(&cache_mutex);
00172     total_length += length;
00173     /*LOGPRINTF("Add memory usage:%d, total length:%d\n"
00174             , length
00175             , total_length);*/
00176 }
00177 
00178 bool PagesCache::remove_page(const int page_num)
00179 {
00180     // remove the out-of-date page based on the remove strategy
00181     PagesIter begin = pages.begin();
00182     PagesIter end = pages.end();
00183     PagesIter iter = begin;
00184     PagesIter remove_iter = iter;
00185 
00186     while(iter != end)
00187     {
00188         // get the page with lowest priority
00189         if (*(iter->second) < *(remove_iter->second))
00190         {
00191             remove_iter = iter;
00192         }
00193         iter++;
00194     }
00195 
00196     if (remove_iter->second->get_bitmap() && !remove_iter->second->locked())
00197     {
00198         if (page_num >= 0 &&
00199             (remove_iter->second == pages[page_num] ||
00200              compare_priority(remove_iter->second->get_page_num(),
00201                               page_num,
00202                               remove_iter->second->get_doc_controller()->get_prerender_policy())
00203                               >= 0))
00204         {
00205             // if the request page is the lowest or all of the cached page has
00206             // higher priority, MUST not remove anything
00207             return false;
00208         }
00209 
00210         // delete the valid page(length > 0 and NOT locked)
00211         // sub the total length
00212         int delta = static_cast<int>(remove_iter->second->destroy());
00213 
00214         // update the total length
00215         total_length -= delta;
00216 
00217         LOGPRINTF("Remove Cached Page:%d, Total Length:%d, Delta Length:%d"
00218             , remove_iter->second->get_page_num()
00219             , total_length
00220             , delta);
00221 
00222         if (total_length < 0)
00223         {
00224             // this is an exception 
00225             total_length = 0;
00226         }
00227     }
00228     else if (!remove_iter->second->get_bitmap())
00229     {
00230         WARNPRINTF("No bitmap now");
00231         return false;
00232     }
00233     else
00234     {
00235         WARNPRINTF("Cannot remove the locked page %d"
00236             , remove_iter->second->get_page_num());
00237         return false;
00238     }
00239 
00240     return true;
00241 }
00242 
00243 }
00244 
Generated by  doxygen 1.6.2-20100208