Merge branch 'lwt_pipes_limit' into 'master'
Lwt_pipe: limit by content size in bytes See merge request !137
This commit is contained in:
commit
ec0e7d4d48
@ -10,8 +10,6 @@
|
|||||||
(* TODO encode/encrypt before to push into the writer pipe. *)
|
(* TODO encode/encrypt before to push into the writer pipe. *)
|
||||||
(* TODO patch Sodium.Box to avoid allocation of the encrypted buffer.*)
|
(* TODO patch Sodium.Box to avoid allocation of the encrypted buffer.*)
|
||||||
(* TODO patch Data_encoding for continuation-based binary writer/reader. *)
|
(* TODO patch Data_encoding for continuation-based binary writer/reader. *)
|
||||||
(* TODO use queue bound by memory size of its elements, not by the
|
|
||||||
number of elements. *)
|
|
||||||
(* TODO test `close ~wait:true`. *)
|
(* TODO test `close ~wait:true`. *)
|
||||||
(* TODO nothing in welcoming message proves that the incoming peer is
|
(* TODO nothing in welcoming message proves that the incoming peer is
|
||||||
the owner of the public key... only the first message will
|
the owner of the public key... only the first message will
|
||||||
@ -218,7 +216,7 @@ module Reader = struct
|
|||||||
canceler: Canceler.t ;
|
canceler: Canceler.t ;
|
||||||
conn: connection ;
|
conn: connection ;
|
||||||
encoding: 'msg Data_encoding.t ;
|
encoding: 'msg Data_encoding.t ;
|
||||||
messages: 'msg tzresult Lwt_pipe.t ;
|
messages: (int * 'msg) tzresult Lwt_pipe.t ;
|
||||||
mutable worker: unit Lwt.t ;
|
mutable worker: unit Lwt.t ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,13 +227,15 @@ module Reader = struct
|
|||||||
Lwt_unix.yield () >>= fun () ->
|
Lwt_unix.yield () >>= fun () ->
|
||||||
Lwt_utils.protect ~canceler:st.canceler begin fun () ->
|
Lwt_utils.protect ~canceler:st.canceler begin fun () ->
|
||||||
Crypto.read_chunk st.conn.fd st.conn.cryptobox_data >>=? fun buf ->
|
Crypto.read_chunk st.conn.fd st.conn.cryptobox_data >>=? fun buf ->
|
||||||
read_message st buf
|
let size = 6 * (Sys.word_size / 8) + MBytes.length buf in
|
||||||
|
read_message st buf >>|? fun msg ->
|
||||||
|
size, msg
|
||||||
end >>= function
|
end >>= function
|
||||||
| Ok None ->
|
| Ok (_, None) ->
|
||||||
Lwt_pipe.push st.messages (Error [Decoding_error]) >>= fun () ->
|
Lwt_pipe.push st.messages (Error [Decoding_error]) >>= fun () ->
|
||||||
worker_loop st
|
worker_loop st
|
||||||
| Ok (Some msg) ->
|
| Ok (size, Some msg) ->
|
||||||
Lwt_pipe.push st.messages (Ok msg) >>= fun () ->
|
Lwt_pipe.push st.messages (Ok (size, msg)) >>= fun () ->
|
||||||
worker_loop st
|
worker_loop st
|
||||||
| Error [Lwt_utils.Canceled | Exn Lwt_pipe.Closed] ->
|
| Error [Lwt_utils.Canceled | Exn Lwt_pipe.Closed] ->
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
@ -245,6 +245,11 @@ module Reader = struct
|
|||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
|
|
||||||
let run ?size conn encoding canceler =
|
let run ?size conn encoding canceler =
|
||||||
|
let compute_size = function
|
||||||
|
| Ok (size, _) -> (Sys.word_size / 8) * 11 + size
|
||||||
|
| Error _ -> 0 (* we push Error only when we close the socket,
|
||||||
|
we don't fear memory leaks in that case... *) in
|
||||||
|
let size = map_option size ~f:(fun max -> (max, compute_size)) in
|
||||||
let st =
|
let st =
|
||||||
{ canceler ; conn ; encoding ;
|
{ canceler ; conn ; encoding ;
|
||||||
messages = Lwt_pipe.create ?size () ;
|
messages = Lwt_pipe.create ?size () ;
|
||||||
@ -301,6 +306,13 @@ module Writer = struct
|
|||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
|
|
||||||
let run ?size conn encoding canceler =
|
let run ?size conn encoding canceler =
|
||||||
|
let compute_size = function
|
||||||
|
| msg, None ->
|
||||||
|
10 * (Sys.word_size / 8) + Data_encoding.Binary.length encoding msg
|
||||||
|
| msg, Some _ ->
|
||||||
|
18 * (Sys.word_size / 8) + Data_encoding.Binary.length encoding msg
|
||||||
|
in
|
||||||
|
let size = map_option size ~f:(fun max -> max, compute_size) in
|
||||||
let st =
|
let st =
|
||||||
{ canceler ; conn ; encoding ;
|
{ canceler ; conn ; encoding ;
|
||||||
messages = Lwt_pipe.create ?size () ;
|
messages = Lwt_pipe.create ?size () ;
|
||||||
@ -367,10 +379,6 @@ let catch_closed_pipe f =
|
|||||||
| exn -> fail (Exn exn)
|
| exn -> fail (Exn exn)
|
||||||
end
|
end
|
||||||
|
|
||||||
let is_writable { writer } =
|
|
||||||
not (Lwt_pipe.is_full writer.messages)
|
|
||||||
let wait_writable { writer } =
|
|
||||||
Lwt_pipe.not_full writer.messages
|
|
||||||
let write { writer } msg =
|
let write { writer } msg =
|
||||||
catch_closed_pipe begin fun () ->
|
catch_closed_pipe begin fun () ->
|
||||||
Lwt_pipe.push writer.messages (msg, None) >>= return
|
Lwt_pipe.push writer.messages (msg, None) >>= return
|
||||||
|
@ -71,14 +71,6 @@ val accept:
|
|||||||
|
|
||||||
(** {2 Output functions} *)
|
(** {2 Output functions} *)
|
||||||
|
|
||||||
val is_writable: 'msg t -> bool
|
|
||||||
(** [is_writable conn] is [true] iff [conn] internal write queue is
|
|
||||||
not full. *)
|
|
||||||
|
|
||||||
val wait_writable: 'msg t -> unit Lwt.t
|
|
||||||
(** (Cancelable) [wait_writable conn] returns when [conn]'s internal
|
|
||||||
write queue becomes writable (i.e. not full). *)
|
|
||||||
|
|
||||||
val write: 'msg t -> 'msg -> unit tzresult Lwt.t
|
val write: 'msg t -> 'msg -> unit tzresult Lwt.t
|
||||||
(** [write conn msg] returns when [msg] has successfully been added to
|
(** [write conn msg] returns when [msg] has successfully been added to
|
||||||
[conn]'s internal write queue or fails with a corresponding
|
[conn]'s internal write queue or fails with a corresponding
|
||||||
@ -103,12 +95,12 @@ val wait_readable: 'msg t -> unit tzresult Lwt.t
|
|||||||
(** (Cancelable) [wait_readable conn] returns when [conn]'s internal
|
(** (Cancelable) [wait_readable conn] returns when [conn]'s internal
|
||||||
read queue becomes readable (i.e. not empty). *)
|
read queue becomes readable (i.e. not empty). *)
|
||||||
|
|
||||||
val read: 'msg t -> 'msg tzresult Lwt.t
|
val read: 'msg t -> (int * 'msg) tzresult Lwt.t
|
||||||
(** [read conn msg] returns when [msg] has successfully been popped
|
(** [read conn msg] returns when [msg] has successfully been popped
|
||||||
from [conn]'s internal read queue or fails with a corresponding
|
from [conn]'s internal read queue or fails with a corresponding
|
||||||
error. *)
|
error. *)
|
||||||
|
|
||||||
val read_now: 'msg t -> 'msg tzresult option
|
val read_now: 'msg t -> (int * 'msg) tzresult option
|
||||||
(** [read_now conn msg] is [Some msg] if [conn]'s internal read queue
|
(** [read_now conn msg] is [Some msg] if [conn]'s internal read queue
|
||||||
is not empty, [None] if it is empty, or fails with a correponding
|
is not empty, [None] if it is empty, or fails with a correponding
|
||||||
error otherwise. *)
|
error otherwise. *)
|
||||||
|
@ -65,7 +65,7 @@ module Answerer = struct
|
|||||||
type 'msg callback = {
|
type 'msg callback = {
|
||||||
bootstrap: unit -> Point.t list Lwt.t ;
|
bootstrap: unit -> Point.t list Lwt.t ;
|
||||||
advertise: Point.t list -> unit Lwt.t ;
|
advertise: Point.t list -> unit Lwt.t ;
|
||||||
message: 'msg -> unit Lwt.t ;
|
message: int -> 'msg -> unit Lwt.t ;
|
||||||
}
|
}
|
||||||
|
|
||||||
type 'msg t = {
|
type 'msg t = {
|
||||||
@ -80,7 +80,7 @@ module Answerer = struct
|
|||||||
Lwt_utils.protect ~canceler:st.canceler begin fun () ->
|
Lwt_utils.protect ~canceler:st.canceler begin fun () ->
|
||||||
P2p_connection.read st.conn
|
P2p_connection.read st.conn
|
||||||
end >>= function
|
end >>= function
|
||||||
| Ok Bootstrap -> begin
|
| Ok (_, Bootstrap) -> begin
|
||||||
st.callback.bootstrap () >>= function
|
st.callback.bootstrap () >>= function
|
||||||
| [] ->
|
| [] ->
|
||||||
worker_loop st
|
worker_loop st
|
||||||
@ -93,13 +93,13 @@ module Answerer = struct
|
|||||||
Canceler.cancel st.canceler >>= fun () ->
|
Canceler.cancel st.canceler >>= fun () ->
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
end
|
end
|
||||||
| Ok (Advertise points) ->
|
| Ok (_, Advertise points) ->
|
||||||
st.callback.advertise points >>= fun () ->
|
st.callback.advertise points >>= fun () ->
|
||||||
worker_loop st
|
worker_loop st
|
||||||
| Ok (Message msg) ->
|
| Ok (size, Message msg) ->
|
||||||
st.callback.message msg >>= fun () ->
|
st.callback.message size msg >>= fun () ->
|
||||||
worker_loop st
|
worker_loop st
|
||||||
| Ok Disconnect | Error [P2p_io_scheduler.Connection_closed] ->
|
| Ok (_, Disconnect) | Error [P2p_io_scheduler.Connection_closed] ->
|
||||||
Canceler.cancel st.canceler >>= fun () ->
|
Canceler.cancel st.canceler >>= fun () ->
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
| Error [Lwt_utils.Canceled] ->
|
| Error [Lwt_utils.Canceled] ->
|
||||||
@ -181,7 +181,7 @@ and events = {
|
|||||||
|
|
||||||
and ('msg, 'meta) connection = {
|
and ('msg, 'meta) connection = {
|
||||||
canceler : Canceler.t ;
|
canceler : Canceler.t ;
|
||||||
messages : 'msg Lwt_pipe.t ;
|
messages : (int * 'msg) Lwt_pipe.t ;
|
||||||
conn : 'msg Message.t P2p_connection.t ;
|
conn : 'msg Message.t P2p_connection.t ;
|
||||||
gid_info : (('msg, 'meta) connection, 'meta) Gid_info.t ;
|
gid_info : (('msg, 'meta) connection, 'meta) Gid_info.t ;
|
||||||
point_info : ('msg, 'meta) connection Point_info.t option ;
|
point_info : ('msg, 'meta) connection Point_info.t option ;
|
||||||
@ -248,10 +248,13 @@ let active_connections pool = Gid.Table.length pool.connected_gids
|
|||||||
let create_connection pool conn id_point pi gi =
|
let create_connection pool conn id_point pi gi =
|
||||||
let gid = Gid_info.gid gi in
|
let gid = Gid_info.gid gi in
|
||||||
let canceler = Canceler.create () in
|
let canceler = Canceler.create () in
|
||||||
let messages =
|
let size =
|
||||||
Lwt_pipe.create ?size:pool.config.incoming_app_message_queue_size () in
|
map_option pool.config.incoming_app_message_queue_size
|
||||||
|
~f:(fun qs -> qs, fun (size, _) -> (Sys.word_size / 8) * 11 + size) in
|
||||||
|
let messages = Lwt_pipe.create ?size () in
|
||||||
let callback =
|
let callback =
|
||||||
{ Answerer.message = Lwt_pipe.push messages ;
|
{ Answerer.message =
|
||||||
|
(fun size msg -> Lwt_pipe.push messages (size, msg)) ;
|
||||||
advertise = register_new_points pool gid ;
|
advertise = register_new_points pool gid ;
|
||||||
bootstrap = list_known_points pool gid ;
|
bootstrap = list_known_points pool gid ;
|
||||||
} in
|
} in
|
||||||
@ -471,7 +474,7 @@ let accept pool fd point =
|
|||||||
|
|
||||||
let read { messages } =
|
let read { messages } =
|
||||||
Lwt.catch
|
Lwt.catch
|
||||||
(fun () -> Lwt_pipe.pop messages >>= return)
|
(fun () -> Lwt_pipe.pop messages >>= fun ( _, msg) -> return msg)
|
||||||
(fun _ (* Closed *) -> fail P2p_io_scheduler.Connection_closed)
|
(fun _ (* Closed *) -> fail P2p_io_scheduler.Connection_closed)
|
||||||
|
|
||||||
let is_readable { messages } =
|
let is_readable { messages } =
|
||||||
|
@ -315,6 +315,13 @@ let create
|
|||||||
|
|
||||||
exception Closed
|
exception Closed
|
||||||
|
|
||||||
|
let read_size = function
|
||||||
|
| Ok buf -> (Sys.word_size / 8) * 8 + MBytes.length buf
|
||||||
|
| Error _ -> 0 (* we push Error only when we close the socket,
|
||||||
|
we don't fear memory leaks in that case... *)
|
||||||
|
|
||||||
|
let write_size mbytes = (Sys.word_size / 8) * 6 + MBytes.length mbytes
|
||||||
|
|
||||||
let register =
|
let register =
|
||||||
let cpt = ref 0 in
|
let cpt = ref 0 in
|
||||||
fun st conn ->
|
fun st conn ->
|
||||||
@ -324,8 +331,12 @@ let register =
|
|||||||
end else begin
|
end else begin
|
||||||
let id = incr cpt; !cpt in
|
let id = incr cpt; !cpt in
|
||||||
let canceler = Canceler.create () in
|
let canceler = Canceler.create () in
|
||||||
let read_queue = Lwt_pipe.create ?size:st.read_queue_size ()
|
let read_size =
|
||||||
and write_queue = Lwt_pipe.create ?size:st.write_queue_size () in
|
map_option st.read_queue_size ~f:(fun v -> v, read_size) in
|
||||||
|
let write_size =
|
||||||
|
map_option st.write_queue_size ~f:(fun v -> v, write_size) in
|
||||||
|
let read_queue = Lwt_pipe.create ?size:read_size () in
|
||||||
|
let write_queue = Lwt_pipe.create ?size:write_size () in
|
||||||
let read_conn =
|
let read_conn =
|
||||||
ReadScheduler.create_connection
|
ReadScheduler.create_connection
|
||||||
st.read_scheduler (conn, st.read_buffer_size) read_queue canceler id
|
st.read_scheduler (conn, st.read_buffer_size) read_queue canceler id
|
||||||
|
@ -41,7 +41,7 @@ val create:
|
|||||||
(** [create ~max_upload_speed ~max_download_speed ~read_queue_size
|
(** [create ~max_upload_speed ~max_download_speed ~read_queue_size
|
||||||
~write_queue_size ()] is an IO scheduler with specified (global)
|
~write_queue_size ()] is an IO scheduler with specified (global)
|
||||||
max upload (resp. download) speed, and specified read
|
max upload (resp. download) speed, and specified read
|
||||||
(resp. write) queue sizes for connections. *)
|
(resp. write) queue sizes (in bytes) for connections. *)
|
||||||
|
|
||||||
val register: t -> Lwt_unix.file_descr -> connection
|
val register: t -> Lwt_unix.file_descr -> connection
|
||||||
(** [register sched fd] is a [connection] managed by [sched]. *)
|
(** [register sched fd] is a [connection] managed by [sched]. *)
|
||||||
|
@ -10,25 +10,30 @@
|
|||||||
open Lwt.Infix
|
open Lwt.Infix
|
||||||
|
|
||||||
type 'a t =
|
type 'a t =
|
||||||
{ queue : 'a Queue.t ;
|
{ queue : (int * 'a) Queue.t ;
|
||||||
size : int option ;
|
mutable current_size : int ;
|
||||||
|
max_size : int ;
|
||||||
|
compute_size : ('a -> int) ;
|
||||||
mutable closed : bool ;
|
mutable closed : bool ;
|
||||||
mutable push_waiter : (unit Lwt.t * unit Lwt.u) option ;
|
mutable push_waiter : (unit Lwt.t * unit Lwt.u) option ;
|
||||||
mutable pop_waiter : (unit Lwt.t * unit Lwt.u) option ;
|
mutable pop_waiter : (unit Lwt.t * unit Lwt.u) option ;
|
||||||
empty: unit Lwt_condition.t ;
|
empty: unit Lwt_condition.t ;
|
||||||
full: unit Lwt_condition.t ;
|
|
||||||
not_full : unit Lwt_condition.t ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let create ?size () =
|
let create ?size () =
|
||||||
|
let max_size, compute_size =
|
||||||
|
match size with
|
||||||
|
| None -> max_int, (fun _ -> 0)
|
||||||
|
| Some (max_size, compute_size) ->
|
||||||
|
max_size, (fun e -> 4 * (Sys.word_size / 8) + compute_size e) in
|
||||||
{ queue = Queue.create () ;
|
{ queue = Queue.create () ;
|
||||||
size ;
|
current_size = 0 ;
|
||||||
|
max_size ;
|
||||||
|
compute_size ;
|
||||||
closed = false ;
|
closed = false ;
|
||||||
push_waiter = None ;
|
push_waiter = None ;
|
||||||
pop_waiter = None ;
|
pop_waiter = None ;
|
||||||
empty = Lwt_condition.create () ;
|
empty = Lwt_condition.create () ;
|
||||||
full = Lwt_condition.create () ;
|
|
||||||
not_full = Lwt_condition.create () ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let notify_push q =
|
let notify_push q =
|
||||||
@ -61,49 +66,40 @@ let wait_pop q =
|
|||||||
q.pop_waiter <- Some (waiter, wakener) ;
|
q.pop_waiter <- Some (waiter, wakener) ;
|
||||||
Lwt.protected waiter
|
Lwt.protected waiter
|
||||||
|
|
||||||
let available_space { size } len =
|
|
||||||
match size with
|
|
||||||
| None -> true
|
|
||||||
| Some size -> len < size
|
|
||||||
|
|
||||||
let length { queue } = Queue.length queue
|
let length { queue } = Queue.length queue
|
||||||
let is_empty { queue } = Queue.is_empty queue
|
let is_empty { queue } = Queue.is_empty queue
|
||||||
let is_full ({ queue } as q) = not (available_space q (Queue.length queue))
|
|
||||||
|
|
||||||
let rec empty q =
|
let rec empty q =
|
||||||
if is_empty q
|
if is_empty q
|
||||||
then Lwt.return_unit
|
then Lwt.return_unit
|
||||||
else (Lwt_condition.wait q.empty >>= fun () -> empty q)
|
else (Lwt_condition.wait q.empty >>= fun () -> empty q)
|
||||||
let rec full q =
|
|
||||||
if is_full q
|
|
||||||
then Lwt.return_unit
|
|
||||||
else (Lwt_condition.wait q.full >>= fun () -> full q)
|
|
||||||
let rec not_full q =
|
|
||||||
if not (is_empty q)
|
|
||||||
then Lwt.return_unit
|
|
||||||
else (Lwt_condition.wait q.not_full >>= fun () -> not_full q)
|
|
||||||
|
|
||||||
exception Closed
|
exception Closed
|
||||||
|
|
||||||
let rec push ({ closed ; queue ; full } as q) elt =
|
let rec push ({ closed ; queue ; current_size ;
|
||||||
let len = Queue.length queue in
|
max_size ; compute_size} as q) elt =
|
||||||
if closed then Lwt.fail Closed
|
let elt_size = compute_size elt in
|
||||||
else if available_space q len then begin
|
if closed then
|
||||||
Queue.push elt queue ;
|
Lwt.fail Closed
|
||||||
|
else if current_size + elt_size < max_size || Queue.is_empty queue then begin
|
||||||
|
Queue.push (elt_size, elt) queue ;
|
||||||
|
q.current_size <- current_size + elt_size ;
|
||||||
notify_push q ;
|
notify_push q ;
|
||||||
(if not (available_space q (len + 1)) then Lwt_condition.signal full ());
|
|
||||||
Lwt.return_unit
|
Lwt.return_unit
|
||||||
end else
|
end else
|
||||||
wait_pop q >>= fun () ->
|
wait_pop q >>= fun () ->
|
||||||
push q elt
|
push q elt
|
||||||
|
|
||||||
let rec push_now ({ closed ; queue ; full } as q) elt =
|
let rec push_now ({ closed ; queue ; compute_size ;
|
||||||
|
current_size ; max_size
|
||||||
|
} as q) elt =
|
||||||
if closed then raise Closed ;
|
if closed then raise Closed ;
|
||||||
let len = Queue.length queue in
|
let elt_size = compute_size elt in
|
||||||
available_space q len && begin
|
(current_size + elt_size < max_size || Queue.is_empty queue)
|
||||||
Queue.push elt queue ;
|
&& begin
|
||||||
|
Queue.push (elt_size, elt) queue ;
|
||||||
|
q.current_size <- current_size + elt_size ;
|
||||||
notify_push q ;
|
notify_push q ;
|
||||||
(if not (available_space q (len + 1)) then Lwt_condition.signal full ()) ;
|
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -112,27 +108,11 @@ exception Full
|
|||||||
let push_now_exn q elt =
|
let push_now_exn q elt =
|
||||||
if not (push_now q elt) then raise Full
|
if not (push_now q elt) then raise Full
|
||||||
|
|
||||||
let rec pop_all ({ closed ; queue ; empty ; not_full } as q) =
|
let rec pop ({ closed ; queue ; empty ; current_size } as q) =
|
||||||
let was_full = is_full q in
|
|
||||||
if not (Queue.is_empty queue) then
|
if not (Queue.is_empty queue) then
|
||||||
let queue_copy = Queue.copy queue in
|
let (elt_size, elt) = Queue.pop queue in
|
||||||
Queue.clear queue;
|
|
||||||
notify_pop q ;
|
notify_pop q ;
|
||||||
(if was_full then Lwt_condition.signal not_full ());
|
q.current_size <- current_size - elt_size ;
|
||||||
Lwt_condition.signal empty ();
|
|
||||||
Lwt.return queue_copy
|
|
||||||
else if closed then
|
|
||||||
Lwt.fail Closed
|
|
||||||
else
|
|
||||||
wait_push q >>= fun () ->
|
|
||||||
pop_all q
|
|
||||||
|
|
||||||
let rec pop ({ closed ; queue ; empty ; not_full } as q) =
|
|
||||||
let was_full = is_full q in
|
|
||||||
if not (Queue.is_empty queue) then
|
|
||||||
let elt = Queue.pop queue in
|
|
||||||
notify_pop q ;
|
|
||||||
(if was_full then Lwt_condition.signal not_full ());
|
|
||||||
(if Queue.length queue = 0 then Lwt_condition.signal empty ());
|
(if Queue.length queue = 0 then Lwt_condition.signal empty ());
|
||||||
Lwt.return elt
|
Lwt.return elt
|
||||||
else if closed then
|
else if closed then
|
||||||
@ -143,7 +123,7 @@ let rec pop ({ closed ; queue ; empty ; not_full } as q) =
|
|||||||
|
|
||||||
let rec peek ({ closed ; queue } as q) =
|
let rec peek ({ closed ; queue } as q) =
|
||||||
if not (Queue.is_empty queue) then
|
if not (Queue.is_empty queue) then
|
||||||
let elt = Queue.peek queue in
|
let (_elt_size, elt) = Queue.peek queue in
|
||||||
Lwt.return elt
|
Lwt.return elt
|
||||||
else if closed then
|
else if closed then
|
||||||
Lwt.fail Closed
|
Lwt.fail Closed
|
||||||
@ -153,28 +133,15 @@ let rec peek ({ closed ; queue } as q) =
|
|||||||
|
|
||||||
exception Empty
|
exception Empty
|
||||||
|
|
||||||
let pop_now_exn ({ closed ; queue ; empty ; not_full } as q) =
|
let pop_now_exn ({ closed ; queue ; empty ; current_size } as q) =
|
||||||
let was_full = is_full q in
|
|
||||||
if Queue.is_empty queue then
|
if Queue.is_empty queue then
|
||||||
(if closed then raise Closed else raise Empty) ;
|
(if closed then raise Closed else raise Empty) ;
|
||||||
let elt = Queue.pop queue in
|
let (elt_size, elt) = Queue.pop queue in
|
||||||
(if was_full then Lwt_condition.signal not_full ());
|
|
||||||
(if Queue.length queue = 0 then Lwt_condition.signal empty ());
|
(if Queue.length queue = 0 then Lwt_condition.signal empty ());
|
||||||
|
q.current_size <- current_size - elt_size ;
|
||||||
notify_pop q ;
|
notify_pop q ;
|
||||||
elt
|
elt
|
||||||
|
|
||||||
let pop_all_now ({ closed ; queue ; empty ; not_full } as q) =
|
|
||||||
let was_empty = is_empty q in
|
|
||||||
let was_full = is_full q in
|
|
||||||
if Queue.is_empty queue then
|
|
||||||
(if closed then raise Closed else raise Empty) ;
|
|
||||||
let queue_copy = Queue.copy queue in
|
|
||||||
Queue.clear queue ;
|
|
||||||
(if was_full then Lwt_condition.signal not_full ());
|
|
||||||
(if not was_empty then Lwt_condition.signal empty ());
|
|
||||||
notify_pop q ;
|
|
||||||
queue_copy
|
|
||||||
|
|
||||||
let pop_now q =
|
let pop_now q =
|
||||||
match pop_now_exn q with
|
match pop_now_exn q with
|
||||||
| exception Empty -> None
|
| exception Empty -> None
|
||||||
@ -195,7 +162,6 @@ let close q =
|
|||||||
q.closed <- true ;
|
q.closed <- true ;
|
||||||
notify_push q ;
|
notify_push q ;
|
||||||
notify_pop q ;
|
notify_pop q ;
|
||||||
Lwt_condition.broadcast_exn q.full Closed ;
|
|
||||||
end
|
end
|
||||||
|
|
||||||
let rec iter q ~f =
|
let rec iter q ~f =
|
||||||
|
@ -14,18 +14,15 @@
|
|||||||
type 'a t
|
type 'a t
|
||||||
(** Type of queues holding values of type ['a]. *)
|
(** Type of queues holding values of type ['a]. *)
|
||||||
|
|
||||||
val create : ?size:int -> unit -> 'a t
|
val create : ?size:(int * ('a -> int)) -> unit -> 'a t
|
||||||
(** [create ~size] is an empty queue that can hold max [size]
|
(** [create ~size:(max_size, compute_size)] is an empty queue that can
|
||||||
elements. *)
|
hold max [size] bytes of data, using [compute_size] to compute the
|
||||||
|
size of a datum. *)
|
||||||
|
|
||||||
val push : 'a t -> 'a -> unit Lwt.t
|
val push : 'a t -> 'a -> unit Lwt.t
|
||||||
(** [push q v] is a thread that blocks while [q] contains more
|
(** [push q v] is a thread that blocks while [q] contains more
|
||||||
than [size] elements, then adds [v] at the end of [q]. *)
|
than [size] elements, then adds [v] at the end of [q]. *)
|
||||||
|
|
||||||
val pop_all : 'a t -> 'a Queue.t Lwt.t
|
|
||||||
(** [pop' q] is a thread that returns all elements in [q] or waits
|
|
||||||
till there is at least one element in [q]. *)
|
|
||||||
|
|
||||||
val pop : 'a t -> 'a Lwt.t
|
val pop : 'a t -> 'a Lwt.t
|
||||||
(** [pop q] is a thread that blocks while [q] is empty, then
|
(** [pop q] is a thread that blocks while [q] is empty, then
|
||||||
removes and returns the first element in [q]. *)
|
removes and returns the first element in [q]. *)
|
||||||
@ -48,10 +45,6 @@ val push_now_exn : 'a t -> 'a -> unit
|
|||||||
(** [push_now q v] adds [v] at the ends of [q] immediately or
|
(** [push_now q v] adds [v] at the ends of [q] immediately or
|
||||||
raise [Full] if [q] is currently full. *)
|
raise [Full] if [q] is currently full. *)
|
||||||
|
|
||||||
val pop_all_now : 'a t -> 'a Queue.t
|
|
||||||
(** [pop_all_now q] is a copy of [q]'s internal queue, that may be
|
|
||||||
empty. *)
|
|
||||||
|
|
||||||
val pop_now : 'a t -> 'a option
|
val pop_now : 'a t -> 'a option
|
||||||
(** [pop_now q] maybe removes and returns the first element in [q] if
|
(** [pop_now q] maybe removes and returns the first element in [q] if
|
||||||
[q] contains at least one element. *)
|
[q] contains at least one element. *)
|
||||||
@ -68,18 +61,9 @@ val length : 'a t -> int
|
|||||||
val is_empty : 'a t -> bool
|
val is_empty : 'a t -> bool
|
||||||
(** [is_empty q] is [true] if [q] is empty, [false] otherwise. *)
|
(** [is_empty q] is [true] if [q] is empty, [false] otherwise. *)
|
||||||
|
|
||||||
val is_full : 'a t -> bool
|
|
||||||
(** [is_full q] is [true] if [q] is full, [false] otherwise. *)
|
|
||||||
|
|
||||||
val empty : 'a t -> unit Lwt.t
|
val empty : 'a t -> unit Lwt.t
|
||||||
(** [empty q] returns when [q] becomes empty. *)
|
(** [empty q] returns when [q] becomes empty. *)
|
||||||
|
|
||||||
val full : 'a t -> unit Lwt.t
|
|
||||||
(** [full q] returns when [q] becomes full. *)
|
|
||||||
|
|
||||||
val not_full : 'a t -> unit Lwt.t
|
|
||||||
(** [not_full q] returns when [q] stop being full. *)
|
|
||||||
|
|
||||||
val iter : 'a t -> f:('a -> unit Lwt.t) -> unit Lwt.t
|
val iter : 'a t -> f:('a -> unit Lwt.t) -> unit Lwt.t
|
||||||
(** [iter q ~f] pops all elements of [q] and applies [f] on them. *)
|
(** [iter q ~f] pops all elements of [q] and applies [f] on them. *)
|
||||||
|
|
||||||
|
@ -161,14 +161,14 @@ let client addr port =
|
|||||||
(* let's exchange a simple message. *)
|
(* let's exchange a simple message. *)
|
||||||
connect sched addr port id2 >>=? fun auth_fd ->
|
connect sched addr port id2 >>=? fun auth_fd ->
|
||||||
P2p_connection.accept auth_fd bytes_encoding >>=? fun conn ->
|
P2p_connection.accept auth_fd bytes_encoding >>=? fun conn ->
|
||||||
P2p_connection.read conn >>=? fun msg ->
|
P2p_connection.read conn >>=? fun (msg_size, msg) ->
|
||||||
assert (MBytes.compare simple_msg msg = 0) ;
|
assert (MBytes.compare simple_msg msg = 0) ;
|
||||||
P2p_connection.close conn >>= fun _stat ->
|
P2p_connection.close conn >>= fun _stat ->
|
||||||
lwt_log_notice "Simple OK" >>= fun () ->
|
lwt_log_notice "Simple OK" >>= fun () ->
|
||||||
(* let's detect a closed connection on `read`. *)
|
(* let's detect a closed connection on `read`. *)
|
||||||
connect sched addr port id2 >>=? fun auth_fd ->
|
connect sched addr port id2 >>=? fun auth_fd ->
|
||||||
P2p_connection.accept auth_fd bytes_encoding >>=? fun conn ->
|
P2p_connection.accept auth_fd bytes_encoding >>=? fun conn ->
|
||||||
P2p_connection.read conn >>=? fun msg ->
|
P2p_connection.read conn >>=? fun (msg_size, msg) ->
|
||||||
assert (MBytes.compare simple_msg msg = 0) ;
|
assert (MBytes.compare simple_msg msg = 0) ;
|
||||||
P2p_connection.read conn >>= fun msg ->
|
P2p_connection.read conn >>= fun msg ->
|
||||||
assert (is_connection_closed msg) ;
|
assert (is_connection_closed msg) ;
|
||||||
|
@ -170,8 +170,8 @@ let max_download_speed = ref None
|
|||||||
let max_upload_speed = ref None
|
let max_upload_speed = ref None
|
||||||
|
|
||||||
let read_buffer_size = ref (1 lsl 14)
|
let read_buffer_size = ref (1 lsl 14)
|
||||||
let read_queue_size = ref (Some 1)
|
let read_queue_size = ref (Some (1 lsl 14))
|
||||||
let write_queue_size = ref (Some 1)
|
let write_queue_size = ref (Some (1 lsl 14))
|
||||||
|
|
||||||
let delay = ref 60.
|
let delay = ref 60.
|
||||||
let clients = ref 8
|
let clients = ref 8
|
||||||
|
Loading…
Reference in New Issue
Block a user