ccnr_sendq.c

Go to the documentation of this file.
00001 /**
00002  * @file ccnr_sendq.c
00003  * 
00004  * Part of ccnr -  CCNx Repository Daemon.
00005  *
00006  */
00007 
00008 /*
00009  * Copyright (C) 2011 Palo Alto Research Center, Inc.
00010  *
00011  * This work is free software; you can redistribute it and/or modify it under
00012  * the terms of the GNU General Public License version 2 as published by the
00013  * Free Software Foundation.
00014  * This work is distributed in the hope that it will be useful, but WITHOUT ANY
00015  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00017  * for more details. You should have received a copy of the GNU General Public
00018  * License along with this program; if not, write to the
00019  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020  * Boston, MA 02110-1301, USA.
00021  */
00022  
00023 #include <errno.h>
00024 #include <fcntl.h>
00025 #include <limits.h>
00026 #include <netdb.h>
00027 #include <poll.h>
00028 #include <signal.h>
00029 #include <stddef.h>
00030 #include <stdint.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <time.h>
00035 #include <unistd.h>
00036 #include <arpa/inet.h>
00037 #include <sys/time.h>
00038 #include <sys/socket.h>
00039 #include <sys/stat.h>
00040 #include <sys/types.h>
00041 #include <sys/un.h>
00042 #include <netinet/in.h>
00043 
00044 #include <ccn/bloom.h>
00045 #include <ccn/ccn.h>
00046 #include <ccn/ccn_private.h>
00047 #include <ccn/charbuf.h>
00048 #include <ccn/face_mgmt.h>
00049 #include <ccn/hashtb.h>
00050 #include <ccn/indexbuf.h>
00051 #include <ccn/schedule.h>
00052 #include <ccn/reg_mgmt.h>
00053 #include <ccn/uri.h>
00054 
00055 #include "ccnr_private.h"
00056 
00057 #include "ccnr_sendq.h"
00058 
00059 #include "ccnr_io.h"
00060 #include "ccnr_link.h"
00061 #include "ccnr_msg.h"
00062 #include "ccnr_store.h"
00063 
00064 static int
00065 choose_face_delay(struct ccnr_handle *h, struct fdholder *fdholder, enum cq_delay_class c)
00066 {
00067     if (fdholder->flags & CCNR_FACE_CCND)
00068         return(1);
00069     if (fdholder->flags & CCNR_FACE_REPODATA)
00070         return(1);
00071     return(1);
00072 }
00073 
00074 static struct content_queue *
00075 content_queue_create(struct ccnr_handle *h, struct fdholder *fdholder, enum cq_delay_class c)
00076 {
00077     struct content_queue *q;
00078     unsigned usec;
00079     q = calloc(1, sizeof(*q));
00080     if (q != NULL) {
00081         usec = choose_face_delay(h, fdholder, c);
00082         q->burst_nsec = (usec <= 500 ? 500 : 150000); // XXX - needs a knob
00083         q->min_usec = usec;
00084         q->rand_usec = 2 * usec;
00085         q->nrun = 0;
00086         q->send_queue = ccn_indexbuf_create();
00087         if (q->send_queue == NULL) {
00088             free(q);
00089             return(NULL);
00090         }
00091         q->sender = NULL;
00092     }
00093     return(q);
00094 }
00095 
00096 PUBLIC void
00097 r_sendq_content_queue_destroy(struct ccnr_handle *h, struct content_queue **pq)
00098 {
00099     struct content_queue *q;
00100     if (*pq != NULL) {
00101         q = *pq;
00102         ccn_indexbuf_destroy(&q->send_queue);
00103         if (q->sender != NULL) {
00104             ccn_schedule_cancel(h->sched, q->sender);
00105             q->sender = NULL;
00106         }
00107         free(q);
00108         *pq = NULL;
00109     }
00110 }
00111 
00112 static enum cq_delay_class
00113 choose_content_delay_class(struct ccnr_handle *h, unsigned filedesc, int content_flags)
00114 {
00115     return(CCN_CQ_NORMAL); /* default */
00116 }
00117 
00118 static unsigned
00119 randomize_content_delay(struct ccnr_handle *h, struct content_queue *q)
00120 {
00121     unsigned usec;
00122     
00123     usec = q->min_usec + q->rand_usec;
00124     if (usec < 2)
00125         return(1);
00126     if (usec <= 20 || q->rand_usec < 2) // XXX - what is a good value for this?
00127         return(usec); /* small value, don't bother to randomize */
00128     usec = q->min_usec + (nrand48(h->seed) % q->rand_usec);
00129     if (usec < 2)
00130         return(1);
00131     return(usec);
00132 }
00133 
00134 static int
00135 content_sender(struct ccn_schedule *sched,
00136     void *clienth,
00137     struct ccn_scheduled_event *ev,
00138     int flags)
00139 {
00140     int i, j;
00141     int delay;
00142     int nsec;
00143     int burst_nsec;
00144     int burst_max;
00145     struct ccnr_handle *h = clienth;
00146     struct content_entry *content = NULL;
00147     unsigned filedesc = ev->evint;
00148     struct fdholder *fdholder = NULL;
00149     struct content_queue *q = ev->evdata;
00150     (void)sched;
00151     
00152     if ((flags & CCN_SCHEDULE_CANCEL) != 0)
00153         goto Bail;
00154     fdholder = r_io_fdholder_from_fd(h, filedesc);
00155     if (fdholder == NULL)
00156         goto Bail;
00157     if (q->send_queue == NULL)
00158         goto Bail;
00159     if ((fdholder->flags & CCNR_FACE_NOSEND) != 0)
00160         goto Bail;
00161     /* Send the content at the head of the queue */
00162     if (q->ready > q->send_queue->n ||
00163         (q->ready == 0 && q->nrun >= 12 && q->nrun < 120))
00164         q->ready = q->send_queue->n;
00165     nsec = 0;
00166     burst_nsec = q->burst_nsec;
00167     burst_max = 2;
00168     if (q->ready < burst_max)
00169         burst_max = q->ready;
00170     if (burst_max == 0)
00171         q->nrun = 0;
00172     for (i = 0; i < burst_max && nsec < 1000000; i++) {
00173         content = r_store_content_from_cookie(h, q->send_queue->buf[i]);
00174         if (content == NULL)
00175             q->nrun = 0;
00176         else {
00177             r_link_send_content(h, fdholder, content);
00178             /* fdholder may have vanished, bail out if it did */
00179             if (r_io_fdholder_from_fd(h, filedesc) == NULL)
00180                 goto Bail;
00181             // nsec += burst_nsec * (unsigned)((content->size + 1023) / 1024);
00182             q->nrun++;
00183         }
00184     }
00185     if (q->ready < i) abort();
00186     q->ready -= i;
00187     /* Update queue */
00188     for (j = 0; i < q->send_queue->n; i++, j++)
00189         q->send_queue->buf[j] = q->send_queue->buf[i];
00190     q->send_queue->n = j;
00191     /* Do a poll before going on to allow others to preempt send. */
00192     delay = (nsec + 499) / 1000 + 1;
00193     if (q->ready > 0) {
00194         return(delay);
00195     }
00196     q->ready = j;
00197     if (q->nrun >= 12 && q->nrun < 120) {
00198         /* We seem to be a preferred provider, forgo the randomized delay */
00199         if (j == 0)
00200             delay += burst_nsec / 50;
00201         return(delay);
00202     }
00203     /* Determine when to run again */
00204     for (i = 0; i < q->send_queue->n; i++) {
00205         content = r_store_content_from_cookie(h, q->send_queue->buf[i]);
00206         if (content != NULL) {
00207             q->nrun = 0;
00208             delay = randomize_content_delay(h, q);
00209             if (CCNSHOULDLOG(h, LM_8, CCNL_FINER))
00210                 ccnr_msg(h, "fdholder %u queued %u delay %i",
00211                          (unsigned)ev->evint, q->ready, delay);
00212             return(delay);
00213         }
00214     }
00215     q->send_queue->n = q->ready = 0;
00216 Bail:
00217     q->sender = NULL;
00218     return(0);
00219 }
00220 
00221 PUBLIC int
00222 r_sendq_face_send_queue_insert(struct ccnr_handle *h,
00223                        struct fdholder *fdholder, struct content_entry *content)
00224 {
00225     int ans = -1;
00226     int delay;
00227     enum cq_delay_class c;
00228     struct content_queue *q;
00229     if (fdholder == NULL || content == NULL || (fdholder->flags & CCNR_FACE_NOSEND) != 0)
00230         return(-1);
00231     c = choose_content_delay_class(h, fdholder->filedesc, r_store_content_flags(content));
00232     if (fdholder->q[c] == NULL)
00233         fdholder->q[c] = content_queue_create(h, fdholder, c);
00234     q = fdholder->q[c];
00235     if (q == NULL)
00236         return(-1);
00237     ans = ccn_indexbuf_set_insert(q->send_queue, r_store_content_cookie(h, content));
00238     if (q->sender == NULL) {
00239         delay = randomize_content_delay(h, q);
00240         q->ready = q->send_queue->n;
00241         q->sender = ccn_schedule_event(h->sched, delay,
00242                                        content_sender, q, fdholder->filedesc);
00243         if (CCNSHOULDLOG(h, LM_8, CCNL_FINER))
00244             ccnr_msg(h, "fdholder %u q %d delay %d usec", fdholder->filedesc, c, delay);
00245     }
00246     return (ans);
00247 }

Generated on Thu Feb 16 00:43:58 2012 for Content-Centric Networking in C by  doxygen 1.5.6