cache.h
Go to the documentation of this file.
00001 #ifndef GCACHE_CACHE_H
00002 #define GCACHE_CACHE_H
00003 
00004 #ifdef _MSC_VER
00005 
00006 typedef __int16 int16_t;
00007 typedef unsigned __int16 uint16_t;
00008 typedef __int32 int32_t;
00009 typedef unsigned __int32 uint32_t;
00010 typedef __int64 int64_t;
00011 typedef unsigned __int64 uint64_t;
00012 
00013 #else
00014 #include <stdint.h>
00015 #endif
00016 
00017 #include <iostream>
00018 #include <limits.h>
00019 #include <vector>
00020 #include <list>
00021 
00022 #include "token.h"
00023 
00024 #include <wrap/system/multithreading/mt.h>
00025 #include <wrap/system/multithreading/atomic_int.h>
00026 
00027 #include "provider.h"
00028 
00029 using namespace std;
00030 /* this cache system enforce the rule that the items in a cache are always in all the cache below */
00031 /* two mechanism to remove tokens from the cache:
00032       1) set token count to something low
00033       2) set maximum number of tokens in the provider
00034 */
00035 
00039 namespace vcg {
00040 
00041 template <typename Token> class Transfer;
00042 
00043 template <typename Token>
00044 class Cache: public Provider<Token> {
00045 
00046 public:
00048     bool final;
00049     //if true the cache will exit at the first opportunity
00050     bool quit;
00052     mt::atomicInt new_data;
00054     void (*callback)(void *data);
00055 
00057     Provider<Token> *input;
00058 
00060     std::vector<Transfer<Token> *> transfers;
00061 
00062 protected:
00064     uint64_t s_max;
00066     uint64_t s_curr;
00067 
00068 public:
00069     Cache(uint64_t _capacity = INT_MAX):
00070         final(false), quit(false), new_data(false), input(NULL), s_max(_capacity), s_curr(0) {}
00071     virtual ~Cache() {}
00072 
00073     void setInputCache(Provider<Token> *p) { input = p; }
00074     uint64_t capacity() { return s_max; }
00075     uint64_t size() { return s_curr; }
00076     void setCapacity(uint64_t c) { s_max = c; }
00077 
00079     bool newData() {
00080         bool r = new_data.testAndSetOrdered(1, 0); //if changed is 1, r is true
00081         return r;
00082     }
00083 
00086     void flush() {
00087         //std::vector<Token *> tokens;
00088         {
00089             for(int i = 0; i < this->heap.size(); i++) {
00090                 Token *token = &(this->heap[i]);
00091                 //tokens.push_back(token);
00092                 s_curr -= drop(token);
00093                 //assert(!(token->count.load() >= Token::LOCKED));
00094                 if(final)
00095                     token->count.testAndSetOrdered(Token::READY, Token::CACHE);
00096                 input->heap.push(token);
00097             }
00098             this->heap.clear();
00099         }
00100         if(!s_curr == 0) {
00101             std::cerr << "Cache size after flush is not ZERO!\n";
00102             s_curr = 0;
00103         }
00104     }
00105 
00108     template <class FUNCTOR> void flush(FUNCTOR functor) {
00109         std::vector<Token *> tokens;
00110         {
00111             int count = 0;
00112             mt::mutexlocker locker(&(this->heap_lock));
00113             for(int k = 0; k < this->heap.size(); k++) {
00114                 Token *token = &this->heap[k];
00115                 if(functor(token)) { //drop it
00116                     tokens.push_back(token);
00117                     s_curr -= drop(token);
00118                     //assert(token->count.load() < Token::LOCKED);
00119                     if(final)
00120                         token->count.testAndSetOrdered(Token::READY, Token::CACHE);
00121                 } else
00122                     this->heap.at(count++) = token;
00123             }
00124             this->heap.resize(count);
00125             this->heap_dirty = true;
00126         }
00127         {
00128             mt::mutexlocker locker(&(input->heap_lock));
00129             for(unsigned int i = 0; i < tokens.size(); i++) {
00130                 input->heap.push(tokens[i]);
00131             }
00132         }
00133     }
00134 
00135     virtual void abort() {}
00136 
00137 protected:
00139     virtual int size(Token *token) = 0;
00141     virtual int get(Token *token) = 0;
00143     virtual int drop(Token *token) = 0;
00145 
00146 
00147 
00148 
00150     virtual void begin() {}
00151     virtual void middle() {}
00153     virtual void end() {}
00154 
00156     void run() {
00157         assert(input);
00158         /* basic operation of the cache:
00159           1) make room until eliminating an element would leave empty space.
00160           2) transfer first element of input_cache if
00161           cache has room OR first element in input has higher priority of last element */
00162         begin();
00163         while(!this->quit) {
00164             input->check_queue.enter();     //wait for cache below to load something or priorities to change
00165             if(this->quit) break;
00166 
00167             middle();
00168 
00169             if(unload() || load()) {
00170                 new_data.testAndSetOrdered(0, 1);  //if not changed, set as changed
00171                 input->check_queue.open();        //we signal ourselves to check again
00172                 cout << "loaded or unloaded\n";
00173             }
00174             input->check_queue.leave();
00175         }
00176         this->quit = false;                   //in case someone wants to restart;
00177         end();
00178     }
00179 
00180 
00181 
00185     bool unload() {
00186         Token *remove = NULL;
00187         //make room int the cache checking that:
00188         //1 we need to make room (capacity < current)
00189         if(size() > capacity()) {
00190             mt::mutexlocker locker(&(this->heap_lock));
00191 
00192             //2 we have some element not in the upper caches (heap.size()  > 0
00193             if(this->heap.size()) {
00194                 Token &last = this->heap.min();
00195                 int itemsize = size(&last);
00196 
00197                 //3 after removing the item, we are still full (avoids bouncing items)
00198                 if(size() - itemsize > capacity()) {
00199 
00200                     //4 item to remove is not locked. (only in last cache. you can't lock object otherwise)
00201                     if(!final) { //not final we can drop when we want
00202                         remove = this->heap.popMin();
00203                     } else {
00204                         last.count.testAndSetOrdered(Token::READY, Token::CACHE);
00205 #if(QT_VERSION < 0x050000)
00206                 int last_count = last.count;
00207 #else
00208                 int last_count = last.count.load();
00209 #endif
00210                         if(last_count <= Token::CACHE) { //was not locked and now can't be locked, remove it.
00211                             remove = this->heap.popMin();
00212                         } else { //last item is locked need to reorder stack
00213                             remove = this->heap.popMin();
00214                             this->heap.push(remove);
00215                             cout << "Reordering stack something (what?)\n";
00216                             return true;
00217                         }
00218                     }
00219                 }
00220             }
00221         }
00222 
00223         if(remove) {
00224             {
00225                 mt::mutexlocker input_locker(&(input->heap_lock));
00226                 int size = drop(remove);
00227                 assert(size >= 0);
00228                 s_curr -= size;
00229                 input->heap.push(remove);
00230             }
00231             return true;
00232         }
00233         return false;
00234     }
00235 
00237     bool load() {
00238         Token *insert = NULL;
00239         Token *last = NULL;              //we want to lock only one heap at once to avoid deadlocks.
00240 
00241         /* check wether we have room (curr < capacity) or heap is empty.
00242        empty heap is bad: we cannot drop anything to make room, and cache above has nothing to get.
00243        this should not happen if we set correct cache sizes, but if it happens.... */
00244         {
00245             mt::mutexlocker locker(&(this->heap_lock));
00246             this->rebuild();
00247             if(size() > capacity() && this->heap.size() > 0) {
00248                 last = &(this->heap.min()); //no room, set last so we might check for a swap.
00249             }
00250         }
00251 
00252         {
00253             mt::mutexlocker input_locker(&(input->heap_lock));
00254             input->rebuild();                                  //if dirty rebuild
00255             if(input->heap.size()) {                           //we need something in input to tranfer.
00256                 Token &first = input->heap.max();
00257 #if(QT_VERSION < 0x050000)
00258                 int first_count = first.count;
00259 #else
00260                 int first_count = first.count.load();
00261 #endif
00262                 if(first_count > Token::REMOVE &&
00263                         (!last || first.priority > last->priority)) { //if !last we already decided we want a transfer., otherwise check for a swap
00264                     insert = input->heap.popMax();                 //remove item from heap, while we transfer it.
00265                 }
00266             }
00267         }
00268 
00269         if(insert) {                                        //we want to fetch something
00270 
00271             int size = get(insert);
00272 
00273             if(size >= 0) {                                   //success
00274                 s_curr += size;
00275                 {
00276                     mt::mutexlocker locker(&(this->heap_lock));
00277                     if(final)
00278                         insert->count.ref();                       //now lock is 0 and can be locked
00279 
00280                     this->heap.push(insert);
00281                 }
00282                 this->check_queue.open();                      //we should signal the parent cache that we have a new item
00283                 return true;
00284 
00285             } else {                                         //failed transfer put it back, we will keep trying to transfer it...
00286                 mt::mutexlocker input_locker(&(input->heap_lock));
00287                 input->heap.push(insert);
00288                 return false;
00289             }
00290         }
00291         return false;
00292     }
00293 };
00294 
00295 } //namespace
00296 
00297 #endif // GCACHE_H


shape_reconstruction
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:29:21