gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnunet-scheme] 02/04: dht/client: Put weak references in id->operation-


From: gnunet
Subject: [gnunet-scheme] 02/04: dht/client: Put weak references in id->operation-map.
Date: Wed, 16 Feb 2022 22:19:08 +0100

This is an automated email from the git hooks/post-receive script.

maxime-devos pushed a commit to branch master
in repository gnunet-scheme.

commit 9eba8c6bd1ad6428f09eb84bc6bd80a130af3f34
Author: Maxime Devos <maximedevos@telenet.be>
AuthorDate: Wed Feb 16 20:49:39 2022 +0000

    dht/client: Put weak references in id->operation-map.
    
    * gnu/gnunet/dht/client.scm
      (<get>)[get:linger?]: New field.
      (start-get!): Add 'linger?' argument.
      (make-weak-reference,make-strong-reference,dereference): New
      procedures.
      (reconnect)[id->operation-map]: Add comment about weakness.
      (reconnect)[handlers]<msg:dht:client:result>: Handle the case where
      no 'found' procedure is available.
      (reconnect)[control]<start-get!>: Wrap the search object in a weak
      reference when not lingering.
      (reconnect)[control]request-search-result-iterator]: Dereference the
      weak reference, if any.
      (reconnect)[control]<resend-old-operations!>: Dereference the weak
      reference, if any.  Handle the case where the weak reference broke.
    * doc/distributed-hash-table.scm (start-get!): Document the new
      'linger?' argument.
---
 doc/distributed-hash-table.tm | 12 +++++-
 gnu/gnunet/dht/client.scm     | 85 ++++++++++++++++++++++++++++++++++---------
 2 files changed, 79 insertions(+), 18 deletions(-)

diff --git a/doc/distributed-hash-table.tm b/doc/distributed-hash-table.tm
index 784c804..b5b41f0 100644
--- a/doc/distributed-hash-table.tm
+++ b/doc/distributed-hash-table.tm
@@ -136,7 +136,8 @@
   used.<index|searching the DHT><index|inserting data into the DHT>
 
   <\explain>
-    <scm|(start-get! <var|server> <var|query> <var|found>)><index|start-get!>
+    <scm|(start-get! <var|server> <var|query> <var|found>
+    <var|#:linger?>=#true)><index|start-get!>
   <|explain>
     Search for data matching <var|query> in the DHT. When a datum is found,
     call the unary procedure <var|found> on the search result. It is possible
@@ -154,6 +155,15 @@
     internal buffers for the slices passed to <var|found>, which could be
     overwritten after the call to <var|found>. As such, it might be necessary
     to make a copy of the search result, using <scm|copy-search-result>.
+
+    When the boolean <var|linger?> is false, the search is automatically
+    cancelled when the search object becomes unreachable according to the GC.
+    <todo|actually implement this>
+
+    <\warning>
+      Guile currently (3.0.8) uses a conservative GC, so it cannot always
+      detect unreachability when it should.
+    </warning>
   </explain>
 
   <\explain>
diff --git a/gnu/gnunet/dht/client.scm b/gnu/gnunet/dht/client.scm
index 4ebaaa1..23f1d8d 100644
--- a/gnu/gnunet/dht/client.scm
+++ b/gnu/gnunet/dht/client.scm
@@ -79,11 +79,14 @@
          (only (guile)
                pk define-syntax-rule define* lambda* error
                make-hash-table hashq-set! hashq-remove! hashv-set! hashv-ref
-               hashv-remove! hash-clear! hash-map->list)
+               hashv-remove! hash-clear! hash-map->list
+               ->bool and=>)
          (only (ice-9 atomic)
                make-atomic-box atomic-box-ref atomic-box-set!)
          (only (ice-9 match)
                match)
+         (only (ice-9 weak-vector)
+               weak-vector weak-vector-ref weak-vector?)
          (only (gnu extractor enum)
                symbol-value)
          (only (fibers)
@@ -109,7 +112,7 @@
                cut-syntax)
          (only (rnrs base)
                and >= = quote * / + - define begin ... let*
-               quote case else values apply let cond if >
+               quote case else values apply let cond if > eq?
                <= expt assert exact? integer? lambda for-each
                not expt min max div-and-mod positive? define-syntax
                vector)
@@ -603,7 +606,17 @@ do anything if @var{server} has been permanently 
disconnected."
              (immutable found get:iterator) ; procedure accepting 
<search-result>
              (immutable query get:query) ; <query>
              (immutable unique-id get:unique-id)
-             (immutable options get:options)))
+             (immutable options get:options)
+             ;; TODO: actually cancel (using (gnu gnunet concurrency
+             ;; lost-and-found))
+             ;;
+             ;; If #false, 'reconnect' does not keep a strong reference to the
+             ;; search object and 'reconnect' will automatically cancel the
+             ;; search when the search object becomes unreachable.
+             ;;
+             ;; If #true, the search will not be automatically cancelled;
+             ;; 'reconnect' keeps a strong reference.
+             (immutable linger? get:linger?))) ; boolean
 
     (define-record-type (<put> %make-put put?)
       (fields (immutable server put:server)
@@ -654,7 +667,8 @@ do anything if @var{server} has been permanently 
disconnected."
             (assert (block-type? type))
             (value->index type))))
 
