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-05-20 02:11:54 +00:00
|
|
|
%%
|
|
|
|
%% This client API handles low-level PDU serialization/deserialization
|
|
|
|
%% and low-level TCP session management, e.g. open, receive, write,
|
|
|
|
%% close. The API for higher-level session management and Machi state
|
|
|
|
%% management can be found in {@link machi_proxy_flu1_client} and
|
|
|
|
%% {@link machi_cr_client}.
|
|
|
|
%%
|
2015-06-30 10:04:23 +00:00
|
|
|
%% For the moment, this module implements a Protocol Buffers-based
|
2015-05-20 02:11:54 +00:00
|
|
|
%% protocol as the sole supported access method to the server,
|
|
|
|
%% sequencer, and projection store. Conceptually, those three
|
|
|
|
%% services are independent and ought to have their own protocols. As
|
|
|
|
%% a practical matter, there is no need for wire protocol
|
|
|
|
%% compatibility. Furthermore, from the perspective of failure
|
|
|
|
%% detection, it is very convenient that all three FLU-related
|
|
|
|
%% services are accessed using the same single TCP port.
|
2015-06-30 10:04:23 +00:00
|
|
|
%%
|
|
|
|
%% TODO This EDoc was written first, and the EDoc and also `-type' and
|
|
|
|
%% `-spec' definitions for {@link machi_proxy_flu1_client} and {@link
|
|
|
|
%% machi_cr_client} must be improved.
|
2015-04-08 05:24:07 +00:00
|
|
|
|
2015-03-31 07:46:03 +00:00
|
|
|
-module(machi_flu1_client).
|
|
|
|
|
|
|
|
-include("machi.hrl").
|
2015-06-26 07:25:12 +00:00
|
|
|
-include("machi_pb.hrl").
|
2015-04-03 03:33:47 +00:00
|
|
|
-include("machi_projection.hrl").
|
2015-03-31 07:46:03 +00:00
|
|
|
|
2015-07-16 07:25:38 +00:00
|
|
|
-ifdef(PULSE).
|
|
|
|
-compile({parse_transform, pulse_instrument}).
|
|
|
|
-include_lib("pulse_otp/include/pulse_otp.hrl").
|
|
|
|
-endif.
|
|
|
|
|
2015-05-18 10:06:06 +00:00
|
|
|
-define(HARD_TIMEOUT, 2500).
|
|
|
|
|
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-05-17 05:10:42 +00:00
|
|
|
append_chunk_extra/5, append_chunk_extra/6,
|
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-05-18 10:06:06 +00:00
|
|
|
get_latest_epochid/2, get_latest_epochid/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-07-02 19:30:05 +00:00
|
|
|
kick_projection_reaction/2, kick_projection_reaction/3,
|
2015-04-03 03:33:47 +00:00
|
|
|
|
|
|
|
%% Common API
|
2015-06-26 07:25:12 +00:00
|
|
|
echo/2, echo/3,
|
2015-05-17 07:18:30 +00:00
|
|
|
quit/1,
|
|
|
|
|
|
|
|
%% Connection management API
|
|
|
|
connected_p/1, connect/1, disconnect/1
|
2015-03-31 07:46:03 +00:00
|
|
|
]).
|
|
|
|
%% 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-06-19 07:04:34 +00:00
|
|
|
-type port_wrap() :: {w,atom(),term()}.
|
2015-04-02 11:49:45 +00:00
|
|
|
|
2015-03-31 07:46:03 +00:00
|
|
|
%% @doc Append a chunk (binary- or iolist-style) of data to a file
|
|
|
|
%% with `Prefix'.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec append_chunk(port_wrap(), machi_dt:epoch_id(), machi_dt:file_prefix(), machi_dt:chunk()) ->
|
|
|
|
{ok, machi_dt:chunk_pos()} | {error, machi_dt:error_general()} | {error, term()}.
|
2015-04-02 09:08:42 +00:00
|
|
|
append_chunk(Sock, EpochID, Prefix, Chunk) ->
|
2015-05-17 05:10:42 +00:00
|
|
|
append_chunk2(Sock, EpochID, Prefix, Chunk, 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-06-19 07:24:57 +00:00
|
|
|
-spec append_chunk(machi_dt:inet_host(), machi_dt:inet_port(),
|
|
|
|
machi_dt:epoch_id(), machi_dt:file_prefix(), machi_dt:chunk()) ->
|
|
|
|
{ok, machi_dt:chunk_pos()} | {error, machi_dt:error_general()} | {error, term()}.
|
2015-04-02 09:08:42 +00:00
|
|
|
append_chunk(Host, TcpPort, EpochID, Prefix, Chunk) ->
|
2015-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-03-31 07:46:03 +00:00
|
|
|
try
|
2015-05-17 05:10:42 +00:00
|
|
|
append_chunk2(Sock, EpochID, Prefix, Chunk, 0)
|
|
|
|
after
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-05-17 05:10:42 +00:00
|
|
|
end.
|
|
|
|
|
|
|
|
%% @doc Append a chunk (binary- or iolist-style) of data to a file
|
|
|
|
%% with `Prefix' and also request an additional `Extra' bytes.
|
|
|
|
%%
|
|
|
|
%% For example, if the `Chunk' size is 1 KByte and `Extra' is 4K Bytes, then
|
|
|
|
%% the file offsets that follow `Chunk''s position for the following 4K will
|
|
|
|
%% be reserved by the file sequencer for later write(s) by the
|
|
|
|
%% `write_chunk()' API.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec append_chunk_extra(port_wrap(), machi_dt:epoch_id(), machi_dt:file_prefix(), machi_dt:chunk(), machi_dt:chunk_size()) ->
|
|
|
|
{ok, machi_dt:chunk_pos()} | {error, machi_dt:error_general()} | {error, term()}.
|
2015-05-17 05:10:42 +00:00
|
|
|
append_chunk_extra(Sock, EpochID, Prefix, Chunk, ChunkExtra)
|
|
|
|
when is_integer(ChunkExtra), ChunkExtra >= 0 ->
|
|
|
|
append_chunk2(Sock, EpochID, Prefix, Chunk, ChunkExtra).
|
|
|
|
|
|
|
|
%% @doc Append a chunk (binary- or iolist-style) of data to a file
|
|
|
|
%% with `Prefix' and also request an additional `Extra' bytes.
|
|
|
|
%%
|
|
|
|
%% For example, if the `Chunk' size is 1 KByte and `Extra' is 4K Bytes, then
|
|
|
|
%% the file offsets that follow `Chunk''s position for the following 4K will
|
|
|
|
%% be reserved by the file sequencer for later write(s) by the
|
|
|
|
%% `write_chunk()' API.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec append_chunk_extra(machi_dt:inet_host(), machi_dt:inet_port(),
|
|
|
|
machi_dt:epoch_id(), machi_dt:file_prefix(), machi_dt:chunk(), machi_dt:chunk_size()) ->
|
|
|
|
{ok, machi_dt:chunk_pos()} | {error, machi_dt:error_general()} | {error, term()}.
|
2015-05-17 05:10:42 +00:00
|
|
|
append_chunk_extra(Host, TcpPort, EpochID, Prefix, Chunk, ChunkExtra)
|
|
|
|
when is_integer(ChunkExtra), ChunkExtra >= 0 ->
|
2015-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-05-17 05:10:42 +00:00
|
|
|
try
|
|
|
|
append_chunk2(Sock, EpochID, Prefix, Chunk, ChunkExtra)
|
2015-03-31 07:46:03 +00:00
|
|
|
after
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-03-31 07:46:03 +00:00
|
|
|
end.
|
|
|
|
|
|
|
|
%% @doc Read a chunk of data of size `Size' from `File' at `Offset'.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec read_chunk(port_wrap(), machi_dt:epoch_id(), machi_dt:file_name(), machi_dt:file_offset(), machi_dt:chunk_size()) ->
|
|
|
|
{ok, machi_dt:chunk_s()} |
|
|
|
|
{error, machi_dt:error_general() | 'not_written' | 'partial_read'} |
|
2015-05-08 10:07:57 +00:00
|
|
|
{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-06-19 07:24:57 +00:00
|
|
|
-spec read_chunk(machi_dt:inet_host(), machi_dt:inet_port(), machi_dt:epoch_id(),
|
|
|
|
machi_dt:file_name(), machi_dt:file_offset(), machi_dt:chunk_size()) ->
|
|
|
|
{ok, machi_dt:chunk_s()} |
|
|
|
|
{error, machi_dt:error_general() | 'not_written' | 'partial_read'} |
|
2015-05-08 10:07:57 +00:00
|
|
|
{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-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-03-31 07:46:03 +00:00
|
|
|
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
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-03-31 07:46:03 +00:00
|
|
|
end.
|
|
|
|
|
|
|
|
%% @doc Fetch the list of chunk checksums for `File'.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec checksum_list(port_wrap(), machi_dt:epoch_id(), machi_dt:file_name()) ->
|
2015-06-30 06:20:35 +00:00
|
|
|
{ok, binary()} |
|
2015-06-19 07:24:57 +00:00
|
|
|
{error, machi_dt:error_general() | 'no_such_file' | 'partial_read'} |
|
2015-05-08 10:07:57 +00:00
|
|
|
{error, term()}.
|
2015-05-17 07:18:30 +00:00
|
|
|
checksum_list(Sock, EpochID, File) ->
|
2015-04-02 11:49:45 +00:00
|
|
|
checksum_list2(Sock, EpochID, File).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
|
|
|
%% @doc Fetch the list of chunk checksums for `File'.
|
2015-06-30 06:20:35 +00:00
|
|
|
%%
|
|
|
|
%% Why return a simple `binary()' type rather than
|
|
|
|
%% `[machi_dt:chunk_summary()]'? The two reasons are:
|
|
|
|
%% <ol>
|
|
|
|
%% <li> Server overhead: the CPU required to chop up the implementation-
|
|
|
|
%% specific store into zillions of very small terms is very high.
|
|
|
|
%% </li>
|
|
|
|
%% <li> Protocol encoding and decoding overhead: the cost is non-zero,
|
|
|
|
%% and the sum of cost of encoding and decoding a zillion small terms
|
|
|
|
%% is substantial.
|
|
|
|
%% </li>
|
|
|
|
%% </ol>
|
|
|
|
%%
|
|
|
|
%% For both reasons, the server's protocol response is absurdly simple
|
|
|
|
%% and very fast: send back a `binary()' blob to the client. Then it
|
|
|
|
%% is the client's responsibility to spend the CPU time to parse the
|
|
|
|
%% blob.
|
|
|
|
%%
|
|
|
|
%% Details of the encoding used inside the `binary()' blog can be found
|
|
|
|
%% in the EDoc comments for {@link machi_flu1:decode_csum_file_entry/1}.
|
2015-03-31 07:46:03 +00:00
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec checksum_list(machi_dt:inet_host(), machi_dt:inet_port(), machi_dt:epoch_id(), machi_dt:file_name()) ->
|
2015-06-30 06:20:35 +00:00
|
|
|
{ok, binary()} |
|
2015-06-19 07:24:57 +00:00
|
|
|
{error, machi_dt: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-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-03-31 07:46:03 +00:00
|
|
|
try
|
2015-04-02 11:49:45 +00:00
|
|
|
checksum_list2(Sock, EpochID, File)
|
2015-03-31 07:46:03 +00:00
|
|
|
after
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-03-31 07:46:03 +00:00
|
|
|
end.
|
|
|
|
|
|
|
|
%% @doc Fetch the list of all files on the remote FLU.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec list_files(port_wrap(), machi_dt:epoch_id()) ->
|
|
|
|
{ok, [machi_dt:file_info()]} | {error, term()}.
|
2015-05-17 07:18:30 +00:00
|
|
|
list_files(Sock, EpochID) ->
|
2015-04-02 12:01:48 +00:00
|
|
|
list2(Sock, EpochID).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
|
|
|
%% @doc Fetch the list of all files on the remote FLU.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec list_files(machi_dt:inet_host(), machi_dt:inet_port(), machi_dt:epoch_id()) ->
|
|
|
|
{ok, [machi_dt:file_info()]} | {error, term()}.
|
2015-04-02 12:01:48 +00:00
|
|
|
list_files(Host, TcpPort, EpochID) when is_integer(TcpPort) ->
|
2015-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-03-31 07:46:03 +00:00
|
|
|
try
|
2015-04-02 12:01:48 +00:00
|
|
|
list2(Sock, EpochID)
|
2015-03-31 07:46:03 +00:00
|
|
|
after
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-03-31 07:46:03 +00:00
|
|
|
end.
|
|
|
|
|
2015-05-08 07:53:10 +00:00
|
|
|
%% @doc Fetch the wedge status from the remote FLU.
|
|
|
|
|
2015-05-17 07:18:30 +00:00
|
|
|
-spec wedge_status(port_wrap()) ->
|
2015-06-19 07:24:57 +00:00
|
|
|
{ok, {boolean(), machi_dt:epoch_id()}} | {error, term()}.
|
2015-05-08 07:53:10 +00:00
|
|
|
|
2015-05-17 07:18:30 +00:00
|
|
|
wedge_status(Sock) ->
|
2015-05-08 07:53:10 +00:00
|
|
|
wedge_status2(Sock).
|
|
|
|
|
|
|
|
%% @doc Fetch the wedge status from the remote FLU.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec wedge_status(machi_dt:inet_host(), machi_dt:inet_port()) ->
|
|
|
|
{ok, {boolean(), machi_dt:epoch_id()}} | {error, term()}.
|
2015-05-08 07:53:10 +00:00
|
|
|
wedge_status(Host, TcpPort) when is_integer(TcpPort) ->
|
2015-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-05-08 07:53:10 +00:00
|
|
|
try
|
|
|
|
wedge_status2(Sock)
|
|
|
|
after
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-05-08 07:53:10 +00:00
|
|
|
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
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec get_latest_epochid(port_wrap(), machi_dt:projection_type()) ->
|
|
|
|
{ok, machi_dt:epoch_id()} | {error, term()}.
|
2015-05-18 10:06:06 +00:00
|
|
|
get_latest_epochid(Sock, ProjType)
|
2015-04-03 08:55:35 +00:00
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
2015-05-18 10:06:06 +00:00
|
|
|
get_latest_epochid2(Sock, ProjType).
|
2015-04-03 08:55:35 +00:00
|
|
|
|
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
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec get_latest_epochid(machi_dt:inet_host(), machi_dt:inet_port(), machi_dt:projection_type()) ->
|
|
|
|
{ok, machi_dt:epoch_id()} | {error, term()}.
|
2015-05-18 10:06:06 +00:00
|
|
|
get_latest_epochid(Host, TcpPort, ProjType)
|
2015-04-03 08:55:35 +00:00
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
2015-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-04-03 08:55:35 +00:00
|
|
|
try
|
2015-05-18 10:06:06 +00:00
|
|
|
get_latest_epochid2(Sock, ProjType)
|
2015-04-03 08:55:35 +00:00
|
|
|
after
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-04-03 08:55:35 +00:00
|
|
|
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
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec read_latest_projection(port_wrap(), machi_dt:projection_type()) ->
|
|
|
|
{ok, machi_dt:projection()} | {error, not_written} | {error, term()}.
|
2015-04-03 09:37:09 +00:00
|
|
|
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
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec read_latest_projection(machi_dt:inet_host(), machi_dt:inet_port(),
|
|
|
|
machi_dt:projection_type()) ->
|
|
|
|
{ok, machi_dt:projection()} | {error, not_written} | {error, term()}.
|
2015-04-03 09:37:09 +00:00
|
|
|
read_latest_projection(Host, TcpPort, ProjType)
|
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
2015-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-04-03 09:37:09 +00:00
|
|
|
try
|
|
|
|
read_latest_projection2(Sock, ProjType)
|
|
|
|
after
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-04-03 09:37:09 +00:00
|
|
|
end.
|
|
|
|
|
2015-04-03 08:55:35 +00:00
|
|
|
%% @doc Read a projection `Proj' of type `ProjType'.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec read_projection(port_wrap(), machi_dt:projection_type(), machi_dt:epoch_num()) ->
|
|
|
|
{ok, machi_dt:projection()} | {error, not_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'.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec read_projection(machi_dt:inet_host(), machi_dt:inet_port(),
|
|
|
|
machi_dt:projection_type(), machi_dt:epoch_num()) ->
|
|
|
|
{ok, machi_dt:projection()} | {error, not_written} | {error, term()}.
|
2015-04-03 08:55:35 +00:00
|
|
|
read_projection(Host, TcpPort, ProjType, Epoch)
|
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
2015-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-04-03 08:55:35 +00:00
|
|
|
try
|
|
|
|
read_projection2(Sock, ProjType, Epoch)
|
|
|
|
after
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-04-03 08:55:35 +00:00
|
|
|
end.
|
|
|
|
|
2015-04-03 03:33:47 +00:00
|
|
|
%% @doc Write a projection `Proj' of type `ProjType'.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec write_projection(port_wrap(), machi_dt:projection_type(), machi_dt:projection()) ->
|
2015-05-19 06:15:05 +00:00
|
|
|
'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'.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec write_projection(machi_dt:inet_host(), machi_dt:inet_port(),
|
|
|
|
machi_dt:projection_type(), machi_dt:projection()) ->
|
2015-05-19 06:15:05 +00:00
|
|
|
'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-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-04-03 03:33:47 +00:00
|
|
|
try
|
|
|
|
write_projection2(Sock, ProjType, Proj)
|
|
|
|
after
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-04-03 03:33:47 +00:00
|
|
|
end.
|
|
|
|
|
2015-04-03 09:37:09 +00:00
|
|
|
%% @doc Get all projections from the FLU's projection store.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec get_all_projections(port_wrap(), machi_dt:projection_type()) ->
|
|
|
|
{ok, [machi_dt: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-06-19 07:24:57 +00:00
|
|
|
-spec get_all_projections(machi_dt:inet_host(), machi_dt:inet_port(), machi_dt:projection_type()) ->
|
|
|
|
{ok, [machi_dt: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' ->
|
2015-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-04-03 09:37:09 +00:00
|
|
|
try
|
2015-04-06 09:43:52 +00:00
|
|
|
get_all_projections2(Sock, ProjType)
|
2015-04-03 09:37:09 +00:00
|
|
|
after
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-04-03 09:37:09 +00:00
|
|
|
end.
|
|
|
|
|
|
|
|
%% @doc Get all epoch numbers from the FLU's projection store.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec list_all_projections(port_wrap(), machi_dt: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-06-19 07:24:57 +00:00
|
|
|
-spec list_all_projections(machi_dt:inet_host(), machi_dt:inet_port(), machi_dt: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(Host, TcpPort, ProjType)
|
2015-04-03 09:37:09 +00:00
|
|
|
when ProjType == 'public' orelse ProjType == 'private' ->
|
2015-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-04-03 09:37:09 +00:00
|
|
|
try
|
2015-04-06 09:43:52 +00:00
|
|
|
list_all_projections2(Sock, ProjType)
|
2015-04-03 09:37:09 +00:00
|
|
|
after
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-04-03 09:37:09 +00:00
|
|
|
end.
|
|
|
|
|
2015-07-02 19:30:05 +00:00
|
|
|
%% @doc Kick (politely) the remote chain manager to react to a
|
|
|
|
%% projection change.
|
|
|
|
|
|
|
|
-spec kick_projection_reaction(port_wrap(), list()) ->
|
|
|
|
ok.
|
|
|
|
kick_projection_reaction(Sock, Options) ->
|
|
|
|
kick_projection_reaction2(Sock, Options).
|
|
|
|
|
|
|
|
%% @doc Kick (politely) the remote chain manager to react to a
|
|
|
|
%% projection change.
|
|
|
|
|
|
|
|
-spec kick_projection_reaction(machi_dt:inet_host(), machi_dt:inet_port(), list()) ->
|
|
|
|
ok.
|
|
|
|
kick_projection_reaction(Host, TcpPort, Options) ->
|
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
|
|
|
try
|
|
|
|
kick_projection_reaction2(Sock, Options)
|
|
|
|
after
|
|
|
|
disconnect(Sock)
|
|
|
|
end.
|
|
|
|
|
2015-06-26 07:25:12 +00:00
|
|
|
%% @doc Echo -- test protocol round-trip.
|
|
|
|
|
|
|
|
-spec echo(port_wrap(), string()) ->
|
|
|
|
string() | {error, term()}.
|
|
|
|
echo(Sock, String) when is_list(String) ->
|
|
|
|
echo2(Sock, String).
|
|
|
|
|
|
|
|
%% @doc Get all epoch numbers from the FLU's projection store.
|
|
|
|
|
|
|
|
-spec echo(machi_dt:inet_host(), machi_dt:inet_port(), string()) ->
|
2015-06-29 08:14:33 +00:00
|
|
|
string() | {error, term()}.
|
2015-06-26 07:25:12 +00:00
|
|
|
echo(Host, TcpPort, String) when is_list(String) ->
|
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
|
|
|
try
|
|
|
|
echo2(Sock, String)
|
|
|
|
after
|
|
|
|
disconnect(Sock)
|
|
|
|
end.
|
|
|
|
|
2015-03-31 07:46:03 +00:00
|
|
|
%% @doc Quit & close the connection to remote FLU.
|
|
|
|
|
2015-05-17 07:18:30 +00:00
|
|
|
-spec quit(port_wrap()) ->
|
2015-03-31 07:46:03 +00:00
|
|
|
ok.
|
2015-05-17 07:18:30 +00:00
|
|
|
quit(Sock) ->
|
|
|
|
catch (_ = w_send(Sock, <<"QUIT\n">>)),
|
|
|
|
disconnect(Sock),
|
|
|
|
ok.
|
|
|
|
|
|
|
|
connected_p({w,tcp,Sock}) ->
|
|
|
|
case (catch inet:peername(Sock)) of
|
|
|
|
{ok, _} -> true;
|
|
|
|
_ -> false
|
|
|
|
end;
|
|
|
|
connected_p(_) ->
|
|
|
|
false.
|
|
|
|
|
|
|
|
connect(#p_srvr{}=P) ->
|
|
|
|
w_connect(P).
|
|
|
|
|
|
|
|
disconnect({w,tcp,_Sock}=WS) ->
|
|
|
|
w_close(WS),
|
|
|
|
ok;
|
|
|
|
disconnect(_) ->
|
2015-03-31 07:46:03 +00:00
|
|
|
ok.
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
|
|
%% @doc Restricted API: Write a chunk of already-sequenced data to
|
|
|
|
%% `File' at `Offset'.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec write_chunk(port_wrap(), machi_dt:epoch_id(), machi_dt:file_name(), machi_dt:file_offset(), machi_dt:chunk()) ->
|
|
|
|
ok | {error, machi_dt: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-06-19 07:24:57 +00:00
|
|
|
-spec write_chunk(machi_dt:inet_host(), machi_dt:inet_port(),
|
|
|
|
machi_dt:epoch_id(), machi_dt:file_name(), machi_dt:file_offset(), machi_dt:chunk()) ->
|
|
|
|
ok | {error, machi_dt: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-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-03-31 07:46:03 +00:00
|
|
|
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
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-03-31 07:46:03 +00:00
|
|
|
end.
|
|
|
|
|
|
|
|
%% @doc Restricted API: Delete a file after it has been successfully
|
|
|
|
%% migrated.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec delete_migration(port_wrap(), machi_dt:epoch_id(), machi_dt:file_name()) ->
|
|
|
|
ok | {error, machi_dt:error_general() | 'no_such_file'} | {error, term()}.
|
2015-05-17 07:18:30 +00:00
|
|
|
delete_migration(Sock, EpochID, File) ->
|
2015-04-02 12:18:41 +00:00
|
|
|
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-06-19 07:24:57 +00:00
|
|
|
-spec delete_migration(machi_dt:inet_host(), machi_dt:inet_port(), machi_dt:epoch_id(), machi_dt:file_name()) ->
|
|
|
|
ok | {error, machi_dt: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-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-03-31 07:46:03 +00:00
|
|
|
try
|
2015-04-02 12:18:41 +00:00
|
|
|
delete_migration2(Sock, EpochID, File)
|
2015-03-31 07:46:03 +00:00
|
|
|
after
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-03-31 07:46:03 +00:00
|
|
|
end.
|
|
|
|
|
|
|
|
%% @doc Restricted API: Truncate a file after it has been successfully
|
|
|
|
%% erasure coded.
|
|
|
|
|
2015-06-19 07:24:57 +00:00
|
|
|
-spec trunc_hack(port_wrap(), machi_dt:epoch_id(), machi_dt:file_name()) ->
|
|
|
|
ok | {error, machi_dt:error_general() | 'no_such_file'} | {error, term()}.
|
2015-05-17 07:18:30 +00:00
|
|
|
trunc_hack(Sock, EpochID, File) ->
|
2015-04-02 12:18:41 +00:00
|
|
|
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-06-19 07:24:57 +00:00
|
|
|
-spec trunc_hack(machi_dt:inet_host(), machi_dt:inet_port(), machi_dt:epoch_id(), machi_dt:file_name()) ->
|
|
|
|
ok | {error, machi_dt: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-05-17 07:18:30 +00:00
|
|
|
Sock = connect(#p_srvr{proto_mod=?MODULE, address=Host, port=TcpPort}),
|
2015-03-31 07:46:03 +00:00
|
|
|
try
|
2015-04-02 12:18:41 +00:00
|
|
|
trunc_hack2(Sock, EpochID, File)
|
2015-03-31 07:46:03 +00:00
|
|
|
after
|
2015-05-17 07:18:30 +00:00
|
|
|
disconnect(Sock)
|
2015-03-31 07:46:03 +00:00
|
|
|
end.
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
2015-04-02 11:31:10 +00:00
|
|
|
read_chunk2(Sock, EpochID, File0, Offset, Size) ->
|
2015-06-26 12:36:07 +00:00
|
|
|
ReqID = <<"id">>,
|
|
|
|
File = machi_util:make_binary(File0),
|
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID,
|
|
|
|
{low_read_chunk, EpochID, File, Offset, Size, []}),
|
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
2015-06-26 11:47:55 +00:00
|
|
|
append_chunk2(Sock, EpochID, Prefix0, Chunk0, ChunkExtra) ->
|
|
|
|
ReqID = <<"id">>,
|
|
|
|
{Chunk, CSum_tag, CSum} =
|
|
|
|
case Chunk0 of
|
|
|
|
X when is_binary(X) ->
|
|
|
|
{Chunk0, ?CSUM_TAG_NONE, <<>>};
|
|
|
|
{ChunkCSum, Chk} ->
|
|
|
|
{Tag, CS} = machi_util:unmake_tagged_csum(ChunkCSum),
|
|
|
|
{Chk, Tag, CS}
|
|
|
|
end,
|
|
|
|
PKey = <<>>, % TODO
|
|
|
|
Prefix = machi_util:make_binary(Prefix0),
|
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID,
|
|
|
|
{low_append_chunk, EpochID, PKey, Prefix, Chunk, CSum_tag, CSum,
|
|
|
|
ChunkExtra}),
|
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
2015-06-26 13:32:53 +00:00
|
|
|
write_chunk2(Sock, EpochID, File0, Offset, Chunk0) ->
|
|
|
|
ReqID = <<"id">>,
|
|
|
|
File = machi_util:make_binary(File0),
|
|
|
|
true = (Offset >= ?MINIMUM_OFFSET),
|
|
|
|
{Chunk, CSum_tag, CSum} =
|
|
|
|
case Chunk0 of
|
|
|
|
X when is_binary(X) ->
|
|
|
|
{Chunk0, ?CSUM_TAG_NONE, <<>>};
|
|
|
|
{ChunkCSum, Chk} ->
|
|
|
|
{Tag, CS} = machi_util:unmake_tagged_csum(ChunkCSum),
|
|
|
|
{Chk, Tag, CS}
|
|
|
|
end,
|
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID,
|
|
|
|
{low_write_chunk, EpochID, File, Offset, Chunk, CSum_tag, CSum}),
|
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
|
|
|
|
2015-06-26 11:47:55 +00:00
|
|
|
list2(Sock, EpochID) ->
|
|
|
|
ReqID = <<"id">>,
|
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID, {low_list_files, EpochID}),
|
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
2015-05-08 07:53:10 +00:00
|
|
|
wedge_status2(Sock) ->
|
2015-06-26 11:47:55 +00:00
|
|
|
ReqID = <<"id">>,
|
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID, {low_wedge_status, undefined}),
|
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
2015-05-08 07:53:10 +00:00
|
|
|
|
2015-06-26 07:25:12 +00:00
|
|
|
echo2(Sock, Message) ->
|
|
|
|
ReqID = <<"id">>,
|
2015-06-26 07:58:24 +00:00
|
|
|
Req = machi_pb_translate:to_pb_request(
|
2015-06-26 11:47:55 +00:00
|
|
|
ReqID, {low_echo, undefined, Message}),
|
2015-06-26 07:25:12 +00:00
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
|
|
|
|
2015-04-02 11:49:45 +00:00
|
|
|
checksum_list2(Sock, EpochID, File) ->
|
2015-06-26 07:25:12 +00:00
|
|
|
ReqID = <<"id">>,
|
2015-06-26 07:58:24 +00:00
|
|
|
Req = machi_pb_translate:to_pb_request(
|
2015-06-26 07:25:12 +00:00
|
|
|
ReqID, {low_checksum_list, EpochID, File}),
|
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
2015-04-02 12:18:41 +00:00
|
|
|
delete_migration2(Sock, EpochID, File) ->
|
2015-06-26 14:03:28 +00:00
|
|
|
ReqID = <<"id">>,
|
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID, {low_delete_migration, EpochID, File}),
|
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
2015-03-31 07:46:03 +00:00
|
|
|
|
2015-04-02 12:18:41 +00:00
|
|
|
trunc_hack2(Sock, EpochID, File) ->
|
2015-06-26 14:03:28 +00:00
|
|
|
ReqID = <<"id-trunc">>,
|
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID, {low_trunc_hack, EpochID, File}),
|
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
2015-04-03 03:33:47 +00:00
|
|
|
|
2015-05-18 10:06:06 +00:00
|
|
|
get_latest_epochid2(Sock, ProjType) ->
|
2015-06-26 07:25:12 +00:00
|
|
|
ReqID = <<42>>,
|
2015-06-26 14:58:34 +00:00
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID, {low_proj, {get_latest_epochid, ProjType}}),
|
2015-06-26 07:25:12 +00:00
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
2015-04-03 08:55:35 +00:00
|
|
|
|
2015-04-03 09:37:09 +00:00
|
|
|
read_latest_projection2(Sock, ProjType) ->
|
2015-06-26 07:25:12 +00:00
|
|
|
ReqID = <<42>>,
|
2015-06-26 14:58:34 +00:00
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID, {low_proj, {read_latest_projection, ProjType}}),
|
2015-06-26 07:25:12 +00:00
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
2015-04-03 09:37:09 +00:00
|
|
|
|
2015-04-03 08:55:35 +00:00
|
|
|
read_projection2(Sock, ProjType, Epoch) ->
|
2015-06-26 07:25:12 +00:00
|
|
|
ReqID = <<42>>,
|
2015-06-26 14:58:34 +00:00
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID, {low_proj, {read_projection, ProjType, Epoch}}),
|
2015-06-26 07:25:12 +00:00
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
2015-04-03 08:55:35 +00:00
|
|
|
|
2015-04-03 03:33:47 +00:00
|
|
|
write_projection2(Sock, ProjType, Proj) ->
|
2015-06-26 07:25:12 +00:00
|
|
|
ReqID = <<42>>,
|
2015-06-26 14:58:34 +00:00
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID, {low_proj, {write_projection, ProjType, Proj}}),
|
2015-06-26 07:25:12 +00:00
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
2015-04-03 09:37:09 +00:00
|
|
|
|
2015-04-06 09:43:52 +00:00
|
|
|
get_all_projections2(Sock, ProjType) ->
|
2015-06-26 07:25:12 +00:00
|
|
|
ReqID = <<42>>,
|
2015-06-26 14:58:34 +00:00
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID, {low_proj, {get_all_projections, ProjType}}),
|
2015-06-26 07:25:12 +00:00
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
2015-04-03 09:37:09 +00:00
|
|
|
|
2015-04-06 09:43:52 +00:00
|
|
|
list_all_projections2(Sock, ProjType) ->
|
2015-06-26 07:25:12 +00:00
|
|
|
ReqID = <<42>>,
|
2015-06-26 14:58:34 +00:00
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID, {low_proj, {list_all_projections, ProjType}}),
|
2015-06-26 07:25:12 +00:00
|
|
|
do_pb_request_common(Sock, ReqID, Req).
|
2015-04-03 03:33:47 +00:00
|
|
|
|
2015-07-02 19:30:05 +00:00
|
|
|
kick_projection_reaction2(Sock, _Options) ->
|
|
|
|
ReqID = <<42>>,
|
|
|
|
Req = machi_pb_translate:to_pb_request(
|
|
|
|
ReqID, {low_proj, {kick_projection_reaction}}),
|
|
|
|
do_pb_request_common(Sock, ReqID, Req, false).
|
|
|
|
|
2015-06-26 07:25:12 +00:00
|
|
|
do_pb_request_common(Sock, ReqID, Req) ->
|
2015-07-02 19:30:05 +00:00
|
|
|
do_pb_request_common(Sock, ReqID, Req, true).
|
|
|
|
|
|
|
|
do_pb_request_common(Sock, ReqID, Req, GetReply_p) ->
|
2015-04-06 09:43:52 +00:00
|
|
|
erase(bad_sock),
|
2015-04-03 03:33:47 +00:00
|
|
|
try
|
2015-06-25 06:08:40 +00:00
|
|
|
ReqBin = list_to_binary(machi_pb:encode_mpb_ll_request(Req)),
|
2015-06-26 07:25:12 +00:00
|
|
|
ok = w_send(Sock, ReqBin),
|
2015-07-02 19:30:05 +00:00
|
|
|
if GetReply_p ->
|
|
|
|
case w_recv(Sock, 0) of
|
|
|
|
{ok, RespBin} ->
|
|
|
|
Resp = machi_pb:decode_mpb_ll_response(RespBin),
|
|
|
|
{ReqID2, Reply} = machi_pb_translate:from_pb_response(Resp),
|
|
|
|
true = (ReqID == ReqID2 orelse ReqID2 == <<>>),
|
|
|
|
Reply;
|
|
|
|
{error, _}=Err ->
|
|
|
|
throw(Err)
|
|
|
|
end;
|
|
|
|
not GetReply_p ->
|
|
|
|
ok
|
2015-04-03 03:33:47 +00:00
|
|
|
end
|
|
|
|
catch
|
|
|
|
throw:Error ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
2015-06-29 07:42:05 +00:00
|
|
|
filter_sock_error_result(Error);
|
2015-05-18 10:06:06 +00:00
|
|
|
error:{case_clause,_}=Noo ->
|
|
|
|
put(bad_sock, Sock),
|
|
|
|
{error, {badmatch, Noo, erlang:get_stacktrace()}};
|
2015-04-03 03:33:47 +00:00
|
|
|
error:{badmatch,_}=BadMatch ->
|
2015-04-06 09:43:52 +00:00
|
|
|
put(bad_sock, Sock),
|
Tweak IsRelevantToMe_p in B10 (more)
Last night we hit a rare case of failed convergence.
f was out of sync with the rest of the world.
f: upi=[b,g,f] repairing=[a,c]
The "rest of the world" used a larger chain at:
*: upi=[c,b,g,a], repairing=[f]
And f refused to join the larger chain because of the way that
IsRelevantToMe_p was being calculated before this commit.
Hrrrm, though, I'm not convinced that this particular problem
is fixed 100% by this patch. What if the chain lengths were
the same but also UPI incompatible? e.g. if I remove 'a' from
the "real world (in the partition simulator)" example above:
f: upi=[b,g,f] repairing=[c]
*: upi=[c,b,g], repairing=[f]
Hrmmmmm, I may need to reintroduce the my-recent-adopted-projection-
flapping-like-counter thingie to try to break this kind of
incompatible deadlock.
2015-09-14 04:40:34 +00:00
|
|
|
{error, {badmatch, BadMatch, erlang:get_stacktrace()}};
|
|
|
|
error:Whoa ->
|
|
|
|
put(bad_sock, Sock),
|
|
|
|
%% TODO: The machi_chain_manager1_converge_demo:t() test can
|
|
|
|
%% create a large number of these errors when moving from
|
|
|
|
%% no partitions to many partitions:
|
|
|
|
%% Whoa undefined: function_clause
|
|
|
|
%% In theory this is harmless, because the client will retry
|
|
|
|
%% with a new socket. But, fix it anyway.
|
|
|
|
io:format(user, "DBG Whoa ~w: ~w\n", [Sock, Whoa]),
|
|
|
|
{error, {whoa, Whoa, erlang:get_stacktrace()}}
|
2015-04-03 03:33:47 +00:00
|
|
|
end.
|
2015-05-17 07:18:30 +00:00
|
|
|
|
2015-06-29 07:42:05 +00:00
|
|
|
filter_sock_error_result({error, closed}) ->
|
|
|
|
{error, partition};
|
|
|
|
filter_sock_error_result(Error) ->
|
|
|
|
Error.
|
|
|
|
|
2015-05-17 07:18:30 +00:00
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
2015-05-17 07:46:50 +00:00
|
|
|
w_connect(#p_srvr{proto_mod=?MODULE, address=Host, port=Port, props=Props})->
|
2015-05-17 07:18:30 +00:00
|
|
|
try
|
2015-05-17 07:46:50 +00:00
|
|
|
case proplists:get_value(session_proto, Props, tcp) of
|
|
|
|
tcp ->
|
2015-05-18 10:06:06 +00:00
|
|
|
Sock = machi_util:connect(Host, Port, ?HARD_TIMEOUT),
|
2015-06-26 07:25:12 +00:00
|
|
|
ok = inet:setopts(Sock, ?PB_PACKET_OPTS),
|
2015-05-17 07:46:50 +00:00
|
|
|
{w,tcp,Sock};
|
|
|
|
%% sctp ->
|
|
|
|
%% %% TODO: not implemented
|
|
|
|
%% {w,sctp,Sock}
|
|
|
|
ssl ->
|
|
|
|
%% TODO: veryveryuntested
|
|
|
|
SslOptions = proplists:get_value(ssl_options, Props),
|
|
|
|
Sock = machi_util:connect(Port, Port),
|
|
|
|
{ok, SslSock} = ssl:connect(Sock, SslOptions),
|
|
|
|
{w,ssl,SslSock}
|
|
|
|
end
|
2015-05-17 07:18:30 +00:00
|
|
|
catch
|
|
|
|
_:_ ->
|
|
|
|
undefined
|
|
|
|
end.
|
|
|
|
|
|
|
|
w_close({w,tcp,Sock}) ->
|
|
|
|
catch gen_tcp:close(Sock),
|
|
|
|
ok.
|
|
|
|
|
|
|
|
w_recv({w,tcp,Sock}, Amt) ->
|
2015-05-18 10:06:06 +00:00
|
|
|
gen_tcp:recv(Sock, Amt, ?HARD_TIMEOUT).
|
2015-05-17 07:18:30 +00:00
|
|
|
|
|
|
|
w_send({w,tcp,Sock}, IoData) ->
|
|
|
|
gen_tcp:send(Sock, IoData).
|
|
|
|
|
2015-06-29 08:06:28 +00:00
|
|
|
%% w_setopts({w,tcp,Sock}, Opts) ->
|
|
|
|
%% inet:setopts(Sock, Opts).
|
2015-05-17 07:18:30 +00:00
|
|
|
|