Statistics
| Branch: | Revision:

pstreamer / src / transaction.c @ bdfb47bf

History | View | Annotate | Download (7 KB)

1
/*
2
 * Copyright (c) 2010-2011 Stefano Traverso
3
 * Copyright (c) 2010-2011 Csaba Kiraly
4
 * Copyright (c) 2017 Luca Baldesi
5
 *
6
 * This file is part of PeerStreamer.
7
 *
8
 * PeerStreamer is free software: you can redistribute it and/or
9
 * modify it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * PeerStreamer is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
16
 * General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with PeerStreamer.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22

    
23
#include <stdint.h>
24
#include <stdio.h>
25
#include <stdbool.h>
26
#include <stdlib.h>
27
#include <sys/time.h>
28

    
29
#include "dbg.h"
30
#include "measures.h"
31
#include "transaction.h"
32

    
33
typedef struct {
34
        uint16_t trans_id;
35
        double offer_sent_time;
36
        double accept_received_time;
37
        struct nodeID *id;
38
        } service_time;
39

    
40
// List to trace peer's service times
41
struct service_times_element {
42
        service_time st;
43
        struct service_times_element *backward;
44
        struct service_times_element *forward;
45
        };
46

    
47

    
48
void _transaction_remove(struct service_times_element ** head, struct service_times_element *stl)
49
{
50
        if (stl->backward == NULL) {
51
                if (stl->forward)
52
                {
53
                        *head = stl->forward;
54
                        (*head)->backward = NULL;
55
                } else
56
                        *head = NULL;
57
        }
58
        else {
59
                if (stl->forward == NULL)
60
                        stl->backward->forward = NULL;
61
                else {
62
                        stl->backward->forward = stl->forward;
63
                        stl->forward->backward = stl->backward;
64
                }
65
        }
66
        nodeid_free(stl->st.id);
67
        free(stl);
68
}        
69

    
70
// Check the service times list to find elements over the timeout
71
void check_neighbor_status_list(struct service_times_element ** stl) {
72
        struct service_times_element *stl_iterator, *stl_aux;
73
        struct timeval current_time;
74

    
75
        gettimeofday(&current_time, NULL);
76
        
77
        dprintf("LIST: check trans_id list\n");
78
        
79
        // Check if list is empty
80
        if (*stl == NULL) {
81
                return;
82
                }
83
        
84
        // Start from the beginning of the list
85
        stl_iterator = *stl;
86
        stl_aux = stl_iterator->forward;
87
        // Iterate the list until you get the right element
88
        while (stl_iterator != NULL) {
89
                // If the element has been in the list for a period greater than the timeout, remove it
90
//                if ( (stl_iterator->st.accept_received_time > 0.0 && ( (current_time.tv_sec + current_time.tv_usec*1e-6) - stl_iterator->st.accept_received_time) > TRANS_ID_MAX_LIFETIME) ||  ((current_time.tv_sec + current_time.tv_usec*1e-6) - stl_iterator->st.offer_sent_time > TRANS_ID_MAX_LIFETIME ) ) {
91
                if ( (current_time.tv_sec + current_time.tv_usec*1e-6 - stl_iterator->st.offer_sent_time) > TRANS_ID_MAX_LIFETIME) {
92
                         dprintf("LIST TIMEOUT: trans_id %d, offer_sent_time %f, accept_received_time %f\n", stl_iterator->st.trans_id, (double) ((current_time.tv_sec + current_time.tv_usec*1e-6) - stl_iterator->st.offer_sent_time  ), (double) ((current_time.tv_sec + current_time.tv_usec*1e-6) - stl_iterator->st.accept_received_time));
93
                         //fprintf(stderr, "LIST TIMEOUT: trans_id %d, offer_sent_time %f, accept_received_time %f\n", stl_iterator->st.trans_id, (double) ((current_time.tv_sec + current_time.tv_usec*1e-6) - stl_iterator->st.offer_sent_time  ), (double) ((current_time.tv_sec + current_time.tv_usec*1e-6) - stl_iterator->st.accept_received_time));
94
#ifndef MONL
95
                        timeout_reception_measure(stl_iterator->st.id);
96
#endif
97
                _transaction_remove(stl, stl_iterator);
98

    
99
                        // Free the memory
100
                }
101
                stl_iterator = stl_aux;
102
                if (stl_iterator)
103
                        stl_aux = stl_aux->forward;
104
        }
105
        return;
106
}
107

    
108
// register the moment when a transaction is started
109
// return a  new transaction id or 0 in case of failure
110
uint16_t transaction_create(struct service_times_element ** stl, struct nodeID *id)
111
{
112
        struct service_times_element *stl2;
113
        struct timeval current_time;
114

    
115
        if (stl && id)
116
        {
117
                check_neighbor_status_list(stl);
118

    
119
                gettimeofday(&current_time, NULL);
120

    
121

    
122
                // create a new element in the list with its offer_sent_time and set accept_received_time to -1.0
123
                stl2 = (struct service_times_element*) malloc(sizeof(struct service_times_element));
124
                stl2->st.offer_sent_time = current_time.tv_sec + current_time.tv_usec*1e-6;
125
                stl2->st.accept_received_time = -1.0;
126
                stl2->st.id = nodeid_dup(id);
127

    
128
                stl2->backward = NULL;
129

    
130
                if (*stl)
131
                {
132
                        stl2->st.trans_id = (*stl)->st.trans_id + 1 ? (*stl)->st.trans_id + 1 : 1;
133
                        (*stl)->backward = stl2;
134
                        stl2->forward = (*stl);
135
                        *stl = stl2;
136
                } else {
137
                        stl2->st.trans_id = 1;
138
                        stl2->forward = NULL;
139
                        *stl = stl2;
140
                }
141
                dprintf("LIST: adding trans_id %d to the list, offer_sent_time %f -- LIST IS NOT EMPTY\n", stl2->st.trans_id, (current_time.tv_sec + current_time.tv_usec*1e-6));
142

    
143
                return stl2->st.trans_id;
144
        }
145
        return 0;
146
}
147

    
148

    
149
// Add the moment I received a positive select in a list
150
// return true if a valid trans_id is found
151
bool transaction_reg_accept(struct service_times_element * stl, uint16_t trans_id,const struct nodeID *id)
152
{
153
        struct service_times_element *stl_iterator;
154
        struct timeval current_time;
155

    
156
        if (stl && id && trans_id)
157
        {
158
                gettimeofday(&current_time, NULL);
159
                stl_iterator = stl;
160

    
161
                // if an accept was received, look for the trans_id and add current_time to accept_received_time field
162
                dprintf("LIST: changing trans_id %d to the list, accept received %f\n", trans_id, current_time.tv_sec + current_time.tv_usec*1e-6);
163
                // Iterate the list until you get the right element
164
                while (stl_iterator != NULL) {
165
                                if (stl_iterator->st.trans_id == trans_id) {
166
                                        stl_iterator->st.accept_received_time = current_time.tv_sec + current_time.tv_usec*1e-6;
167
        #ifndef MONL
168
                                        offer_accept_rtt_measure(id,stl_iterator->st.accept_received_time - stl_iterator->st.offer_sent_time);
169
                                        reception_measure(id);
170
        #endif
171
                                        return true;
172
                                        }
173
                                stl_iterator = stl_iterator->forward;
174
                }
175
        }
176
        return false;
177
}
178

    
179
// Used to get the time elapsed from the moment I get a positive select to the moment i get the ACK
180
// related to the same chunk
181
// it return -1.0 in case no trans_id is found
182
double transaction_remove(struct service_times_element ** stl, uint16_t trans_id) {
183
        struct service_times_element *stl_iterator;
184
        double to_return;
185

    
186
    dprintf("LIST: deleting trans_id %d\n", trans_id);
187

    
188
        // Start from the beginning of the list
189
        stl_iterator = *stl;
190
        // Iterate the list until you get the right element
191
        while (stl_iterator != NULL) {
192
                if (stl_iterator->st.trans_id == trans_id)
193
                        break;
194
                stl_iterator = stl_iterator->forward;
195
                }
196
        if (stl_iterator == NULL){
197
                // not found
198
        dprintf("LIST: deleting trans_id %d -- STL is already NULL \n", trans_id);
199
                return -2.0;
200
        }
201
        
202
#ifndef MONL
203
        // This function is called when an ACK is received, so:
204
        reception_measure(stl_iterator->st.id);
205
#endif
206

    
207
        to_return = stl_iterator->st.accept_received_time;
208

    
209
        _transaction_remove(stl, stl_iterator);
210

    
211
        return to_return;
212
}
213

    
214
void transaction_destroy(struct service_times_element ** head)
215
{
216
        while(*head)
217
        {
218
                _transaction_remove(head, *head);
219
                // in case of nodeid_dup we should free that as well
220
        }
221

    
222
}