1"use strict";(globalThis.webpackChunkcachelib=globalThis.webpackChunkcachelib||[]).push([[9377],{15680(e,t,a){a.r(t),a.d(t,{MDXContext:()=>c,MDXProvider:()=>u,mdx:()=>f,useMDXComponents:()=>m,withMDXComponents:()=>d});var n=a(96540);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(){return i=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n])}return e},i.apply(this,arguments)}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),a.push.apply(a,n)}return a}function l(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?o(Object(a),!0).forEach(function(t){r(e,t,a[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):o(Object(a)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))})}return e}function s(e,t){if(null==e)return{};var a,n,r=function(e,t){if(null==e)return{};var a,n,r={},i=Object.keys(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)a=i[n],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=n.createContext({}),d=function(e){return function(t){var a=m(t.components);return n.createElement(e,i({},t,{components:a}))}},m=function(e){var t=n.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},u=function(e){var t=m(e.components);return n.createElement(c.Provider,{value:t},e.children)},h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},p=n.forwardRef(function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,o=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=m(a),u=r,p=d["".concat(o,".").concat(u)]||d[u]||h[u]||i;return a?n.createElement(p,l(l({ref:t},c),{},{components:a})):n.createElement(p,l({ref:t},c))});function f(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=p;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:r,o[1]=l;for(var c=2;c<i;c++)o[c]=a[c];return n.createElement.apply(null,o)}return n.createElement.apply(null,a)}p.displayName="MDXCreateElement"},97398(e,t,a){a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var n=a(58168),r=(a(96540),a(15680));const i={id:"chained_items",title:"Chained items"},o=void 0,l={unversionedId:"Cache_Library_User_Guides/chained_items",id:"Cache_Library_User_Guides/chained_items",title:"Chained items",description:"The allocate() method allocates memory for data whose size is less than the maximum allocation size (default: 4MB). To cache data whose size exceeds maximum allocation size, use chained allocations.",source:"@site/docs/Cache_Library_User_Guides/chained_items.md",sourceDirName:"Cache_Library_User_Guides",slug:"/Cache_Library_User_Guides/chained_items",permalink:"/docs/Cache_Library_User_Guides/chained_items",draft:!1,editUrl:"https://github.com/facebook/CacheLib/edit/main/website/docs/Cache_Library_User_Guides/chained_items.md",tags:[],version:"current",frontMatter:{id:"chained_items",title:"Chained items"},sidebar:"userguideSidebar",previous:{title:"Configure HybridCache",permalink:"/docs/Cache_Library_User_Guides/Configure_HybridCache"},next:{title:"Compact cache",permalink:"/docs/Cache_Library_User_Guides/compact_cache"}},s={},c=[{value:"Chained allocations",id:"chained-allocations",level:2},{value:"Insertion order and read order",id:"insertion-order-and-read-order",level:2},{value:"Example: A custom data structure with a large data blob.",id:"example-a-custom-data-structure-with-a-large-data-blob",level:2}],d={toc:c};function m({components:e,...t}){return(0,r.mdx)("wrapper",(0,n.A)({},d,t,{components:e,mdxType:"MDXLayout"}),(0,r.mdx)("p",null,"The ",(0,r.mdx)("inlineCode",{parentName:"p"},"allocate()")," method allocates memory for data whose size is less than the maximum allocation size (default: 4MB). To cache data whose size exceeds maximum allocation size, use chained allocations.\nYou can also use chained allocations to extend your data's size gradually."),(0,r.mdx)("h2",{id:"chained-allocations"},"Chained allocations"),(0,r.mdx)("p",null,"When you call the the ",(0,r.mdx)("inlineCode",{parentName:"p"},"allocate()")," method to allocate memory for your data, your data's size must be less than the maximum slab size (4 MB):"),(0,r.mdx)("pre",null,(0,r.mdx)("code",{parentName:"pre",className:"language-cpp"},"template <typename CacheTrait>;
1\nclass CacheAllocator : public CacheBase {\n public:\n // Allocate memory of a specific size from cache.\n WriteHandle allocate(\n PoolId id,\n Key key,\n uint32_t size,\n uint32_t ttlSecs = 0,\n uint32_t creationTime = 0,\n );\n // ...\n};\n")),(0,r.mdx)("p",null,"For example:"),(0,r.mdx)("pre",null,(0,r.mdx)("code",{parentName:"pre",className:"language-cpp"},'string data("Hello world");\n\n// Allocate memory for the data.\nauto handle = cache->allocate(poolId, "key1", data.size());\n')),(0,r.mdx)("p",null,"The allocated memory can't be changed at runtime. To extend this memory, use chained allocations:"),(0,r.mdx)("ol",null,(0,r.mdx)("li",{parentName:"ol"},"Call the ",(0,r.mdx)("inlineCode",{parentName:"li"},"allocate()")," method to allocate memory for an item (the parent item)."),(0,r.mdx)("li",{parentName:"ol"},"Add chained items to the parent item. Call the ",(0,r.mdx)("inlineCode",{parentName:"li"},"allocateChainedItem()")," method to allocate memory for these chained items. A chained item doesn't have a key; thus you must use its parent item to access it.")),(0,r.mdx)("p",null,"The following is the declaration of the ",(0,r.mdx)("inlineCode",{parentName:"p"},"allocateChainedItem()")," method:"),(0,r.mdx)("pre",null,(0,r.mdx)("code",{parentName:"pre",className:"language-cpp"},"template <typename CacheTrait>;\nclass CacheAllocator : public CacheBase {\n public:\n WriteHandle allocateChainedItem(const ReadHandle& parent, uint32_t size);\n // ...\n};\n")),(0,r.mdx)("h2",{id:"insertion-order-and-read-order"},"Insertion order and read order"),(0,r.mdx)("p",null,"Chained items are inserted in LIFO order. When user reads through the chained item using the ChainedAllocs API. The iteration happens in LIFO order starting with the most recently inserted chained item until the chained item inserted first. When user uses ",(0,r.mdx)("inlineCode",{parentName:"p"},"convertToIOBuf")," API, it is in FIFO order starting with the parent, and end with the most recently inserted chained item."),(0,r.mdx)("p",null,"For example:"),(0,r.mdx)("pre",null,(0,r.mdx)("code",{parentName:"pre",className:"language-cpp"},'auto parent = cache->allocate(0, "test key", 0);\nfor (int i = 0; i < 3; i++) {\n auto child = cache->allocateChainedItem(parent, sizeof(int));\n *reinterpret_cast<int*>(child->getMemory()) = i;\n cache->addChainedItem(std::move(child));\n}\n\nauto chainedAllocs = cache->viewAsChainedAllocs(parent);\nfor (const auto& c : chainedAllocs.getChain()) {}\n// 3 -> 2 -> 1\n\nauto iobuf = cache->convertToIOBuf(std::move(parent));\n// parent -> 1 -> 2 -> 3\n')),(0,r.mdx)("h2",{id:"example-a-custom-data-structure-with-a-large-data-blob"},"Example: A custom data structure with a large data blob."),(0,r.mdx)("p",null,"Let's assume we have a data structure that represents a large cache payload."),(0,r.mdx)("pre",null,(0,r.mdx)("code",{parentName:"pre",className:"language-cpp"},"struct LargeUserData {\n uint64_t version;\n uint64_t timestamp;\n size_t length;\n int[] data;\n};\n")),(0,r.mdx)("p",null,"The following code breaks this large cache data and caches it using mulitple\nitems through ",(0,r.mdx)("inlineCode",{parentName:"p"},"ChainedItems"),"."),(0,r.mdx)("details",null," ",(0,r.mdx)("summary",null," Caching `LargeUserData` with chained items "),(0,r.mdx)("pre",null,(0,r.mdx)("code",{parentName:"pre",className:"language-cpp"},'std::unique_ptr<LargeUserData> userData = getLargeUserData();\n\nsize_t userDataSize = sizeof(LargeUserData) + sizeof(int) * userData->length;\n\n// For simplicity, we\'ll split the user data into 1MB chunks\nsize_t numChunks = userDataSize / (1024 * 1024);\n\nstruct CustomParentItem {\n size_t numChunks;\n void* dataPtr[]; // an array of pointers to the chunks\n};\n\nsize_t parentItemSize = sizeof(CustomParentItem) + numChunks * sizeof(void*);\n\n// for simplicity, assume this fits into 1MB\nassert(parentItemSize <(1024 * 1024));\n\nauto parentItemHandle =\n cache.allocate(defaultPool, "an item split into chunks", parentItemSize);
1\n\nCustomParentItem* parentItem =\n reinterpret_cast<CustomParentItem*>(parentItemHandle->getMemory());\n\n// Now split user data into chunks and cache them\nfor (size_t i = 0; i < numChunks; ++i) {\n size_t chunkSize = 1024 * 1024;\n auto chainedItemHandle =\n cache.allocateChainedItem(parentItemHandle, chunkSize);\n\n // For simplicity, assume we always have enough memory\n assert(chainedItemHandle != nullptr);\n\n // Compute user data offset and copy data over\n uint8_t* dataOffset =\n reinterpret_cast<uint8_t*>(userData->data) + chunkSize * i;\n std::memcpy(chainedItemHandle->getMemory(), dataOffset, chunkSize);\n\n // Add this chained item to the parent item\n cache.addChainedItem(parentItemHandle, std::move(chainedItemHandle));\n}\n\n// Now, make parent item visible to others\ncache.insert(parentItemHandle);\n'))))}m.isMDXComponent=!0}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.