Skip to content

Commit f5660ca

Browse files
authored
CP-53843: reusable SM session (#7002)
Builds on top of #6991 The session reuse logic in `xapi_session.ml` does work in this usecase, sm calls are made with `pool=false`. So reimplement the logic so that we use a single session for `sm_exec` per sr. This is achieved by having a hashtable that maps SRs to a corresponding session. The session is created the first time a particular SR needs it and then get reused afterwards. The session gets recreated only if it becomes invalid. This should help the number of database calls during congestion times. Passes BVT and BST.
2 parents 1e887dd + 62ff51f commit f5660ca

3 files changed

Lines changed: 84 additions & 30 deletions

File tree

ocaml/xapi/sm_exec.ml

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ module E = Debug.Make (struct let name = "mscgen" end)
3030

3131
let cmd_name driver = sprintf "%s/%sSR" !Xapi_globs.sm_dir driver
3232

33-
let sm_username = "__sm__backend"
34-
3533
let with_dbg ~name ~dbg f =
3634
Debug_info.with_dbg ~module_name:"Sm_exec" ~name ~dbg f
3735

@@ -320,32 +318,6 @@ let methodResponse xml =
320318
(****************************************************************************************)
321319
(* Functions that actually execute the python backends *)
322320

323-
let with_session ~traceparent sr f =
324-
Server_helpers.exec_with_new_task "sm_exec"
325-
~origin:(Internal_Traced traceparent) (fun __context ->
326-
let create_session () =
327-
let host = !Xapi_globs.localhost_ref in
328-
let session =
329-
Xapi_session.login_no_password ~__context ~uname:None ~host
330-
~pool:false ~is_local_superuser:true ~subject:Ref.null
331-
~auth_user_sid:"" ~auth_user_name:sm_username ~rbac_permissions:[]
332-
in
333-
(* Give this session access to this particular SR *)
334-
Option.iter
335-
(fun sr ->
336-
Db.Session.add_to_other_config ~__context ~self:session
337-
~key:Xapi_globs._sm_session ~value:(Ref.string_of sr)
338-
)
339-
sr ;
340-
session
341-
in
342-
let destroy_session session_id =
343-
Xapi_session.destroy_db_session ~__context ~self:session_id
344-
in
345-
let session_id = create_session () in
346-
finally (fun () -> f session_id) (fun () -> destroy_session session_id)
347-
)
348-
349321
let exec_xmlrpc ~dbg ?context:_ ?(needs_session = true) (driver : string)
350322
(call : call) =
351323
with_dbg ~name:call.cmd ~dbg @@ fun di ->
@@ -467,8 +439,9 @@ let exec_xmlrpc ~dbg ?context:_ ?(needs_session = true) (driver : string)
467439
)
468440
in
469441
if needs_session then
470-
with_session ~traceparent:(Debug_info.span_of di) call.sr_ref
471-
(fun session_id -> do_call {call with session_ref= Some session_id}
442+
Xapi_session.SM.with_session ~traceparent:(Debug_info.span_of di)
443+
call.sr_ref (fun session_id ->
444+
do_call {call with session_ref= Some session_id}
472445
)
473446
else
474447
do_call call

ocaml/xapi/xapi_session.ml

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,3 +1589,77 @@ let create_from_db_file ~__context ~filename =
15891589
in
15901590
let db_ref = Some (Xapi_database.Db_ref.in_memory (Atomic.make db)) in
15911591
create_readonly_session ~__context ~uname:"db-from-file" ~db_ref
1592+
1593+
module SM = struct
1594+
let reusable_sessions : (string option, API.ref_session) Hashtbl.t =
1595+
Hashtbl.create 5
1596+
1597+
let sm_sessions_m = Mutex.create ()
1598+
1599+
let with_sm_sessions_lock f =
1600+
Xapi_stdext_threads.Threadext.Mutex.execute sm_sessions_m f
1601+
1602+
let finally = Xapi_stdext_pervasives.Pervasiveext.finally
1603+
1604+
let sm_username = "__sm__backend"
1605+
1606+
let is_valid_session ~__context session_id =
1607+
try
1608+
(* Call an API function to check the session is still valid *)
1609+
let rpc = Helpers.make_rpc ~__context in
1610+
ignore (Client.Pool.get_all ~rpc ~session_id) ;
1611+
true
1612+
with Api_errors.Server_error (err, _) ->
1613+
debug "%s: Invalid session: %s" __FUNCTION__ err ;
1614+
false
1615+
1616+
let session_access ~__context session sr =
1617+
(* Give this session access to this particular SR *)
1618+
Option.iter
1619+
(fun sr ->
1620+
Db.Session.add_to_other_config ~__context ~self:session
1621+
~key:Xapi_globs._sm_session ~value:(Ref.string_of sr)
1622+
)
1623+
sr
1624+
1625+
let create_session ~__context sr =
1626+
let host = !Xapi_globs.localhost_ref in
1627+
let session =
1628+
login_no_password ~__context ~uname:None ~host ~pool:false
1629+
~is_local_superuser:true ~subject:Ref.null ~auth_user_sid:""
1630+
~auth_user_name:sm_username ~rbac_permissions:[]
1631+
in
1632+
session_access ~__context session sr ;
1633+
session
1634+
1635+
let get_session ~__context sr =
1636+
let sr_key = Option.map Ref.string_of sr in
1637+
with_sm_sessions_lock (fun () ->
1638+
match Hashtbl.find_opt reusable_sessions sr_key with
1639+
| Some session when is_valid_session ~__context session ->
1640+
session
1641+
| Some _ ->
1642+
Hashtbl.remove reusable_sessions sr_key ;
1643+
let new_session = create_session ~__context sr in
1644+
Hashtbl.add reusable_sessions sr_key new_session ;
1645+
new_session
1646+
| None ->
1647+
let new_session = create_session ~__context sr in
1648+
Hashtbl.add reusable_sessions sr_key new_session ;
1649+
new_session
1650+
)
1651+
1652+
let with_session ~traceparent sr f =
1653+
Server_helpers.exec_with_new_task "sm_exec"
1654+
~origin:(Internal_Traced traceparent) (fun __context ->
1655+
if !Xapi_globs.reuse_pool_sessions then
1656+
let session_id = get_session ~__context sr in
1657+
f session_id
1658+
else
1659+
let session_id = create_session ~__context sr in
1660+
let destroy_session () =
1661+
destroy_db_session ~__context ~self:session_id
1662+
in
1663+
finally (fun () -> f session_id) destroy_session
1664+
)
1665+
end

ocaml/xapi/xapi_session.mli

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,10 @@ val set_local_auth_max_threads : int64 -> unit
112112
val set_ext_auth_max_threads : int64 -> unit
113113

114114
val clear_external_auth_cache : unit -> unit
115+
116+
module SM : sig
117+
val with_session :
118+
traceparent:Tracing.Span.t option
119+
-> [< Uuidx.all] Ref.t option
120+
-> (Uuidx.secret Ref.t -> 'a)
121+
-> 'a end

0 commit comments

Comments
 (0)