1"use strict";(globalThis.webpackChunkatsf4g_co_docs||=[]).push([[155],{7841(e,r,t){t.r(r),t.d(r,{assets:()=>o,contentTitle:()=>i,default:()=>h,frontMatter:()=>a,metadata:()=>s,toc:()=>d});const s=JSON.parse('{"id":"architecture/router","title":"Router System","description":"The router system answers the question \\"which service instance owns this stateful object\\": objects (such as","source":"@site/i18n/en/docusaurus-plugin-content-docs/current/architecture/router.md","sourceDirName":"architecture","slug":"/architecture/router","permalink":"/en/architecture/router","draft":false,"unlisted":false,"editUrl":"https://github.com/atframework/atsf4g-co/edit/main/doc/docs/architecture/router.md","tags":[],"version":"current","frontMatter":{"title":"Router System"},"sidebar":"docs","previous":{"title":"RPC and Code Generation","permalink":"/en/architecture/rpc-codegen"},"next":{"title":"Data Layer","permalink":"/en/architecture/data-layer"}}');var n=t(6070),c=t(3797);const a={title:"Router System"},i="Router System (router)",o={},d=[{value:"Core Classes",id:"core-classes",level:2},{value:"Object Access",id:"object-access",level:2},{value:"Router Addressing and Migration",id:"router-addressing-and-migration",level:2},{value:"Message Flow",id:"message-flow",level:2}];function l(e){const r={code:"code",h1:"h1",h2:"h2",header:"header",li:"li",mermaid:"mermaid",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,c.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(r.header,{children:(0,n.jsx)(r.h1,{id:"router-system-router",children:"Router System (router)"})}),"\n",(0,n.jsx)(r.p,{children:'The router system answers the question "which service instance owns this stateful object": objects (such as\r\nplayers or teams) are routed by key to their owning instance, cached in memory, and periodically saved back.'}),"\n",(0,n.jsx)(r.h2,{id:"core-classes",children:"Core Classes"}),"\n",(0,n.jsxs)(r.table,{children:[(0,n.jsx)(r.thead,{children:(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.th,{children:"Class"}),(0,n.jsx)(r.th,{children:"Location"}),(0,n.jsx)(r.th,{children:"Responsibility"})]})}),(0,n.jsxs)(r.tbody,{children:[(0,n.jsxs)(r.tr,{children:[(0,n.jsxs)(r.td,{children:[(0,n.jsx)(r.code,{children:"router_object_base"})," / ",(0,n.jsx)(r.code,{children:"router_object<T>"})]}),(0,n.jsx)(r.td,{children:(0,n.jsx)(r.code,{children:"src/server_frame/router/"})}),(0,n.jsxs)(r.td,{children:["Router object base: ",(0,n.jsx)(r.code,{children:"pull_object"}),"/",(0,n.jsx)(r.code,{children:"save_object"})," (coroutine RPCs), TTL, degradation"]})]}),(0,n.jsxs)(r.tr,{children:[(0,n.jsxs)(r.td,{children:[(0,n.jsx)(r.code,{children:"router_manager_base"})," / ",(0,n.jsx)(r.code,{children:"router_manager<TCache, TObj, TPrivData>"})]}),(0,n.jsx)(r.td,{children:(0,n.jsx)(r.code,{children:"router/router_manager.h"})}),(0,n.jsxs)(r.td,{children:["Object manager: ",(0,n.jsx)(r.code,{children:"mutable_cache"}),"/",(0,n.jsx)(r.code,{children:"mutable_object"}),", event callbacks"]})]}),(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.td,{children:(0,n.jsx)(r.code,{children:"router_manager_set"})}),(0,n.jsx)(r.td,{children:(0,n.jsx)(r.code,{children:"router/router_manager_set.h"})}),(0,n.jsx)(r.td,{children:"Singleton: manages all managers by type_id, auto save/close/transfer timers, metrics"})]}),(0,n.jsxs)(r.tr,{children:[(0,n.jsxs)(r.td,{children:[(0,n.jsx)(r.code,{children:"router_player_cache"})," / ",(0,n.jsx)(r.code,{children:"router_player_manager"})]}),(0,n.jsx)(r.td,{children:(0,n.jsx)(r.code,{children:"router/router_player_*"})}),(0,n.jsxs)(r.td,{children:["Player routing specialization (",(0,n.jsx)(r.code,{children:"player_cache"})," object, ",(0,n.jsx)(r.code,{children:"pull_online_server"}),")"]})]})]})]}),"\n",(0,n.jsxs)(r.p,{children:["Object key = ",(0,n.jsx)(r.code,{children:"type_id + zone_id + object_id"}),"."]}),"\n",(0,n.jsx)(r.h2,{id:"object-access",children:"Object Access"}),"\n",(0,n.jsx)(r.pre,{children:(0,n.jsx)(r.code,{className:"language-cpp",children:"auto mgr = router_manager_set::me
1()->get_manager<MyManager>(type_id);\r\n// Pull the object (if not cached, loads from DB/source instance via the pull_object coroutine RPC)\r\nauto obj = RPC_AWAIT_TYPE_RESULT(mgr->mutable_object(ctx, zone_id, object_id));\r\n// After modification, mark dirty; task_action_auto_save_objects periodically saves back (save_object)\n"})}),"\n",(0,n.jsxs)(r.ul,{children:["\n",(0,n.jsxs)(r.li,{children:["IO for the same key is serialized through ",(0,n.jsx)(r.code,{children:"io_schedule_order_"})," to avoid concurrent read/write races;"]}),"\n",(0,n.jsxs)(r.li,{children:["Objects have TTL and degradation policies; objects not accessed for a long time are automatically closed\r\n(",(0,n.jsx)(r.code,{children:"router_close_manager_set"}),")."]}),"\n"]}),"\n",(0,n.jsx)(r.h2,{id:"router-addressing-and-migration",children:"Router Addressing and Migration"}),"\n",(0,n.jsxs)(r.ul,{children:["\n",(0,n.jsxs)(r.li,{children:["Addressing is ",(0,n.jsx)(r.strong,{children:"not consistent hashing"}),": ownership is determined by the DB route table plus online probing.\r\n",(0,n.jsx)(r.code,{children:"router_manager_base::send_msg"})," fills in the ",(0,n.jsx)(r.code,{children:"SSRouterHead"}),", resolves the target server via the route cache,\r\nand physical transmission still goes through ",(0,n.jsx)(r.code,{children:"ss_msg_dispatcher::send_to_proc"}),";"]}),"\n",(0,n.jsxs)(r.li,{children:["Migration: the ",(0,n.jsx)(r.code,{children:"router_transfer"})," / ",(0,n.jsx)(r.code,{children:"router_update_sync"})," RPCs of ",(0,n.jsx)(r.code,{children:"RouterService"})," (generated handlers in\r\n",(0,n.jsx)(r.code,{children:"router/handle_ss_rpc_routerservice.atfw.gen.*"}),"), together with ",(0,n.jsx)(r.code,{children:"task_action_router_transfer"})," /\r\n",(0,n.jsx)(r.code,{children:"task_action_router_update_sync"}),", transfer objects between instances and update the route table."]}),"\n"]}),"\n",(0,n.jsx)(r.h2,{id:"message-flow",children:"Message Flow"}),"\n",(0,n.jsx)(r.mermaid,{value:"sequenceDiagram\r\n participant A as Service instance A\r\n participant B as Owning instance B\r\n A->>B: SSRouterHead + business message (addressed via route table)\r\n B->>B: pull_object (when not cached)\r\n B->>B: task action processing\r\n B--\x3e>A: Response\r\n Note over B: task_action_auto_save_objects<br/>periodically save_object back to DB"})]})}function h(e={}){const{wrapper:r}={...(0,c.R)(),...e.components};return r?(0,n.jsx)(r,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}}}]);
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.