-    (define* (start-get! server query found)
+    ;; TODO(tests): Disable lingering by default, test linger?=#false
+    (define* (start-get! server query found #:key (linger? #true))
       "Search for data matching query in the DHT. When a datum is found, call
 the unary procedure @var{found} on the search result. It is possible to find
 multiple data matching a query. In that case, found is called multiple times.
@@ -669,12 +683,16 @@ to a separate fiber.
 To avoid expensive copies, the implementation can choose to reuse internal
 buffers for the slices passed to @var{found}, which could be overwritten after
 the call to @var{found}. As such, it might be necessary to make a copy of the
-search result, using @lisp{copy-search-result}."
+search result, using @lisp{copy-search-result}.
+
+When the boolean @var{linger?} is false, the search is automatically
+cancelled when the search object becomes unreachable according to the GC.
+TODO: implement this behaviour!"
       ;; TODO: options, xquery ...
       (define id (fresh-id server))
-      (define handle (%make-get server found query id 0)) ; TODO: options
-      ;; TODO: send 'found', 'id' and 'options' instead of sending the handle
-      ;; that has a reference to 'server' (for guardian reasons, TODO).
+      (define options 0) ; TODO: allow setting some options
+      (when linger? (assert (eq? linger? #true)))
+      (define handle (%make-get server found query id 0 (->bool linger?)))
       (maybe-send-control-message! server 'start-get! handle)
       handle)
 
@@ -744,6 +762,17 @@ code automatically tries to reconnect, so @var{connected} 
can be called after
                    ;; Any ‘small’ exact natural number will do.
                    (make-atomic-box 0)))
 
+    ;; TODO: put in new module?
+    (define (make-weak-reference to)
+      (weak-vector to))
+    (define (make-strong-reference to)
+      (assert (not (weak-vector? to)))
+      to)
+    (define (dereference reference)
+      (if (weak-vector? reference)
+         (weak-vector-ref reference 0)
+         reference))
+
     (define* (reconnect terminal-condition config
                        old-id->operation-map control-channel
                        #:key (spawn spawn-fiber)
@@ -757,6 +786,16 @@ code automatically tries to reconnect, so @var{connected} 
can be called after
       ;;
       ;; To avoid races, 'id->operation-map' and 'old-id->operation-map'
       ;; are only accessed from 'control'.
+      ;;
+      ;; To allow cancelling operations when they become unreachable, 
operations
+      ;; are wrapped in a weak reference (unless linger? is #true).  Otherwise,
+      ;; they won't ever become unreachable.  Keep in mind that, at least in
+      ;; Guile 3.0.7, weak references are broken when the object is returned
+      ;; from the guardian (and probably earlier) -- this seems to be a
+      ;; difficult to fix bug.
+      ;;
+      ;; This code is written to support both the correct and incorrect 
behaviour
+      ;; of guardians+weak vectors.
       (define id->operation-map (make-hash-table))
       (define (request-search-result-iterator unique-id)
        "Ask @code{control} what is the iterator for the get operation with
@@ -821,9 +860,10 @@ operation is cancelled, return @code{#false} instead."
                       (analyse-client-result slice))
                  (! handle (request-search-result-iterator unique-id))
                  (? (not handle)
-                    ;; Where did this unique id come from?
-                    (pk 'unique-id unique-id)
-                    TODO-error-reporting/1)
+                    ;; Perhaps the search object became unreachable;
+                    ;; 'process-stop-search' (see next commit) will be
+                    ;; called soon to inform the DHT service.
+                    (values))
                  (? (get? handle)
                     ;; TODO might not be true once monitoring operations
                     ;; are supported.
@@ -888,7 +928,10 @@ operation is cancelled, return @code{#false} instead."
          (('start-get! get)
           ;; Register the new get operation, such that we remember
           ;; where to send responses to.
-          (hashv-set! id->operation-map (get:unique-id get) get)
+          (hashv-set! id->operation-map (get:unique-id get)
+                      ((if (get:linger? get)
+                          make-strong-reference
+                          make-weak-reference) get))
           ;; (Asynchronuously) send the GET message.
           (send-get! mq get)
           ;; Continue!
@@ -911,7 +954,9 @@ operation is cancelled, return @code{#false} instead."
           (control))
          ;; Send by @code{request-search-result-iterator}.
          (#('request-search-result-iterator unique-id response-channel)
-          (put-message response-channel (hashv-ref id->operation-map 
unique-id))
+          (put-message response-channel
+                       (and=> (hashv-ref id->operation-map unique-id)
+                              dereference))
           ;; Continue!
           (control))
          (('resend-old-operations!)
@@ -919,12 +964,18 @@ operation is cancelled, return @code{#false} instead."
           ;; again.
           ;;
           ;; TODO: restarting monitoring operations
-          (for-each (lambda (get)
-                      (hashv-set! id->operation-map (get:unique-id get) get)
-                      (send-get! mq get))
+          (for-each (lambda (reference)
+                      (define get (dereference reference))
+                      ;; If the (weak) reference is broken, that means the
+                      ;; operation is unreachable, so then there is no point
+                      ;; to resending the get operation.
+                      (when get
+                        (hashv-set! id->operation-map (get:unique-id get)
+                                    reference)
+                        (send-get! mq get)))
                     ;; XXX: @code{hash-for-each} forms a continuation barrier,
                     ;; so turn the hash table into a list before iterating.
-                    (hash-map->list (lambda (x handle) handle)
+                    (hash-map->list (lambda (x reference) reference)
                                     old-id->operation-map))
           ;; Free some memory.
           (hash-clear! old-id->operation-map)

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]