我正在尝试编写一个简单的elixir实用程序脚本,该脚本将一些文本作为来自STDIN(即PostgreSQL转储)的输入,过滤该文本并将其输出到STDOUT以供后续命令使用:
pg_restore db-backup/big_dump.psql.gz | db_trimmer.exs | psql ...
我的脚本的第一个版本是删除转储复制数据的所有行(以COPY
开始,以\.
结尾):
COPY xx_table ... FROM stdin
4 33380 \N \N
4 33380 \N \N
\.
我的目标是控制该脚本使用的内存,因为转储可能非常大。因此,我开始使用Elixir Stream
模块和功能。我最后使用IO.stream
和Stream.transform
进行了第一个实现:
IO.stream(:stdio, :line)
|> Stream.transform(false, fn line, skipping ->
cond do
!skipping && String.starts_with?(line, "COPY") -> {[{true, line}], true}
skipping && line == "\\.\n" -> {[{true, line}], false}
true -> {[{skipping, line}], skipping}
end
end)
|> Stream.filter(fn {skipping, _} -> !skipping end)
|> Stream.map(fn {_, line} -> line end)
|> Stream.into(IO.stream(:stdio, :line))
|> Stream.run()
但是,当我在一个大型转储上运行此脚本时,我注意到,首先进程内存开始大量增长,然后稳定下来。但是随后过程虚拟内存继续增长...
我注意到一个更简单的脚本具有相同的行为:
IO.stream(:stdio, :line)
|> Stream.into(IO.stream(:stdio, :line))
|> Stream.run()
我想知道如何控制该脚本的内存使用(缓冲区,内存中的行数)?您对如何更好地实现此逻辑有建议吗?也许我应该放弃使用STDIN和STDOUT的想法,并在Elixir中使用所有管道?