aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/src/group.erl
diff options
context:
space:
mode:
authorFred Hebert <[email protected]>2017-04-22 17:39:08 -0400
committerFred Hebert <[email protected]>2017-05-17 07:53:01 -0400
commit4b9e1dd37f6e55ba1a04fad36d8ed3c0201b1942 (patch)
tree94c2e64f816f5c6fdd28dd4e9fd43957d288d1e5 /lib/kernel/src/group.erl
parented4d30888beb58c27f61dcf86384696cc221be35 (diff)
downloadotp-4b9e1dd37f6e55ba1a04fad36d8ed3c0201b1942.tar.gz
otp-4b9e1dd37f6e55ba1a04fad36d8ed3c0201b1942.tar.bz2
otp-4b9e1dd37f6e55ba1a04fad36d8ed3c0201b1942.zip
Add persistence to history of the non-legacy shell
This patch adds a mechanism by which shell history gets stored persistently on disk and gets loaded whenever a new shell session begins. The log files are added to the user's cache directory, with multiple files in it, although the location is configurable. All Erlang instances on a given host will share the same log file. There are two hook points in group.erl that are used: when instantiating the buffer, where we fetch from disk, and when adding a line to the buffer (gets stored). This allows all shell instances to use the same base set of lines when loaded, but to keep their history separate after the fact. As lines are added as you go, a new shell session (with ^G -> s -> c) will have access to previous sessions' lines. The implementation makes use of the disk_log library with a rotating log in order to store data, and allow automated repairs. By default, the feature is disabled and must be turned on through OTP environment variable part of the kernel application. The options include: | Option | Accepted values | Default | Description | | ------------------------ | ----------------- |---------- | -------------------- | | shell_history | enabled, disabled | disabled | turn feature on/off | | shell_history_path | any string | user cache| where to put files | | shell_history_file_bytes | 51200..N bytes | 512kb | max data size (>50kb)| | shell_history_drop | ["q().", ...] | [] | blacklisted lines | A version header is added to the disk_log configuration, allowing changes in the storage format to be enacted in the future (i.e. adding segmentation by node name in the same file, or encoding) without conflict. Log rotation is used with multiple log files to ensure proper enforcement of resizing without too much data loss. Because disk_log does not allow to just flush bits of content on rewrite (it truncates any full file), we instead use a wrap log and try to divide the configured size into up to 10 log files so that every time we rotate a log, we lose only 10% of the data. This remains true for corrupted files that cannot fully be repaired. This many-logs-based approach in turn forces the use of a minimal log size for the `shell_history_file_bytes` configuration, since it has to be divided by 10. The shell history is not loaded for the `user` process which, despite running the group.erl module, does not actually require history as it mostly just forwards IO protocol information.
Diffstat (limited to 'lib/kernel/src/group.erl')
-rw-r--r--lib/kernel/src/group.erl3
1 files changed, 2 insertions, 1 deletions
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index b5e73117dd..0eeaaad8d2 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -33,7 +33,7 @@ start(Drv, Shell, Options) ->
server(Drv, Shell, Options) ->
process_flag(trap_exit, true),
edlin:init(),
- put(line_buffer, proplists:get_value(line_buffer, Options, [])),
+ put(line_buffer, proplists:get_value(line_buffer, Options, group_history:load())),
put(read_mode, list),
put(user_drv, Drv),
put(expand_fun,
@@ -783,6 +783,7 @@ save_line_buffer("\n", Lines) ->
save_line_buffer(Line, [Line|_Lines]=Lines) ->
save_line_buffer(Lines);
save_line_buffer(Line, Lines) ->
+ group_history:add(Line),
save_line_buffer([Line|Lines]).
save_line_buffer(Lines) ->