You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ko...@apache.org on 2020/01/06 18:27:17 UTC

[couchdb] 17/19: Enable users to bypass IOQ for certain IO classes

This is an automated email from the ASF dual-hosted git repository.

kocolosk pushed a commit to branch ioq-in-tree
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit e641a740978447f0b29785580e46d2e30e822001
Author: Adam Kocoloski <ko...@apache.org>
AuthorDate: Wed Dec 18 15:22:18 2019 -0500

    Enable users to bypass IOQ for certain IO classes
    
    This patch allows an administrator to configure a "bypass" which
    will cause a particular class of IO to be submitted directly to the
    file descriptor or OS process instead of going through the IO queueing
    mechanism. Installing a bypass can result in higher throughput and
    lower latency, at the expense of less control over the stability of the
    system.
    
    A bypass is configured via the `ioq.priority` configuration block:
    
    [ioq.bypass]
    read = true
    write = true
    compaction = false
    
    This configuration will cause user-submitted read IO to be submitted
    directly. At this time the following classes are available:
    
    - os_process
    - read
    - write
    - view_update
    - shard_sync
    - compaction
    
    This also expands the "compaction" queue to be a general-purpose
    "background" queue that handles IO for both compaction and internal
    replication (aka shard_sync). The other four classes are handled by the
    "interactive" queue. As before, the [ioq] ratio setting determines the
    likelihood that background IO will be selected ahead of interactive IO
    when both queues are non-empty.
---
 src/ioq.erl | 49 ++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 40 insertions(+), 9 deletions(-)

diff --git a/src/ioq.erl b/src/ioq.erl
index 9ca2656..81d94a3 100644
--- a/src/ioq.erl
+++ b/src/ioq.erl
@@ -26,7 +26,7 @@
     concurrency,
     ratio,
     interactive=queue:new(),
-    compaction=queue:new(),
+    background=queue:new(),
     running=[]
 }).
 
@@ -41,7 +41,38 @@
 start_link() ->
     gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
 
-call(Fd, Msg, Priority) ->
+call(Fd, Msg, Metadata) ->
+    Priority = io_class(Msg, Metadata),
+    case bypass(Priority) of
+        true ->
+            gen_server:call(Fd, Msg);
+        false ->
+            queued_call(Fd, Msg, Priority)
+    end.
+
+bypass(Priority) ->
+    config:get("ioq.bypass", atom_to_list(Priority)) =:= "true".
+
+io_class({prompt, _}, _) ->
+    os_process;
+io_class({data, _}, _) ->
+    os_process;
+io_class(_, {interactive, _}) ->
+    read;
+io_class(_, {db_update, _}) ->
+    write;
+io_class(_, {view_update, _, _}) ->
+    view_update;
+io_class(_, {internal_repl, _}) ->
+    shard_sync;
+io_class(_, {db_compact, _}) ->
+    compaction;
+io_class(_, {view_compact, _, _}) ->
+    compaction;
+io_class(_, _) ->
+    other.
+
+queued_call(Fd, Msg, Priority) ->
     Request = #request{fd=Fd, msg=Msg, priority=Priority, from=self()},
     try
         gen_server:call(?MODULE, Request, infinity)
@@ -107,10 +138,10 @@ code_change(_Vsn, State, _Extra) ->
 terminate(_Reason, _State) ->
     ok.
 
-enqueue_request(#request{priority={db_compact, _}}=Request, #state{}=State) ->
-    State#state{compaction=queue:in(Request, State#state.compaction)};
-enqueue_request(#request{priority={view_compact, _, _}}=Request, #state{}=State) ->
-    State#state{compaction=queue:in(Request, State#state.compaction)};
+enqueue_request(#request{priority=compaction}=Request, #state{}=State) ->
+    State#state{background=queue:in(Request, State#state.background)};
+enqueue_request(#request{priority=shard_sync}=Request, #state{}=State) ->
+    State#state{background=queue:in(Request, State#state.background)};
 enqueue_request(#request{}=Request, #state{}=State) ->
     State#state{interactive=queue:in(Request, State#state.interactive)}.
 
@@ -128,17 +159,17 @@ maybe_submit_request(State) ->
     State.
 
 make_next_request(#state{}=State) ->
-    case {queue:is_empty(State#state.compaction), queue:is_empty(State#state.interactive)} of
+    case {queue:is_empty(State#state.background), queue:is_empty(State#state.interactive)} of
         {true, true} ->
             State;
         {true, false} ->
             choose_next_request(#state.interactive, State);
         {false, true} ->
-            choose_next_request(#state.compaction, State);
+            choose_next_request(#state.background, State);
         {false, false} ->
             case couch_rand:uniform() < State#state.ratio of
                 true ->
-                    choose_next_request(#state.compaction, State);
+                    choose_next_request(#state.background, State);
                 false ->
                     choose_next_request(#state.interactive, State)
             end