Home | History | Annotate | Download | only in binary_parse
      1 // Copyright 2015 Google Inc.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 //
     15 ////////////////////////////////////////////////////////////////////////////////
     16 //
     17 // The cache layer works as follows:
     18 // The cache is implemented as a vector (of size 'cache_size') of shared
     19 // pointers to pages recently used. The least recently used page is stored
     20 // at the begining of the vector, the most recent at the end.
     21 
     22 #include "src/binary_parse/cached_paged_byte_array.h"
     23 
     24 #include <cstddef>
     25 
     26 namespace piex {
     27 namespace binary_parse {
     28 
     29 CachedPagedByteArray::CachedPagedByteArray(
     30     const PagedByteArray* paged_byte_array, size_t cache_size)
     31     : paged_byte_array_(paged_byte_array), cache_size_(cache_size) {}
     32 
     33 void CachedPagedByteArray::getPage(size_t page_index,
     34                                    const unsigned char** begin,
     35                                    const unsigned char** end,
     36                                    PagedByteArray::PagePtr* page) const {
     37   std::lock_guard<std::mutex> lock(mutex_);
     38   size_t cache_index;
     39   if (getFromCache(page_index, &cache_index)) {
     40     // Cache hit, retrieve the page from the cache.
     41     *begin = cached_pages_[cache_index].begin;
     42     *end = cached_pages_[cache_index].end;
     43     *page = cached_pages_[cache_index].page;
     44 
     45     // Remove the page to insert it at the end of the cache later.
     46     cached_pages_.erase(cached_pages_.begin() +
     47                         static_cast<std::ptrdiff_t>(cache_index));
     48   } else {
     49     // Cache miss, ask PagedByteArray to load the page.
     50     paged_byte_array_->getPage(page_index, begin, end, page);
     51 
     52     // If the cache is full, remove the first (least recently used) page.
     53     if (cached_pages_.size() >= cache_size_) {
     54       cached_pages_.erase(cached_pages_.begin());
     55     }
     56   }
     57 
     58   // Cache the most recently used page to the end of the vector.
     59   CachedPage cache_page;
     60   cache_page.index = page_index;
     61   cache_page.page = *page;
     62   cache_page.begin = *begin;
     63   cache_page.end = *end;
     64   cached_pages_.push_back(cache_page);
     65 }
     66 
     67 bool CachedPagedByteArray::getFromCache(size_t page_index,
     68                                         size_t* cache_index) const {
     69   for (size_t i = 0; i < cached_pages_.size(); ++i) {
     70     if (cached_pages_[i].index == page_index) {
     71       *cache_index = i;
     72       return true;
     73     }
     74   }
     75   return false;
     76 }
     77 
     78 }  // namespace binary_parse
     79 }  // namespace piex
     80