2015-03-31 07:46:03 +00:00
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
%%
|
|
|
|
%% Copyright (c) 2007-2015 Basho Technologies, Inc. All Rights Reserved.
|
|
|
|
%%
|
|
|
|
%% This file is provided to you under the Apache License,
|
|
|
|
%% Version 2.0 (the "License"); you may not use this file
|
|
|
|
%% except in compliance with the License. You may obtain
|
|
|
|
%% a copy of the License at
|
|
|
|
%%
|
|
|
|
%% http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
%%
|
|
|
|
%% Unless required by applicable law or agreed to in writing,
|
|
|
|
%% software distributed under the License is distributed on an
|
|
|
|
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
|
%% KIND, either express or implied. See the License for the
|
|
|
|
%% specific language governing permissions and limitations
|
|
|
|
%% under the License.
|
|
|
|
%%
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
2015-04-08 05:24:07 +00:00
|
|
|
%% @doc Erlang API for the Machi FLU TCP protocol version 1.
|
|
|
|
|
2015-03-31 07:46:03 +00:00
|
|
|
-module(machi_flu1_client).
|
|
|
|
|
|
|
|
-include("machi.hrl").
|
2015-04-03 03:33:47 +00:00
|
|
|
-include("machi_projection.hrl").
|
2015-03-31 07:46:03 +00:00
|
|
|
|
|
|
|
-export([
|
2015-04-03 03:33:47 +00:00
|
|
|
%% File API
|
2015-04-02 09:08:42 +00:00
|
|
|
append_chunk/4, append_chunk/5,
|
2015-04-02 11:31:10 +00:00
|
|
|
read_chunk/5, read_chunk/6,
|
2015-04-02 11:49:45 +00:00
|
|
|
checksum_list/3, checksum_list/4,
|
2015-04-02 12:01:48 +00:00
|
|
|
list_files/2, list_files/3,
|
2015-05-08 07:53:10 +00:00
|
|
|
wedge_status/1, wedge_status/2,
|
2015-04-03 03:33:47 +00:00
|
|
|
|
|
|
|
%% Projection API
|
2015-04-03 08:55:35 +00:00
|
|
|
get_latest_epoch/2, get_latest_epoch/3,
|
2015-04-03 09:37:09 +00:00
|
|
|
read_latest_projection/2, read_latest_projection/3,
|
2015-04-03 08:55:35 +00:00
|
|
|
read_projection/3, read_projection/4,
|
2015-04-03 03:33:47 +00:00
|
|
|
write_projection/3, write_projection/4,
|
2015-04-06 09:43:52 +00:00
|
|
|
get_all_projections/2, get_all_projections/3,
|
|
|
|
list_all_projections/2, list_all_projections/3,
|
2015-04-03 03:33:47 +00:00
|
|
|
|
|
|
|
%% Common API
|
2015-03-31 07:46:03 +00:00
|
|
|
quit/1
|
|
|
|
]).
|
|
|
|
%% For "internal" replication only.
|
|
|
|
-export([
|
2015-04-02 12:18:41 +00:00
|
|
|
write_chunk/5, write_chunk/6,
|
|
|
|
delete_migration/3, delete_migration/4,
|
|
|
|
trunc_hack/3, trunc_hack/4
|
2015-03-31 07:46:03 +00:00
|
|
|
]).
|
|
|
|
|
2015-04-02 03:38:12 +00:00
|
|
|
-type chunk() :: binary() | iolist(). % client can use either
|
|
|
|
-type chunk_csum() :: {file_offset(), chunk_size(), binary()}.
|
|
|
|
-type chunk_s() :: binary(). % server always uses binary()
|
2015-03-31 07:46:03 +00:00
|
|
|
-type chunk_pos() :: {file_offset(), chunk_size(), file_name_s()}.
|
|
|
|
-type chunk_size() :: non_neg_integer().
|
2015-05-08 10:07:57 +00:00
|
|
|
-type error_general() :: 'bad_arg' | 'wedged'.
|
2015-04-02 09:08:42 +00:00
|
|
|
-type epoch_csum() :: binary().
|
2015-04-06 09:43:52 +00:00
|
|
|
-type epoch_num() :: -1 | non_neg_integer().
|
2015-04-02 09:08:42 +00:00
|
|
|
-type epoch_id() :: {epoch_num(), epoch_csum()}.
|
2015-04-02 03:38:12 +00:00
|
|
|
-type file_info() :: {file_size(), file_name_s()}.
|
2015-03-31 07:46:03 +00:00
|
|
|
-type file_name() :: binary() | list().
|
|
|
|
-type file_name_s() :: binary(). % server reply
|
|
|
|
-type file_offset() :: non_neg_integer().
|
2015-04-02 03:38:12 +00:00
|
|
|
-type file_size() :: non_neg_integer().
|
2015-03-31 07:46:03 +00:00
|
|
|
-type file_prefix() :: binary() | list().
|
2015-04-03 03:33:47 +00:00
|
|
|
-type inet_host() :: inet:ip_address() | inet:hostname().
|
|
|
|
-type inet_port() :: inet:port_number().
|
|
|
|
-type projection() :: #projection_v1{}.
|
|
|
|
-type projection_type() :: 'public' | 'private'.
|
2015-03-31 07:46:03 +00:00
|
|
|
|
2015-04-02 11:49:45 +00:00
|
|
|
-export_type([epoch_id/0]).
|
|
|
|
|
2015-03-31 07:46:03 +00:00
|
|
|
%% @doc Append a chunk (binary- or iolist-style) of data to a file
|
|
|
|
%% with `Prefix'.
|
|
|
|
|
2015-04-02 09:08:42 +00:00
|
|
|
-spec append_chunk(port(), epoch_id(), file_prefix(), chunk()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
{ok, chunk_pos()} | {error, error_general()} | {error, term()}.
|
2015-04-02 09:08:42 +00:00
|
|
|
append_chunk(Sock, EpochID, Prefix, Chunk) ->
|
|
|
|
append_chunk2(Sock, EpochID, Prefix, Chunk).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
|
|
|
%% @doc Append a chunk (binary- or iolist-style) of data to a file
|
|
|
|
%% with `Prefix'.
|
|
|
|
|
2015-04-02 09:08:42 +00:00
|
|
|
-spec append_chunk(inet_host(), inet_port(),
|
|
|
|
epoch_id(), file_prefix(), chunk()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
{ok, chunk_pos()} | {error, error_general()} | {error, term()}.
|
2015-04-02 09:08:42 +00:00
|
|
|
append_chunk(Host, TcpPort, EpochID, Prefix, Chunk) ->
|
2015-03-31 07:46:03 +00:00
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
2015-04-02 09:08:42 +00:00
|
|
|
append_chunk2(Sock, EpochID, Prefix, Chunk)
|
2015-03-31 07:46:03 +00:00
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
|
|
|
%% @doc Read a chunk of data of size `Size' from `File' at `Offset'.
|
|
|
|
|
2015-04-02 11:31:10 +00:00
|
|
|
-spec read_chunk(port(), epoch_id(), file_name(), file_offset(), chunk_size()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
{ok, chunk_s()} |
|
|
|
|
{error, error_general() | 'no_such_file' | 'partial_read'} |
|
|
|
|
{error, term()}.
|
2015-04-02 11:31:10 +00:00
|
|
|
read_chunk(Sock, EpochID, File, Offset, Size)
|
2015-04-02 03:38:12 +00:00
|
|
|
when Offset >= ?MINIMUM_OFFSET, Size >= 0 ->
|
2015-04-02 11:31:10 +00:00
|
|
|
read_chunk2(Sock, EpochID, File, Offset, Size).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
|
|
|
%% @doc Read a chunk of data of size `Size' from `File' at `Offset'.
|
|
|
|
|
2015-04-02 11:31:10 +00:00
|
|
|
-spec read_chunk(inet_host(), inet_port(), epoch_id(),
|
|
|
|
file_name(), file_offset(), chunk_size()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
{ok, chunk_s()} |
|
|
|
|
{error, error_general() | 'no_such_file' | 'partial_read'} |
|
|
|
|
{error, term()}.
|
2015-04-02 11:31:10 +00:00
|
|
|
read_chunk(Host, TcpPort, EpochID, File, Offset, Size)
|
2015-04-02 03:38:12 +00:00
|
|
|
when Offset >= ?MINIMUM_OFFSET, Size >= 0 ->
|
2015-03-31 07:46:03 +00:00
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
2015-04-02 11:31:10 +00:00
|
|
|
read_chunk2(Sock, EpochID, File, Offset, Size)
|
2015-03-31 07:46:03 +00:00
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
|
|
|
%% @doc Fetch the list of chunk checksums for `File'.
|
|
|
|
|
2015-04-02 11:49:45 +00:00
|
|
|
-spec checksum_list(port(), epoch_id(), file_name()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
{ok, [chunk_csum()]} |
|
|
|
|
{error, error_general() | 'no_such_file' | 'partial_read'} |
|
|
|
|
{error, term()}.
|
2015-04-02 11:49:45 +00:00
|
|
|
checksum_list(Sock, EpochID, File) when is_port(Sock) ->
|
|
|
|
checksum_list2(Sock, EpochID, File).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
|
|
|
%% @doc Fetch the list of chunk checksums for `File'.
|
|
|
|
|
2015-04-02 11:49:45 +00:00
|
|
|
-spec checksum_list(inet_host(), inet_port(), epoch_id(), file_name()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
{ok, [chunk_csum()]} |
|
|
|
|
{error, error_general() | 'no_such_file'} | {error, term()}.
|
2015-04-02 11:49:45 +00:00
|
|
|
checksum_list(Host, TcpPort, EpochID, File) when is_integer(TcpPort) ->
|
2015-03-31 07:46:03 +00:00
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
2015-04-02 11:49:45 +00:00
|
|
|
checksum_list2(Sock, EpochID, File)
|
2015-03-31 07:46:03 +00:00
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
|
|
|
%% @doc Fetch the list of all files on the remote FLU.
|
|
|
|
|
2015-04-02 12:01:48 +00:00
|
|
|
-spec list_files(port(), epoch_id()) ->
|
2015-04-02 03:38:12 +00:00
|
|
|
{ok, [file_info()]} | {error, term()}.
|
2015-04-02 12:01:48 +00:00
|
|
|
list_files(Sock, EpochID) when is_port(Sock) ->
|
|
|
|
list2(Sock, EpochID).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
|
|
|
%% @doc Fetch the list of all files on the remote FLU.
|
|
|
|
|
2015-04-02 12:01:48 +00:00
|
|
|
-spec list_files(inet_host(), inet_port(), epoch_id()) ->
|
2015-04-02 03:38:12 +00:00
|
|
|
{ok, [file_info()]} | {error, term()}.
|
2015-04-02 12:01:48 +00:00
|
|
|
list_files(Host, TcpPort, EpochID) when is_integer(TcpPort) ->
|
2015-03-31 07:46:03 +00:00
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
2015-04-02 12:01:48 +00:00
|
|
|
list2(Sock, EpochID)
|
2015-03-31 07:46:03 +00:00
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
2015-05-08 07:53:10 +00:00
|
|
|
%% @doc Fetch the wedge status from the remote FLU.
|
|
|
|
|
|
|
|
-spec wedge_status(port()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
{ok, {boolean(), pv1_epoch()}} | {error, term()}.
|
2015-05-08 07:53:10 +00:00
|
|
|
|
|
|
|
wedge_status(Sock) when is_port(Sock) ->
|
|
|
|
wedge_status2(Sock).
|
|
|
|
|
|
|
|
%% @doc Fetch the wedge status from the remote FLU.
|
|
|
|
|
|
|
|
-spec wedge_status(inet_host(), inet_port()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
{ok, {boolean(), pv1_epoch()}} | {error, term()}.
|
2015-05-08 07:53:10 +00:00
|
|
|
wedge_status(Host, TcpPort) when is_integer(TcpPort) ->
|
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
|
|
|
wedge_status2(Sock)
|
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
2015-04-08 05:24:07 +00:00
|
|
|
%% @doc Get the latest epoch number + checksum from the FLU's projection store.
|
2015-04-03 08:55:35 +00:00
|
|
|
|
|
|
|
-spec get_latest_epoch(port(), projection_type()) ->
|
2015-04-06 06:49:47 +00:00
|
|
|
{ok, epoch_id()} | {error, term()}.
|
2015-04-03 08:55:35 +00:00
|
|
|
get_latest_epoch(Sock, ProjType)
|
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
|
|
|
get_latest_epoch2(Sock, ProjType).
|
|
|
|
|
2015-04-08 05:24:07 +00:00
|
|
|
%% @doc Get the latest epoch number + checksum from the FLU's projection store.
|
2015-04-03 08:55:35 +00:00
|
|
|
|
|
|
|
-spec get_latest_epoch(inet_host(), inet_port(),
|
|
|
|
projection_type()) ->
|
2015-04-06 06:49:47 +00:00
|
|
|
{ok, epoch_id()} | {error, term()}.
|
2015-04-03 08:55:35 +00:00
|
|
|
get_latest_epoch(Host, TcpPort, ProjType)
|
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
|
|
|
get_latest_epoch2(Sock, ProjType)
|
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
2015-04-08 05:24:07 +00:00
|
|
|
%% @doc Get the latest projection from the FLU's projection store for `ProjType'
|
2015-04-03 09:37:09 +00:00
|
|
|
|
|
|
|
-spec read_latest_projection(port(), projection_type()) ->
|
|
|
|
{ok, projection()} | {error, not_written} | {error, term()}.
|
|
|
|
read_latest_projection(Sock, ProjType)
|
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
|
|
|
read_latest_projection2(Sock, ProjType).
|
|
|
|
|
2015-04-08 05:24:07 +00:00
|
|
|
%% @doc Get the latest projection from the FLU's projection store for `ProjType'
|
2015-04-03 09:37:09 +00:00
|
|
|
|
|
|
|
-spec read_latest_projection(inet_host(), inet_port(),
|
|
|
|
projection_type()) ->
|
|
|
|
{ok, projection()} | {error, not_written} | {error, term()}.
|
|
|
|
read_latest_projection(Host, TcpPort, ProjType)
|
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
|
|
|
read_latest_projection2(Sock, ProjType)
|
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
2015-04-03 08:55:35 +00:00
|
|
|
%% @doc Read a projection `Proj' of type `ProjType'.
|
|
|
|
|
|
|
|
-spec read_projection(port(), projection_type(), epoch_num()) ->
|
2015-04-03 09:37:09 +00:00
|
|
|
{ok, projection()} | {error, written} | {error, term()}.
|
2015-04-03 08:55:35 +00:00
|
|
|
read_projection(Sock, ProjType, Epoch)
|
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
|
|
|
read_projection2(Sock, ProjType, Epoch).
|
|
|
|
|
|
|
|
%% @doc Read a projection `Proj' of type `ProjType'.
|
|
|
|
|
|
|
|
-spec read_projection(inet_host(), inet_port(),
|
|
|
|
projection_type(), epoch_num()) ->
|
2015-04-03 09:37:09 +00:00
|
|
|
{ok, projection()} | {error, written} | {error, term()}.
|
2015-04-03 08:55:35 +00:00
|
|
|
read_projection(Host, TcpPort, ProjType, Epoch)
|
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
|
|
|
read_projection2(Sock, ProjType, Epoch)
|
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
2015-04-03 03:33:47 +00:00
|
|
|
%% @doc Write a projection `Proj' of type `ProjType'.
|
|
|
|
|
|
|
|
-spec write_projection(port(), projection_type(), projection()) ->
|
|
|
|
'ok' | {error, written} | {error, term()}.
|
2015-04-03 08:10:52 +00:00
|
|
|
write_projection(Sock, ProjType, Proj)
|
|
|
|
when ProjType == 'public' orelse ProjType == 'private',
|
|
|
|
is_record(Proj, projection_v1) ->
|
2015-04-03 03:33:47 +00:00
|
|
|
write_projection2(Sock, ProjType, Proj).
|
|
|
|
|
|
|
|
%% @doc Write a projection `Proj' of type `ProjType'.
|
|
|
|
|
|
|
|
-spec write_projection(inet_host(), inet_port(),
|
|
|
|
projection_type(), projection()) ->
|
|
|
|
'ok' | {error, written} | {error, term()}.
|
2015-04-03 08:10:52 +00:00
|
|
|
write_projection(Host, TcpPort, ProjType, Proj)
|
|
|
|
when ProjType == 'public' orelse ProjType == 'private',
|
|
|
|
is_record(Proj, projection_v1) ->
|
2015-04-03 03:33:47 +00:00
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
|
|
|
write_projection2(Sock, ProjType, Proj)
|
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
2015-04-03 09:37:09 +00:00
|
|
|
%% @doc Get all projections from the FLU's projection store.
|
|
|
|
|
2015-04-06 09:43:52 +00:00
|
|
|
-spec get_all_projections(port(), projection_type()) ->
|
2015-04-03 09:37:09 +00:00
|
|
|
{ok, [projection()]} | {error, term()}.
|
2015-04-06 09:43:52 +00:00
|
|
|
get_all_projections(Sock, ProjType)
|
2015-04-03 09:37:09 +00:00
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
2015-04-06 09:43:52 +00:00
|
|
|
get_all_projections2(Sock, ProjType).
|
2015-04-03 09:37:09 +00:00
|
|
|
|
|
|
|
%% @doc Get all projections from the FLU's projection store.
|
|
|
|
|
2015-04-06 09:43:52 +00:00
|
|
|
-spec get_all_projections(inet_host(), inet_port(),
|
2015-04-03 09:37:09 +00:00
|
|
|
projection_type()) ->
|
|
|
|
{ok, [projection()]} | {error, term()}.
|
2015-04-06 09:43:52 +00:00
|
|
|
get_all_projections(Host, TcpPort, ProjType)
|
2015-04-03 09:37:09 +00:00
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
2015-04-06 09:43:52 +00:00
|
|
|
get_all_projections2(Sock, ProjType)
|
2015-04-03 09:37:09 +00:00
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
|
|
|
%% @doc Get all epoch numbers from the FLU's projection store.
|
|
|
|
|
2015-04-06 09:43:52 +00:00
|
|
|
-spec list_all_projections(port(), projection_type()) ->
|
2015-04-03 09:37:09 +00:00
|
|
|
{ok, [non_neg_integer()]} | {error, term()}.
|
2015-04-06 09:43:52 +00:00
|
|
|
list_all_projections(Sock, ProjType)
|
2015-04-03 09:37:09 +00:00
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
2015-04-06 09:43:52 +00:00
|
|
|
list_all_projections2(Sock, ProjType).
|
2015-04-03 09:37:09 +00:00
|
|
|
|
|
|
|
%% @doc Get all epoch numbers from the FLU's projection store.
|
|
|
|
|
2015-04-06 09:43:52 +00:00
|
|
|
-spec list_all_projections(inet_host(), inet_port(),
|
2015-04-03 09:37:09 +00:00
|
|
|
projection_type()) ->
|
|
|
|
{ok, [non_neg_integer()]} | {error, term()}.
|
2015-04-06 09:43:52 +00:00
|
|
|
list_all_projections(Host, TcpPort, ProjType)
|
2015-04-03 09:37:09 +00:00
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
2015-04-06 09:43:52 +00:00
|
|
|
list_all_projections2(Sock, ProjType)
|
2015-04-03 09:37:09 +00:00
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
2015-03-31 07:46:03 +00:00
|
|
|
%% @doc Quit & close the connection to remote FLU.
|
|
|
|
|
|
|
|
-spec quit(port()) ->
|
|
|
|
ok.
|
|
|
|
quit(Sock) when is_port(Sock) ->
|
|
|
|
catch (_ = gen_tcp:send(Sock, <<"QUIT\n">>)),
|
|
|
|
catch gen_tcp:close(Sock),
|
|
|
|
ok.
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
|
|
%% @doc Restricted API: Write a chunk of already-sequenced data to
|
|
|
|
%% `File' at `Offset'.
|
|
|
|
|
2015-04-02 12:18:41 +00:00
|
|
|
-spec write_chunk(port(), epoch_id(), file_name(), file_offset(), chunk()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
ok | {error, error_general()} | {error, term()}.
|
2015-04-02 12:18:41 +00:00
|
|
|
write_chunk(Sock, EpochID, File, Offset, Chunk)
|
2015-04-02 03:38:12 +00:00
|
|
|
when Offset >= ?MINIMUM_OFFSET ->
|
2015-04-02 12:18:41 +00:00
|
|
|
write_chunk2(Sock, EpochID, File, Offset, Chunk).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
|
|
|
%% @doc Restricted API: Write a chunk of already-sequenced data to
|
|
|
|
%% `File' at `Offset'.
|
|
|
|
|
2015-04-02 12:18:41 +00:00
|
|
|
-spec write_chunk(inet_host(), inet_port(),
|
|
|
|
epoch_id(), file_name(), file_offset(), chunk()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
ok | {error, error_general()} | {error, term()}.
|
2015-04-02 12:18:41 +00:00
|
|
|
write_chunk(Host, TcpPort, EpochID, File, Offset, Chunk)
|
2015-04-02 03:38:12 +00:00
|
|
|
when Offset >= ?MINIMUM_OFFSET ->
|
2015-03-31 07:46:03 +00:00
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
2015-04-02 12:18:41 +00:00
|
|
|
write_chunk2(Sock, EpochID, File, Offset, Chunk)
|
2015-03-31 07:46:03 +00:00
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
|
|
|
%% @doc Restricted API: Delete a file after it has been successfully
|
|
|
|
%% migrated.
|
|
|
|
|
2015-04-02 12:18:41 +00:00
|
|
|
-spec delete_migration(port(), epoch_id(), file_name()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
ok | {error, error_general() | 'no_such_file'} | {error, term()}.
|
2015-04-02 12:18:41 +00:00
|
|
|
delete_migration(Sock, EpochID, File) when is_port(Sock) ->
|
|
|
|
delete_migration2(Sock, EpochID, File).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
|
|
|
%% @doc Restricted API: Delete a file after it has been successfully
|
|
|
|
%% migrated.
|
|
|
|
|
2015-04-02 12:18:41 +00:00
|
|
|
-spec delete_migration(inet_host(), inet_port(), epoch_id(), file_name()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
ok | {error, error_general() | 'no_such_file'} | {error, term()}.
|
2015-04-02 12:18:41 +00:00
|
|
|
delete_migration(Host, TcpPort, EpochID, File) when is_integer(TcpPort) ->
|
2015-03-31 07:46:03 +00:00
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
2015-04-02 12:18:41 +00:00
|
|
|
delete_migration2(Sock, EpochID, File)
|
2015-03-31 07:46:03 +00:00
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
|
|
|
%% @doc Restricted API: Truncate a file after it has been successfully
|
|
|
|
%% erasure coded.
|
|
|
|
|
2015-04-02 12:18:41 +00:00
|
|
|
-spec trunc_hack(port(), epoch_id(), file_name()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
ok | {error, error_general() | 'no_such_file'} | {error, term()}.
|
2015-04-02 12:18:41 +00:00
|
|
|
trunc_hack(Sock, EpochID, File) when is_port(Sock) ->
|
|
|
|
trunc_hack2(Sock, EpochID, File).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
|
|
|
%% @doc Restricted API: Truncate a file after it has been successfully
|
|
|
|
%% erasure coded.
|
|
|
|
|
2015-04-02 12:18:41 +00:00
|
|
|
-spec trunc_hack(inet_host(), inet_port(), epoch_id(), file_name()) ->
|
2015-05-08 10:07:57 +00:00
|
|
|
ok | {error, error_general() | 'no_such_file'} | {error, term()}.
|
2015-04-02 12:18:41 +00:00
|
|
|
trunc_hack(Host, TcpPort, EpochID, File) when is_integer(TcpPort) ->
|
2015-03-31 07:46:03 +00:00
|
|
|
Sock = machi_util:connect(Host, TcpPort),
|
|
|
|
try
|
2015-04-02 12:18:41 +00:00
|
|
|
trunc_hack2(Sock, EpochID, File)
|
2015-03-31 07:46:03 +00:00
|
|
|
after
|
|
|
|
catch gen_tcp:close(Sock)
|
|
|
|
end.
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
2015-04-02 09:08:42 +00:00
|
|
|
append_chunk2(Sock, EpochID, Prefix0, Chunk0) ->
|
2015-04-06 09:43:52 +00:00
|
|
|
erase(bad_sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
try
|
|
|
|
%% TODO: add client-side checksum to the server's protocol
|
2015-04-08 05:24:07 +00:00
|
|
|
%% _ = machi_util:checksum_chunk(Chunk),
|
2015-03-31 07:46:03 +00:00
|
|
|
Prefix = machi_util:make_binary(Prefix0),
|
|
|
|
Chunk = machi_util:make_binary(Chunk0),
|
|
|
|
Len = iolist_size(Chunk0),
|
|
|
|
true = (Len =< ?MAX_CHUNK_SIZE),
|
2015-04-02 09:08:42 +00:00
|
|
|
{EpochNum, EpochCSum} = EpochID,
|
|
|
|
EpochIDRaw = <<EpochNum:(4*8)/big, EpochCSum/binary>>,
|
2015-03-31 07:46:03 +00:00
|
|
|
LenHex = machi_util:int_to_hexbin(Len, 32),
|
2015-04-02 09:08:42 +00:00
|
|
|
Cmd = [<<"A ">>, EpochIDRaw, LenHex, Prefix, 10],
|
2015-03-31 07:46:03 +00:00
|
|
|
ok = gen_tcp:send(Sock, [Cmd, Chunk]),
|
|
|
|
{ok, Line} = gen_tcp:recv(Sock, 0),
|
|
|
|
PathLen = byte_size(Line) - 3 - 16 - 1 - 1,
|
|
|
|
case Line of
|
|
|
|
<<"OK ", OffsetHex:16/binary, " ",
|
|
|
|
Path:PathLen/binary, _:1/binary>> ->
|
|
|
|
Offset = machi_util:hexstr_to_int(OffsetHex),
|
|
|
|
{ok, {Offset, Len, Path}};
|
|
|
|
<<"ERROR BAD-ARG", _/binary>> ->
|
|
|
|
{error, bad_arg};
|
2015-05-08 10:07:57 +00:00
|
|
|
<<"ERROR WEDGED", _/binary>> ->
|
|
|
|
{error, wedged};
|
2015-03-31 07:46:03 +00:00
|
|
|
<<"ERROR ", Rest/binary>> ->
|
|
|
|
{error, Rest}
|
|
|
|
end
|
|
|
|
catch
|
|
|
|
throw:Error ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
Error;
|
|
|
|
error:{badmatch,_}=BadMatch ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
{error, {badmatch, BadMatch, erlang:get_stacktrace()}}
|
|
|
|
end.
|
|
|
|
|
2015-04-02 11:31:10 +00:00
|
|
|
read_chunk2(Sock, EpochID, File0, Offset, Size) ->
|
2015-04-06 09:43:52 +00:00
|
|
|
erase(bad_sock),
|
|
|
|
try
|
|
|
|
{EpochNum, EpochCSum} = EpochID,
|
|
|
|
EpochIDRaw = <<EpochNum:(4*8)/big, EpochCSum/binary>>,
|
|
|
|
File = machi_util:make_binary(File0),
|
|
|
|
PrefixHex = machi_util:int_to_hexbin(Offset, 64),
|
|
|
|
SizeHex = machi_util:int_to_hexbin(Size, 32),
|
|
|
|
CmdLF = [$R, 32, EpochIDRaw, PrefixHex, SizeHex, File, 10],
|
|
|
|
ok = gen_tcp:send(Sock, CmdLF),
|
|
|
|
case gen_tcp:recv(Sock, 3) of
|
|
|
|
{ok, <<"OK\n">>} ->
|
|
|
|
{ok, _Chunk}=Res = gen_tcp:recv(Sock, Size),
|
|
|
|
Res;
|
|
|
|
{ok, Else} ->
|
|
|
|
{ok, OldOpts} = inet:getopts(Sock, [packet]),
|
|
|
|
ok = inet:setopts(Sock, [{packet, line}]),
|
|
|
|
{ok, Else2} = gen_tcp:recv(Sock, 0),
|
|
|
|
ok = inet:setopts(Sock, OldOpts),
|
|
|
|
case Else of
|
|
|
|
<<"ERA">> ->
|
|
|
|
{error, todo_erasure_coded}; %% escript_cc_parse_ec_info(Sock, Line, Else2);
|
|
|
|
<<"ERR">> ->
|
|
|
|
case Else2 of
|
|
|
|
<<"OR BAD-IO\n">> ->
|
|
|
|
{error, no_such_file};
|
|
|
|
<<"OR NOT-ERASURE\n">> ->
|
|
|
|
{error, no_such_file};
|
|
|
|
<<"OR BAD-ARG\n">> ->
|
|
|
|
{error, bad_arg};
|
|
|
|
<<"OR PARTIAL-READ\n">> ->
|
|
|
|
{error, partial_read};
|
2015-05-08 10:07:57 +00:00
|
|
|
<<"OR WEDGED", _/binary>> ->
|
|
|
|
{error, wedged};
|
2015-04-06 09:43:52 +00:00
|
|
|
_ ->
|
|
|
|
{error, Else2}
|
|
|
|
end;
|
|
|
|
_ ->
|
|
|
|
{error, {whaaa_todo, <<Else/binary, Else2/binary>>}}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
catch
|
|
|
|
throw:Error ->
|
|
|
|
put(bad_sock, Sock),
|
|
|
|
Error;
|
|
|
|
error:{badmatch,_}=BadMatch ->
|
|
|
|
put(bad_sock, Sock),
|
|
|
|
{error, {badmatch, BadMatch, erlang:get_stacktrace()}}
|
2015-03-31 07:46:03 +00:00
|
|
|
end.
|
|
|
|
|
2015-04-02 12:01:48 +00:00
|
|
|
list2(Sock, EpochID) ->
|
2015-03-31 07:46:03 +00:00
|
|
|
try
|
2015-04-02 12:01:48 +00:00
|
|
|
{EpochNum, EpochCSum} = EpochID,
|
|
|
|
EpochIDRaw = <<EpochNum:(4*8)/big, EpochCSum/binary>>,
|
|
|
|
ok = gen_tcp:send(Sock, [<<"L ">>, EpochIDRaw, <<"\n">>]),
|
2015-03-31 07:46:03 +00:00
|
|
|
ok = inet:setopts(Sock, [{packet, line}]),
|
2015-05-08 12:37:19 +00:00
|
|
|
case gen_tcp:recv(Sock, 0) of
|
|
|
|
{ok, <<"OK\n">>} ->
|
|
|
|
Res = list3(gen_tcp:recv(Sock, 0), Sock),
|
|
|
|
ok = inet:setopts(Sock, [{packet, raw}]),
|
|
|
|
{ok, Res};
|
|
|
|
{ok, <<"ERROR WEDGED\n">>} ->
|
|
|
|
{error, wedged};
|
|
|
|
{ok, <<"ERROR ", Rest/binary>>} ->
|
|
|
|
{error, Rest}
|
|
|
|
end
|
2015-03-31 07:46:03 +00:00
|
|
|
catch
|
|
|
|
throw:Error ->
|
|
|
|
Error;
|
|
|
|
error:{badmatch,_}=BadMatch ->
|
|
|
|
{error, {badmatch, BadMatch}}
|
|
|
|
end.
|
|
|
|
|
2015-04-02 12:01:48 +00:00
|
|
|
list3({ok, <<".\n">>}, _Sock) ->
|
2015-03-31 07:46:03 +00:00
|
|
|
[];
|
2015-04-02 12:01:48 +00:00
|
|
|
list3({ok, Line}, Sock) ->
|
2015-04-01 08:59:40 +00:00
|
|
|
FileLen = byte_size(Line) - 16 - 1 - 1,
|
|
|
|
<<SizeHex:16/binary, " ", File:FileLen/binary, _/binary>> = Line,
|
|
|
|
Size = machi_util:hexstr_to_int(SizeHex),
|
2015-04-02 12:01:48 +00:00
|
|
|
[{Size, File}|list3(gen_tcp:recv(Sock, 0), Sock)];
|
|
|
|
list3(Else, _Sock) ->
|
2015-03-31 07:46:03 +00:00
|
|
|
throw({server_protocol_error, Else}).
|
|
|
|
|
2015-05-08 07:53:10 +00:00
|
|
|
wedge_status2(Sock) ->
|
|
|
|
try
|
|
|
|
ok = gen_tcp:send(Sock, [<<"WEDGE-STATUS\n">>]),
|
|
|
|
ok = inet:setopts(Sock, [{packet, line}]),
|
|
|
|
{ok, <<"OK ",
|
|
|
|
BooleanHex:2/binary, " ",
|
|
|
|
EpochHex:8/binary, " ",
|
|
|
|
CSumHex:40/binary, "\n">>} = gen_tcp:recv(Sock, 0),
|
|
|
|
ok = inet:setopts(Sock, [{packet, raw}]),
|
|
|
|
Boolean = if BooleanHex == <<"00">> -> false;
|
|
|
|
BooleanHex == <<"01">> -> true
|
|
|
|
end,
|
|
|
|
Res = {Boolean, {machi_util:hexstr_to_int(EpochHex),
|
|
|
|
machi_util:hexstr_to_bin(CSumHex)}},
|
|
|
|
{ok, Res}
|
|
|
|
catch
|
|
|
|
throw:Error ->
|
|
|
|
Error;
|
|
|
|
error:{badmatch,_}=BadMatch ->
|
|
|
|
{error, {badmatch, BadMatch}}
|
|
|
|
end.
|
|
|
|
|
2015-04-02 11:49:45 +00:00
|
|
|
checksum_list2(Sock, EpochID, File) ->
|
2015-04-06 09:43:52 +00:00
|
|
|
erase(bad_sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
try
|
2015-04-02 11:49:45 +00:00
|
|
|
{EpochNum, EpochCSum} = EpochID,
|
|
|
|
EpochIDRaw = <<EpochNum:(4*8)/big, EpochCSum/binary>>,
|
|
|
|
ok = gen_tcp:send(Sock, [<<"C ">>, EpochIDRaw, File, <<"\n">>]),
|
2015-03-31 07:46:03 +00:00
|
|
|
ok = inet:setopts(Sock, [{packet, line}]),
|
|
|
|
case gen_tcp:recv(Sock, 0) of
|
|
|
|
{ok, <<"OK ", Rest/binary>> = Line} ->
|
|
|
|
put(status, ok), % may be unset later
|
|
|
|
RestLen = byte_size(Rest) - 1,
|
|
|
|
<<LenHex:RestLen/binary, _:1/binary>> = Rest,
|
|
|
|
<<Len:64/big>> = machi_util:hexstr_to_bin(LenHex),
|
|
|
|
ok = inet:setopts(Sock, [{packet, raw}]),
|
2015-04-01 08:59:40 +00:00
|
|
|
{ok, checksum_list_finish(checksum_list_fast(Sock, Len))};
|
2015-03-31 07:46:03 +00:00
|
|
|
{ok, <<"ERROR NO-SUCH-FILE", _/binary>>} ->
|
|
|
|
{error, no_such_file};
|
|
|
|
{ok, <<"ERROR BAD-ARG", _/binary>>} ->
|
|
|
|
{error, bad_arg};
|
2015-05-08 10:07:57 +00:00
|
|
|
{ok, <<"ERROR WEDGED", _/binary>>} ->
|
|
|
|
{error, wedged};
|
2015-03-31 07:46:03 +00:00
|
|
|
{ok, Else} ->
|
|
|
|
throw({server_protocol_error, Else})
|
|
|
|
end
|
|
|
|
catch
|
|
|
|
throw:Error ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
Error;
|
|
|
|
error:{badmatch,_}=BadMatch ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
{error, {badmatch, BadMatch}}
|
|
|
|
end.
|
|
|
|
|
|
|
|
checksum_list_fast(Sock, 0) ->
|
|
|
|
{ok, <<".\n">> = _Line} = gen_tcp:recv(Sock, 2),
|
|
|
|
[];
|
|
|
|
checksum_list_fast(Sock, Remaining) ->
|
|
|
|
Num = erlang:min(Remaining, 1024*1024),
|
|
|
|
{ok, Bytes} = gen_tcp:recv(Sock, Num),
|
|
|
|
[Bytes|checksum_list_fast(Sock, Remaining - byte_size(Bytes))].
|
|
|
|
|
2015-04-01 08:59:40 +00:00
|
|
|
checksum_list_finish(Chunks) ->
|
|
|
|
Bin = case Chunks of
|
|
|
|
[X] ->
|
|
|
|
X;
|
|
|
|
_ ->
|
|
|
|
iolist_to_binary(Chunks)
|
|
|
|
end,
|
|
|
|
[begin
|
|
|
|
CSumLen = byte_size(Line) - 16 - 1 - 8 - 1,
|
|
|
|
<<OffsetHex:16/binary, " ", SizeHex:8/binary, " ",
|
|
|
|
CSum:CSumLen/binary>> = Line,
|
|
|
|
{machi_util:hexstr_to_int(OffsetHex),
|
|
|
|
machi_util:hexstr_to_int(SizeHex),
|
|
|
|
machi_util:hexstr_to_bin(CSum)}
|
|
|
|
end || Line <- re:split(Bin, "\n", [{return, binary}]),
|
|
|
|
Line /= <<>>].
|
2015-03-31 07:46:03 +00:00
|
|
|
|
2015-04-02 12:18:41 +00:00
|
|
|
write_chunk2(Sock, EpochID, File0, Offset, Chunk0) ->
|
2015-04-06 09:43:52 +00:00
|
|
|
erase(bad_sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
try
|
2015-04-02 12:18:41 +00:00
|
|
|
{EpochNum, EpochCSum} = EpochID,
|
|
|
|
EpochIDRaw = <<EpochNum:(4*8)/big, EpochCSum/binary>>,
|
2015-03-31 07:46:03 +00:00
|
|
|
%% TODO: add client-side checksum to the server's protocol
|
2015-04-08 05:24:07 +00:00
|
|
|
%% _ = machi_util:checksum_chunk(Chunk),
|
2015-03-31 07:46:03 +00:00
|
|
|
File = machi_util:make_binary(File0),
|
|
|
|
true = (Offset >= ?MINIMUM_OFFSET),
|
|
|
|
OffsetHex = machi_util:int_to_hexbin(Offset, 64),
|
|
|
|
Chunk = machi_util:make_binary(Chunk0),
|
|
|
|
Len = iolist_size(Chunk0),
|
|
|
|
true = (Len =< ?MAX_CHUNK_SIZE),
|
|
|
|
LenHex = machi_util:int_to_hexbin(Len, 32),
|
2015-04-02 12:18:41 +00:00
|
|
|
Cmd = [<<"W-repl ">>, EpochIDRaw, OffsetHex,
|
|
|
|
LenHex, File, <<"\n">>],
|
2015-03-31 07:46:03 +00:00
|
|
|
ok = gen_tcp:send(Sock, [Cmd, Chunk]),
|
|
|
|
{ok, Line} = gen_tcp:recv(Sock, 0),
|
|
|
|
PathLen = byte_size(Line) - 3 - 16 - 1 - 1,
|
|
|
|
case Line of
|
|
|
|
<<"OK\n">> ->
|
|
|
|
ok;
|
|
|
|
<<"ERROR BAD-ARG", _/binary>> ->
|
|
|
|
{error, bad_arg};
|
2015-05-08 10:07:57 +00:00
|
|
|
<<"ERROR WEDGED", _/binary>> ->
|
|
|
|
{error, wedged};
|
2015-03-31 07:46:03 +00:00
|
|
|
<<"ERROR ", _/binary>>=Else ->
|
|
|
|
{error, {server_said, Else}}
|
|
|
|
end
|
|
|
|
catch
|
|
|
|
throw:Error ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
Error;
|
|
|
|
error:{badmatch,_}=BadMatch ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
{error, {badmatch, BadMatch, erlang:get_stacktrace()}}
|
|
|
|
end.
|
|
|
|
|
2015-04-02 12:18:41 +00:00
|
|
|
delete_migration2(Sock, EpochID, File) ->
|
2015-04-06 09:43:52 +00:00
|
|
|
erase(bad_sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
try
|
2015-04-02 12:18:41 +00:00
|
|
|
{EpochNum, EpochCSum} = EpochID,
|
|
|
|
EpochIDRaw = <<EpochNum:(4*8)/big, EpochCSum/binary>>,
|
|
|
|
Cmd = [<<"DEL-migration ">>, EpochIDRaw, File, <<"\n">>],
|
|
|
|
ok = gen_tcp:send(Sock, Cmd),
|
2015-03-31 07:46:03 +00:00
|
|
|
ok = inet:setopts(Sock, [{packet, line}]),
|
|
|
|
case gen_tcp:recv(Sock, 0) of
|
|
|
|
{ok, <<"OK\n">>} ->
|
|
|
|
ok;
|
|
|
|
{ok, <<"ERROR NO-SUCH-FILE", _/binary>>} ->
|
|
|
|
{error, no_such_file};
|
|
|
|
{ok, <<"ERROR BAD-ARG", _/binary>>} ->
|
|
|
|
{error, bad_arg};
|
2015-05-08 10:07:57 +00:00
|
|
|
{ok, <<"ERROR WEDGED", _/binary>>} ->
|
|
|
|
{error, wedged};
|
2015-03-31 07:46:03 +00:00
|
|
|
{ok, Else} ->
|
|
|
|
throw({server_protocol_error, Else})
|
|
|
|
end
|
|
|
|
catch
|
|
|
|
throw:Error ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
Error;
|
|
|
|
error:{badmatch,_}=BadMatch ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
{error, {badmatch, BadMatch}}
|
|
|
|
end.
|
|
|
|
|
2015-04-02 12:18:41 +00:00
|
|
|
trunc_hack2(Sock, EpochID, File) ->
|
2015-04-06 09:43:52 +00:00
|
|
|
erase(bad_sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
try
|
2015-04-02 12:18:41 +00:00
|
|
|
{EpochNum, EpochCSum} = EpochID,
|
|
|
|
EpochIDRaw = <<EpochNum:(4*8)/big, EpochCSum/binary>>,
|
|
|
|
Cmd = [<<"TRUNC-hack--- ">>, EpochIDRaw, File, <<"\n">>],
|
|
|
|
ok = gen_tcp:send(Sock, Cmd),
|
2015-03-31 07:46:03 +00:00
|
|
|
ok = inet:setopts(Sock, [{packet, line}]),
|
|
|
|
case gen_tcp:recv(Sock, 0) of
|
|
|
|
{ok, <<"OK\n">>} ->
|
|
|
|
ok;
|
|
|
|
{ok, <<"ERROR NO-SUCH-FILE", _/binary>>} ->
|
|
|
|
{error, no_such_file};
|
|
|
|
{ok, <<"ERROR BAD-ARG", _/binary>>} ->
|
|
|
|
{error, bad_arg};
|
2015-05-08 10:07:57 +00:00
|
|
|
{ok, <<"ERROR WEDGED", _/binary>>} ->
|
|
|
|
{error, wedged};
|
2015-03-31 07:46:03 +00:00
|
|
|
{ok, Else} ->
|
|
|
|
throw({server_protocol_error, Else})
|
|
|
|
end
|
|
|
|
catch
|
|
|
|
throw:Error ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
Error;
|
|
|
|
error:{badmatch,_}=BadMatch ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
2015-03-31 07:46:03 +00:00
|
|
|
{error, {badmatch, BadMatch}}
|
|
|
|
end.
|
2015-04-03 03:33:47 +00:00
|
|
|
|
2015-04-03 08:55:35 +00:00
|
|
|
get_latest_epoch2(Sock, ProjType) ->
|
|
|
|
ProjCmd = {get_latest_epoch, ProjType},
|
|
|
|
do_projection_common(Sock, ProjCmd).
|
|
|
|
|
2015-04-03 09:37:09 +00:00
|
|
|
read_latest_projection2(Sock, ProjType) ->
|
|
|
|
ProjCmd = {read_latest_projection, ProjType},
|
|
|
|
do_projection_common(Sock, ProjCmd).
|
|
|
|
|
2015-04-03 08:55:35 +00:00
|
|
|
read_projection2(Sock, ProjType, Epoch) ->
|
|
|
|
ProjCmd = {read_projection, ProjType, Epoch},
|
|
|
|
do_projection_common(Sock, ProjCmd).
|
|
|
|
|
2015-04-03 03:33:47 +00:00
|
|
|
write_projection2(Sock, ProjType, Proj) ->
|
2015-04-03 08:55:35 +00:00
|
|
|
ProjCmd = {write_projection, ProjType, Proj},
|
|
|
|
do_projection_common(Sock, ProjCmd).
|
2015-04-03 09:37:09 +00:00
|
|
|
|
2015-04-06 09:43:52 +00:00
|
|
|
get_all_projections2(Sock, ProjType) ->
|
|
|
|
ProjCmd = {get_all_projections, ProjType},
|
2015-04-03 09:37:09 +00:00
|
|
|
do_projection_common(Sock, ProjCmd).
|
|
|
|
|
2015-04-06 09:43:52 +00:00
|
|
|
list_all_projections2(Sock, ProjType) ->
|
|
|
|
ProjCmd = {list_all_projections, ProjType},
|
2015-04-03 09:37:09 +00:00
|
|
|
do_projection_common(Sock, ProjCmd).
|
2015-04-03 03:33:47 +00:00
|
|
|
|
|
|
|
do_projection_common(Sock, ProjCmd) ->
|
2015-04-06 09:43:52 +00:00
|
|
|
erase(bad_sock),
|
2015-04-03 03:33:47 +00:00
|
|
|
try
|
|
|
|
ProjCmdBin = term_to_binary(ProjCmd),
|
|
|
|
Len = iolist_size(ProjCmdBin),
|
|
|
|
true = (Len =< ?MAX_CHUNK_SIZE),
|
|
|
|
LenHex = machi_util:int_to_hexbin(Len, 32),
|
|
|
|
Cmd = [<<"PROJ ">>, LenHex, <<"\n">>],
|
|
|
|
ok = gen_tcp:send(Sock, [Cmd, ProjCmdBin]),
|
2015-04-03 08:55:35 +00:00
|
|
|
ok = inet:setopts(Sock, [{packet, line}]),
|
2015-04-03 03:33:47 +00:00
|
|
|
{ok, Line} = gen_tcp:recv(Sock, 0),
|
|
|
|
case Line of
|
2015-04-03 08:55:35 +00:00
|
|
|
<<"OK ", ResLenHex:8/binary, "\n">> ->
|
|
|
|
ResLen = machi_util:hexstr_to_int(ResLenHex),
|
|
|
|
ok = inet:setopts(Sock, [{packet, raw}]),
|
|
|
|
{ok, ResBin} = gen_tcp:recv(Sock, ResLen),
|
|
|
|
ok = inet:setopts(Sock, [{packet, line}]),
|
|
|
|
binary_to_term(ResBin);
|
2015-04-03 03:33:47 +00:00
|
|
|
Else ->
|
|
|
|
{error, Else}
|
|
|
|
end
|
|
|
|
catch
|
|
|
|
throw:Error ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
2015-04-03 03:33:47 +00:00
|
|
|
Error;
|
|
|
|
error:{badmatch,_}=BadMatch ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
2015-04-03 03:33:47 +00:00
|
|
|
{error, {badmatch, BadMatch, erlang:get_stacktrace()}}
|
|
|
|
end.
|