summaryrefslogtreecommitdiffstats
path: root/system/xen/xsa/xsa206-4.8-0009-oxenstored-discard-old-commit-history-on-txn-end.patch
diff options
context:
space:
mode:
Diffstat (limited to 'system/xen/xsa/xsa206-4.8-0009-oxenstored-discard-old-commit-history-on-txn-end.patch')
-rw-r--r--system/xen/xsa/xsa206-4.8-0009-oxenstored-discard-old-commit-history-on-txn-end.patch141
1 files changed, 141 insertions, 0 deletions
diff --git a/system/xen/xsa/xsa206-4.8-0009-oxenstored-discard-old-commit-history-on-txn-end.patch b/system/xen/xsa/xsa206-4.8-0009-oxenstored-discard-old-commit-history-on-txn-end.patch
new file mode 100644
index 0000000000..f1734c8375
--- /dev/null
+++ b/system/xen/xsa/xsa206-4.8-0009-oxenstored-discard-old-commit-history-on-txn-end.patch
@@ -0,0 +1,141 @@
+From 66bdbbc41a45d2bf59ddb4ff26c52c1cc546f720 Mon Sep 17 00:00:00 2001
+From: Thomas Sanders <thomas.sanders@citrix.com>
+Date: Thu, 23 Mar 2017 14:25:16 +0000
+Subject: [PATCH 09/15] oxenstored: discard old commit-history on txn end
+
+The history of commits is to be used for working out which historical
+commit(s) (including atomic writes) caused conflicts with a
+currently-failing commit of a transaction. Any commit that was made
+before the current transaction started cannot be relevant. Therefore
+we never need to keep history from before the start of the
+longest-running transaction that is open at any given time: whenever a
+transaction ends (with or without a commit) then if it was the
+longest-running open transaction we can delete history up until start
+of the the next-longest-running open transaction.
+
+Some transactions might stay open for a very long time, so if any
+transaction exceeds conflict_max_history_seconds then we remove it
+from consideration in this context, and will not guarantee to keep
+remembering about historical commits made during such a transaction.
+
+We implement this by keeping a list of all open transactions that have
+not been open too long. When a transaction ends, we remove it from the
+list, along with any that have been open longer than the maximum; then
+we delete any history from before the start of the longest-running
+transaction remaining in the list.
+
+Reported-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Thomas Sanders <thomas.sanders@citrix.com>
+Reviewed-by: Jonathan Davies <jonathan.davies@citrix.com>
+Reviewed-by: Christian Lindig <christian.lindig@citrix.com>
+---
+ tools/ocaml/xenstored/history.ml | 17 +++++++++++++++++
+ tools/ocaml/xenstored/process.ml | 4 ++--
+ tools/ocaml/xenstored/transaction.ml | 29 +++++++++++++++++++++++++----
+ 3 files changed, 44 insertions(+), 6 deletions(-)
+
+diff --git a/tools/ocaml/xenstored/history.ml b/tools/ocaml/xenstored/history.ml
+index e4b4d70..6f7a282 100644
+--- a/tools/ocaml/xenstored/history.ml
++++ b/tools/ocaml/xenstored/history.ml
+@@ -36,6 +36,23 @@ let mark_symbols () =
+ )
+ !history
+
++(* Keep only enough commit-history to protect the running transactions that we are still tracking *)
++(* There is scope for optimisation here, replacing List.filter with something more efficient,
++ * probably on a different list-like structure. *)
++let trim () =
++ history := match Transaction.oldest_short_running_transaction () with
++ | None -> [] (* We have no open transaction, so no history is needed *)
++ | Some (_, txn) -> (
++ (* keep records with finish_count recent enough to be relevant *)
++ List.filter (fun r -> r.finish_count > txn.Transaction.start_count) !history
++ )
++
++let end_transaction txn con tid commit =
++ let success = Connection.end_transaction con tid commit in
++ Transaction.end_transaction txn;
++ trim ();
++ success
++
+ let push (x: history_record) =
+ let dom = x.con.Connection.dom in
+ match dom with
+diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
+index b435a4a..6f4d118 100644
+--- a/tools/ocaml/xenstored/process.ml
++++ b/tools/ocaml/xenstored/process.ml
+@@ -313,7 +313,7 @@ let transaction_replay c t doms cons =
+ false
+ | Transaction.Full(id, oldstore, cstore) ->
+ let tid = Connection.start_transaction c cstore in
+- let new_t = Transaction.make tid cstore in
++ let new_t = Transaction.make ~internal:true tid cstore in
+ let con = sprintf "r(%d):%s" id (Connection.get_domstr c) in
+ let perform_exn (request, response) =
+ write_access_log ~ty:request.Packet.ty ~tid ~con ~data:request.Packet.data;
+@@ -370,7 +370,7 @@ let do_transaction_end con t domains cons data =
+ in
+ let success =
+ let commit = if commit then Some (fun con trans -> transaction_replay con trans domains cons) else None in
+- Connection.end_transaction con (Transaction.get_id t) commit in
++ History.end_transaction t con (Transaction.get_id t) commit in
+ if not success then
+ raise Transaction_again;
+ if commit then begin
+diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml
+index b1791b3..edd1178 100644
+--- a/tools/ocaml/xenstored/transaction.ml
++++ b/tools/ocaml/xenstored/transaction.ml
+@@ -87,12 +87,29 @@ type t = {
+ mutable read_lowpath: Store.Path.t option;
+ mutable write_lowpath: Store.Path.t option;
+ }
++let get_id t = match t.ty with No -> none | Full (id, _, _) -> id
+
+ let counter = ref 0L
+
+-let make id store =
++(* Scope for optimisation: different data-structure and functions to search/filter it *)
++let short_running_txns = ref []
++
++let oldest_short_running_transaction () =
++ let rec last = function
++ | [] -> None
++ | [x] -> Some x
++ | x :: xs -> last xs
++ in last !short_running_txns
++
++let end_transaction txn =
++ let cutoff = Unix.gettimeofday () -. !Define.conflict_max_history_seconds in
++ short_running_txns := List.filter
++ (function (start_time, tx) -> start_time >= cutoff && tx != txn)
++ !short_running_txns
++
++let make ?(internal=false) id store =
+ let ty = if id = none then No else Full(id, Store.copy store, store) in
+- {
++ let txn = {
+ ty = ty;
+ start_count = !counter;
+ store = if id = none then store else Store.copy store;
+@@ -101,9 +118,13 @@ let make id store =
+ operations = [];
+ read_lowpath = None;
+ write_lowpath = None;
+- }
++ } in
++ if id <> none && not internal then (
++ let now = Unix.gettimeofday () in
++ short_running_txns := (now, txn) :: !short_running_txns
++ );
++ txn
+
+-let get_id t = match t.ty with No -> none | Full (id, _, _) -> id
+ let get_store t = t.store
+ let get_paths t = t.paths
+
+--
+2.1.4
+