Merge branch 'lwt_pipes_limit' into 'master'

Lwt_pipe: limit by content size in bytes

See merge request !137
This commit is contained in:
Grégoire Henry 2017-01-24 00:05:07 +01:00
commit ec0e7d4d48
9 changed files with 92 additions and 128 deletions

View File

@ -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

View File

@ -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. *)

View File

@ -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 } =

View File

@ -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

View File

@ -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]. *)

View File

@ -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 =

View File

@ -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. *)

View File

@ -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) ;

View File

@ -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