| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef GAPIR_RESOURCE_IN_MEMORY_CACHE_H |
| #define GAPIR_RESOURCE_IN_MEMORY_CACHE_H |
| |
| #include "resource_provider.h" |
| |
| #include <list> |
| #include <memory> |
| #include <string> |
| #include <unordered_map> |
| |
| namespace gapir { |
| |
| // Fixed size in-memory resource cache with ability to resize itself to an arbitrary size while |
| // minimizing invalidation of resources in the cache. It uses a ring buffer to store the cache and |
| // starts invalidating cache entries from the oldest to the newest when more space is required. |
| // |
| // The state of the cache is one of the following, using the implementation's iterators: |
| // | free space (empty cache, iterators are not valid) | |
| // | last and next block | free space (only one block is in the cache) | |
| // | free space | next block | occupied space | last block | padding | |
| // | occupied space | last block | free space | next block | occupied space | padding | |
| class ResourceInMemoryCache : public ResourceProvider { |
| public: |
| // Creates a new in-memory cache with the given fallback provider and base address. The initial |
| // cache size is 0 byte. |
| static std::unique_ptr<ResourceInMemoryCache> create( |
| std::unique_ptr<ResourceProvider> fallbackProvider, void* baseAddress); |
| |
| // If the requested resource is in the cache, copies it to the given memory address. If it |
| // isn't in the cache then requests it from the fallback provider and saves it into the cache |
| // if it fits (smaller than or equal to the size of the full cache). |
| bool get(const ResourceId& id, const ServerConnection& gazer, void* target, |
| uint32_t size) override; |
| |
| // Forwards the get request to the fallback provider without caching its result. |
| bool getUncached(const ResourceId& id, const ServerConnection& gazer, void* target, |
| uint32_t size) override; |
| |
| // No prefetching is done for this provider because of the limited size of the in memory cache |
| // and because there is no performance gain if we fetch multiple resources at the same time |
| // compared to the case when we fetch them one by one. The prefetch request is forwarded to the |
| // fallback provider for possible prefetching after filtering out resources already present in |
| // the cache. |
| bool prefetch(const ResourceList& resources, |
| const ServerConnection& gazer, void* buffer, uint32_t size) override; |
| |
| // Resizes the memory region used by the cache, modifying the end of its memory region. |
| // Resources falling outside of the new memory region will be evicted from the cache. |
| void updateSize(size_t newSize); |
| |
| private: |
| // Data structure representing a cached resource including its resource id and the offset of |
| // its memory location, relative to the base address of the cache. Begin is the offset of the |
| // first byte and end is the offset of the byte immediately after the end of the resource. The |
| // size of the resource is (end - begin). |
| struct Entry { |
| Entry(const ResourceId& id, size_t begin, size_t end); |
| |
| ResourceId id; |
| size_t begin; |
| size_t end; |
| }; |
| |
| ResourceInMemoryCache(std::unique_ptr<ResourceProvider> fallbackProvider, void* baseAddress); |
| |
| // Allocates the given amount of memory inside the resource cache for the resource with the |
| // provided resource id (required for later bookkeeping). If the allocation was successful (the |
| // requested memory is smaller then the size of the cache) then returns the base address of the |
| // allocated region, otherwise returns a null pointer, |
| uint8_t* allocateMemory(const std::string& id, size_t size); |
| |
| // Fallback provider for the case when the requested resource is not in the cache. |
| std::unique_ptr<ResourceProvider> mFallbackProvider; |
| |
| // The base address and the size of the memory used for caching. This memory region is owned by |
| // the memory manager class, not by the cache itself. |
| uint8_t* mBaseAddress; |
| size_t mSize; |
| |
| // The list of resources currently in the cache with their location. |
| std::list<Entry> mBlockList; |
| |
| // Iterator pointing to the last block inserted in the cache. |
| std::list<Entry>::iterator mLastBlock; |
| |
| // Iterator pointing to the next block to be removed from the cache. |
| std::list<Entry>::iterator mNextBlock; |
| |
| // The resources currently inside the cache. The value for each key is the offset of the |
| // resource inside the cache |
| std::unordered_map<ResourceId, size_t> mCache; |
| }; |
| |
| } // namespace gapir |
| |
| #endif // GAPIR_RESOURCE_IN_MEMORY_CACHE_H |