summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Bakken <luke@bakken.io>2022-07-15 13:49:52 -0700
committerMichael Klishin <michael@clojurewerkz.org>2022-07-19 12:22:48 +0400
commit414c8a0c186272af2b80f3676cf3d6aa0eb9df3e (patch)
tree0ab9044939fc23459a6b72c59eb0619b4bf88ed4
parentc7f46cec474c4e21b7134579902c5441e10f12b2 (diff)
downloadrabbitmq-server-git-414c8a0c186272af2b80f3676cf3d6aa0eb9df3e.tar.gz
Use win32sysinfo.exe to get disk and memory info
Follow-up to rabbitmq/rabbitmq-server#4140 In rabbitmq/rabbitmq-server#4328, I use Powershell to get disk info. This PR changes that to use the "included with OTP" win32sysinfo.exe Remove Powershell code Correctly parse the return value of os_mon_sysinfo:get_disk_info/0 (cherry picked from commit c0f2f6a23284e4565fbc4b51bc25bd72baf9a6bb)
-rw-r--r--deps/rabbit/src/rabbit_disk_monitor.erl161
-rw-r--r--deps/rabbit/src/rabbit_sup.erl5
2 files changed, 38 insertions, 128 deletions
diff --git a/deps/rabbit/src/rabbit_disk_monitor.erl b/deps/rabbit/src/rabbit_disk_monitor.erl
index 1fd561aba9..f984d96cca 100644
--- a/deps/rabbit/src/rabbit_disk_monitor.erl
+++ b/deps/rabbit/src/rabbit_disk_monitor.erl
@@ -62,16 +62,7 @@
%% on start-up
retries,
%% Interval between retries
- interval,
- %% Win32 specific state
- win32 = undefined
-}).
-
--record(win32state, {
- %% port of running powershell.exe
- port,
- %% monitor of the port
- mon_ref
+ interval
}).
%%----------------------------------------------------------------------------
@@ -174,17 +165,6 @@ handle_info(try_enable, #state{retries = Retries} = State) ->
handle_info(update, State) ->
{noreply, start_timer(internal_update(State))};
-% win32 process monitor message
-handle_info({'DOWN', MonRef, port, Port, _Info0},
- #state{win32 = #win32state{port = Port, mon_ref = MonRef}} = State0) ->
- {ok, State1} = enable_os(State0),
- {noreply, State1};
-
-% Note: we get this message if powershell dies or is killed. Since we're monitoring the port,
-% the DOWN message will take care of restarting it.
-handle_info({Port, {data, {noeol, _Line}}},
- #state{win32 = #win32state{port = Port}} = State) ->
- {noreply, State};
handle_info(Info, State) ->
rabbit_log:debug("~p unhandled msg: ~p", [?MODULE, Info]),
{noreply, State}.
@@ -234,7 +214,7 @@ set_disk_limits(State, Limit0) ->
internal_update(State = #state { limit = Limit,
dir = Dir,
alarmed = Alarmed}) ->
- CurrentFree = get_disk_free(Dir, State),
+ CurrentFree = get_disk_free(Dir),
NewAlarmed = CurrentFree < Limit,
case {Alarmed, NewAlarmed} of
{false, true} ->
@@ -249,21 +229,17 @@ internal_update(State = #state { limit = Limit,
ets:insert(?ETS_NAME, {disk_free, CurrentFree}),
State#state{alarmed = NewAlarmed, actual = CurrentFree}.
-get_disk_free(Dir, State) ->
- get_disk_free(Dir, os:type(), State).
+get_disk_free(Dir) ->
+ get_disk_free(Dir, os:type()).
-get_disk_free(Dir, {unix, Sun}, _State)
+get_disk_free(Dir, {unix, Sun})
when Sun =:= sunos; Sun =:= sunos4; Sun =:= solaris ->
Df = os:find_executable("df"),
parse_free_unix(run_cmd(Df ++ " -k " ++ Dir));
-get_disk_free(Dir, {unix, _}, _State) ->
+get_disk_free(Dir, {unix, _}) ->
Df = os:find_executable("df"),
parse_free_unix(run_cmd(Df ++ " -kP " ++ Dir));
-get_disk_free(Dir, {win32, _}, #state{win32 = undefined}) ->
- rabbit_log:debug("~p powershell not running, getting free space from Dir: ~p", [?MODULE, Dir]),
- {ok, Free} = win32_get_disk_free_dir(Dir),
- Free;
-get_disk_free(Dir, {win32, _}, #state{win32 = W32State}) ->
+get_disk_free(Dir, {win32, _}) ->
% Dir:
% "c:/Users/username/AppData/Roaming/RabbitMQ/db/rabbit2@username-z01-mnesia"
case win32_get_drive_letter(Dir) of
@@ -274,12 +250,26 @@ get_disk_free(Dir, {win32, _}, #state{win32 = W32State}) ->
{ok, Free} = win32_get_disk_free_dir(Dir),
Free;
DriveLetter ->
- case catch win32_get_disk_free_pwsh(DriveLetter, W32State) of
- {ok, Free1} -> Free1;
- PwshNotOk ->
- rabbit_log:error("could not determine disk free: ~p", [PwshNotOk]),
- exit(could_not_determine_disk_free)
- end
+ % Note: yes, "$ " is the $char sequence for an ASCII space
+ F = fun([D, $:, $\\, $ | _]) when D =:= DriveLetter ->
+ true;
+ (_) -> false
+ end,
+ % Note: we can use os_mon_sysinfo:get_disk_info/1 after the following is fixed:
+ % https://github.com/erlang/otp/issues/6156
+ [DriveInfoStr] = lists:filter(F, os_mon_sysinfo:get_disk_info()),
+
+ % Note: DriveInfoStr is in this format
+ % "C:\\ DRIVE_FIXED 720441434112 1013310287872 720441434112\n"
+ [DriveLetter, $:, $\\, $ | DriveInfo] = DriveInfoStr,
+
+ % https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdiskfreespaceexa
+ % lib/os_mon/c_src/win32sysinfo.c:
+ % if (fpGetDiskFreeSpaceEx(drive,&availbytes,&totbytes,&totbytesfree)){
+ % sprintf(answer,"%s DRIVE_FIXED %I64u %I64u %I64u\n",drive,availbytes,totbytes,totbytesfree);
+ ["DRIVE_FIXED", FreeBytesAvailableToCallerStr,
+ _TotalNumberOfBytesStr, _TotalNumberOfFreeBytesStr] = string:tokens(DriveInfo, " "),
+ list_to_integer(FreeBytesAvailableToCallerStr)
end.
parse_free_unix(Str) ->
@@ -291,29 +281,14 @@ parse_free_unix(Str) ->
_ -> exit({unparseable, Str})
end.
-win32_get_drive_letter([DriveLetter, $:, $/ | _]) when
- (DriveLetter >= $a andalso DriveLetter =< $z) orelse
- (DriveLetter >= $A andalso DriveLetter =< $Z) ->
+win32_get_drive_letter([DriveLetter, $:, $/ | _]) when (DriveLetter >= $a andalso DriveLetter =< $z) ->
+ % Note: os_mon_sysinfo returns drives with uppercase letters, so uppercase it here
+ DriveLetter - 32;
+win32_get_drive_letter([DriveLetter, $:, $/ | _]) when (DriveLetter >= $A andalso DriveLetter =< $Z) ->
DriveLetter;
win32_get_drive_letter(_) ->
error.
-win32_get_disk_free_pwsh(DriveLetter, #win32state{port = Port, mon_ref = MonRef}) when
- (DriveLetter >= $a andalso DriveLetter =< $z) orelse
- (DriveLetter >= $A andalso DriveLetter =< $Z) ->
- % DriveLetter $c
- Cmd = "(Get-PSDrive -Name " ++ [DriveLetter] ++ ").Free\n",
- true = erlang:port_command(Port, Cmd),
- case pwsh_receive(Port, Cmd) of
- {ok, PoshResult} ->
- {ok, list_to_integer(string:trim(PoshResult))};
- {error, _} = Error ->
- % Note: returning an error will cause the current process
- % to exit, so clean up here
- pwsh_cleanup(Port, MonRef),
- Error
- end.
-
win32_get_disk_free_dir(Dir) ->
%% On Windows, the Win32 API enforces a limit of 260 characters
%% (MAX_PATH). If we call `dir` with a path longer than that, it
@@ -376,49 +351,18 @@ interval(#state{limit = Limit,
enable(#state{retries = 0} = State) ->
State;
-enable(#state{dir = Dir, interval = Interval, limit = Limit, retries = Retries}
- = State0) ->
- {ok, State1} = enable_os(State0),
- case {catch get_disk_free(Dir, State1),
+enable(#state{dir = Dir, interval = Interval, limit = Limit, retries = Retries} = State) ->
+ case {catch get_disk_free(Dir),
vm_memory_monitor:get_total_memory()} of
{N1, N2} when is_integer(N1), is_integer(N2) ->
rabbit_log:info("Enabling free disk space monitoring", []),
- start_timer(set_disk_limits(State1, Limit));
+ start_timer(set_disk_limits(State, Limit));
Err ->
rabbit_log:info("Free disk space monitor encountered an error "
"(e.g. failed to parse output from OS tools): ~p, retries left: ~b",
[Err, Retries]),
erlang:send_after(Interval, self(), try_enable),
- State1#state{enabled = false}
- end.
-
-enable_os(State) ->
- enable_os(os:type(), State).
-
-enable_os({win32, _}, State) ->
- SystemRootDir = os:getenv("SystemRoot", "C:\\WINDOWS"),
- Pwsh = find_powershell(SystemRootDir),
- PwshArgs = ["-NonInteractive", "-NoProfile", "-NoLogo", "-InputFormat", "Text", "-WindowStyle", "Hidden"],
- % Note: 'hide' must be used or this will not work!
- PortOptions = [use_stdio, stderr_to_stdout, {cd, SystemRootDir}, {line, 512}, hide, {args, PwshArgs}],
- Port = erlang:open_port({spawn_executable, Pwsh}, PortOptions),
- MonRef = erlang:monitor(port, Port),
- W32State = #win32state{port = Port, mon_ref = MonRef},
- {ok, State#state{win32 = W32State}};
-enable_os(_, State) ->
- {ok, State}.
-
-find_powershell(SystemRootDir) ->
- case os:find_executable("pwsh.exe") of
- false ->
- case os:find_executable("powershell.exe") of
- false ->
- SystemRootDir ++ "\\system32\\WindowsPowerShell\\v1.0\\powershell.exe";
- Powershell ->
- Powershell
- end;
- Pwsh ->
- Pwsh
+ State#state{enabled = false}
end.
run_cmd(Cmd) ->
@@ -437,38 +381,3 @@ run_cmd(Cmd) ->
rabbit_log:error("Command timed out: '~s'", [Cmd]),
{error, timeout}
end.
-
-pwsh_receive(Port, Cmd0) ->
- Cmd1 = string:trim(Cmd0),
- FoundCmd = receive
- {Port, {data, {eol, Line0}}} ->
- Line1 = string:trim(Line0),
- case string:find(Line1, Cmd1, trailing) of
- nomatch ->
- {error, {unexpected, Line1}};
- _ ->
- ok
- end
- after 5000 ->
- {error, timeout}
- end,
- case FoundCmd of
- ok ->
- receive
- {Port, {data, {eol, Line2}}} ->
- {ok, Line2}
- after 5000 ->
- {error, timeout}
- end;
- Error ->
- Error
- end.
-
-pwsh_cleanup(Port, MonRef) ->
- try
- erlang:port_command(Port, "exit 0\n"),
- erlang:demonitor(MonRef),
- erlang:port_close(Port)
- catch Class:Error:Stacktrace ->
- rabbit_log:debug("~p ~p:~p:~p", [?MODULE, Class, Error, Stacktrace])
- end.
diff --git a/deps/rabbit/src/rabbit_sup.erl b/deps/rabbit/src/rabbit_sup.erl
index ec669dd1e0..cbcf0ca664 100644
--- a/deps/rabbit/src/rabbit_sup.erl
+++ b/deps/rabbit/src/rabbit_sup.erl
@@ -105,5 +105,6 @@ init([]) -> {ok, {{one_for_all, 0, 1}, []}}.
%%----------------------------------------------------------------------------
-child_reply({ok, _}) -> ok;
-child_reply(X) -> X.
+child_reply({ok, _, _}) -> ok;
+child_reply({ok, _}) -> ok;
+child_reply(X) -> X.