summaryrefslogtreecommitdiff
path: root/ot_vector.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_vector.c')
-rw-r--r--ot_vector.c247
1 files changed, 134 insertions, 113 deletions
diff --git a/ot_vector.c b/ot_vector.c
index 2a632b2..2acfbef 100644
--- a/ot_vector.c
+++ b/ot_vector.c
@@ -4,39 +4,37 @@
4 $id$ */ 4 $id$ */
5 5
6/* System */ 6/* System */
7#include <stddef.h>
8#include <stdint.h>
7#include <stdlib.h> 9#include <stdlib.h>
8#include <string.h> 10#include <string.h>
9#include <strings.h> 11#include <strings.h>
10#include <stdint.h>
11 12
12/* Opentracker */ 13/* Opentracker */
13#include "trackerlogic.h" 14#include "trackerlogic.h"
14#include "ot_vector.h"
15 15
16/* Libowfat */ 16/* Libowfat */
17#include "uint32.h"
18#include "uint16.h" 17#include "uint16.h"
18#include "uint32.h"
19 19
20static int vector_compare_peer(const void *peer1, const void *peer2 ) { 20static int vector_compare_peer6(const void *peer1, const void *peer2) { return memcmp(peer1, peer2, OT_PEER_COMPARE_SIZE6); }
21 return memcmp( peer1, peer2, OT_PEER_COMPARE_SIZE ); 21static int vector_compare_peer4(const void *peer1, const void *peer2) { return memcmp(peer1, peer2, OT_PEER_COMPARE_SIZE4); }
22}
23 22
24/* This function gives us a binary search that returns a pointer, even if 23/* This function gives us a binary search that returns a pointer, even if
25 no exact match is found. In that case it sets exactmatch 0 and gives 24 no exact match is found. In that case it sets exactmatch 0 and gives
26 calling functions the chance to insert data 25 calling functions the chance to insert data
27*/ 26*/
28void *binary_search( const void * const key, const void * base, const size_t member_count, const size_t member_size, 27void *binary_search(const void *const key, const void *base, const size_t member_count, const size_t member_size, size_t compare_size, int *exactmatch) {
29 size_t compare_size, int *exactmatch ) {
30 size_t interval = member_count; 28 size_t interval = member_count;
31 29
32 while( interval ) { 30 while (interval) {
33 uint8_t *lookat = ((uint8_t*)base) + member_size * ( interval / 2 ); 31 uint8_t *lookat = ((uint8_t *)base) + member_size * (interval / 2);
34 int cmp = memcmp( lookat, key, compare_size ); 32 int cmp = memcmp(lookat, key, compare_size);
35 if(cmp == 0 ) { 33 if (cmp == 0) {
36 base = lookat; 34 base = lookat;
37 break; 35 break;
38 } 36 }
39 if(cmp < 0) { 37 if (cmp < 0) {
40 base = lookat + member_size; 38 base = lookat + member_size;
41 interval--; 39 interval--;
42 } 40 }
@@ -44,13 +42,14 @@ void *binary_search( const void * const key, const void * base, const size_t mem
44 } 42 }
45 43
46 *exactmatch = interval; 44 *exactmatch = interval;
47 return (void*)base; 45 return (void *)base;
48} 46}
49 47
50static uint8_t vector_hash_peer( ot_peer *peer, int bucket_count ) { 48static uint8_t vector_hash_peer(ot_peer const *peer, size_t compare_size, int bucket_count) {
51 unsigned int hash = 5381, i = OT_PEER_COMPARE_SIZE; 49 unsigned int hash = 5381;
52 uint8_t *p = (uint8_t*)peer; 50 uint8_t *p = (uint8_t *)peer;
53 while( i-- ) hash += (hash<<5) + *(p++); 51 while (compare_size--)
52 hash += (hash << 5) + *(p++);
54 return hash % bucket_count; 53 return hash % bucket_count;
55} 54}
56 55
@@ -61,48 +60,65 @@ static uint8_t vector_hash_peer( ot_peer *peer, int bucket_count ) {
61 if it wasn't found in vector. Caller needs to check the passed "exactmatch" variable to see, whether an insert 60 if it wasn't found in vector. Caller needs to check the passed "exactmatch" variable to see, whether an insert
62 took place. If resizing the vector failed, NULL is returned, else the pointer to the object in vector. 61 took place. If resizing the vector failed, NULL is returned, else the pointer to the object in vector.
63*/ 62*/
64void *vector_find_or_insert( ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch ) { 63void *vector_find_or_insert(ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch) {
65 uint8_t *match = binary_search( key, vector->data, vector->size, member_size, compare_size, exactmatch ); 64 uint8_t *match = binary_search(key, vector->data, vector->size, member_size, compare_size, exactmatch);
65
66 if (*exactmatch)
67 return match;
68
69 if (vector->size + 1 > vector->space) {
70 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
71 ptrdiff_t match_off = match - (uint8_t *)vector->data;
72 uint8_t *new_data = realloc(vector->data, new_space * member_size);
66 73
67 if( *exactmatch ) return match; 74 if (!new_data)
75 return NULL;
68 76
69 if( vector->size + 1 > vector->space ) {
70 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
71 uint8_t *new_data = realloc( vector->data, new_space * member_size );
72 if( !new_data ) return NULL;
73 /* Adjust pointer if it moved by realloc */ 77 /* Adjust pointer if it moved by realloc */
74 match = new_data + (match - (uint8_t*)vector->data); 78 match = new_data + match_off;
75 79
76 vector->data = new_data; 80 vector->data = new_data;
77 vector->space = new_space; 81 vector->space = new_space;
78 } 82 }
79 memmove( match + member_size, match, ((uint8_t*)vector->data) + member_size * vector->size - match ); 83 memmove(match + member_size, match, ((uint8_t *)vector->data) + member_size * vector->size - match);
80 84
81 vector->size++; 85 vector->size++;
82 return match; 86 return match;
83} 87}
84 88
85ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exactmatch ) { 89ot_peer *vector_find_or_insert_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch) {
86 ot_peer *match; 90 ot_peer *match, *end;
91 const size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
92 size_t match_to_end;
87 93
88 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */ 94 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */
89 if( vector->space < vector->size ) 95 if (vector->space < vector->size)
90 vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size ); 96 vector = ((ot_vector *)vector->data) + vector_hash_peer(peer, compare_size, vector->size);
91 match = (ot_peer*)binary_search( peer, vector->data, vector->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, exactmatch ); 97 match = binary_search(peer, vector->data, vector->size, peer_size, compare_size, exactmatch);
92 98
93 if( *exactmatch ) return match; 99 if (*exactmatch)
100 return match;
94 101
95 if( vector->size + 1 > vector->space ) { 102 /* This is the amount of bytes that needs to be pushed backwards by peer_size bytes to make room for new peer */
96 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; 103 end = (ot_peer *)vector->data + vector->size * peer_size;
97 ot_peer *new_data = realloc( vector->data, new_space * sizeof(ot_peer) ); 104 match_to_end = end - match;
98 if( !new_data ) return NULL; 105
106 if (vector->size + 1 > vector->space) {
107 ptrdiff_t offset = match - (ot_peer *)vector->data;
108 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
109 ot_peer *new_data = realloc(vector->data, new_space * peer_size);
110
111 if (!new_data)
112 return NULL;
99 /* Adjust pointer if it moved by realloc */ 113 /* Adjust pointer if it moved by realloc */
100 match = new_data + (match - (ot_peer*)vector->data); 114 match = new_data + offset;
101 115
102 vector->data = new_data; 116 vector->data = new_data;
103 vector->space = new_space; 117 vector->space = new_space;
104 } 118 }
105 memmove( match + 1, match, sizeof(ot_peer) * ( ((ot_peer*)vector->data) + vector->size - match ) ); 119
120 /* Here we're guaranteed to have enough space in vector to move the block of peers after insertion point */
121 memmove(match + peer_size, match, match_to_end);
106 122
107 vector->size++; 123 vector->size++;
108 return match; 124 return match;
@@ -113,126 +129,134 @@ ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exac
113 1 if a non-seeding peer was removed 129 1 if a non-seeding peer was removed
114 2 if a seeding peer was removed 130 2 if a seeding peer was removed
115*/ 131*/
116int vector_remove_peer( ot_vector *vector, ot_peer *peer ) { 132int vector_remove_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size) {
117 int exactmatch; 133 int exactmatch, was_seeder;
118 ot_peer *match, *end; 134 ot_peer *match, *end;
135 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
119 136
120 if( !vector->size ) return 0; 137 if (!vector->size)
138 return 0;
121 139
122 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */ 140 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */
123 if( vector->space < vector->size ) 141 if (vector->space < vector->size)
124 vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size ); 142 vector = ((ot_vector *)vector->data) + vector_hash_peer(peer, compare_size, vector->size);
125 143
126 end = ((ot_peer*)vector->data) + vector->size; 144 end = ((ot_peer *)vector->data) + peer_size * vector->size;
127 match = (ot_peer*)binary_search( peer, vector->data, vector->size, sizeof(ot_peer), OT_PEER_COMPARE_SIZE, &exactmatch ); 145 match = (ot_peer *)binary_search(peer, vector->data, vector->size, peer_size, compare_size, &exactmatch);
128 if( !exactmatch ) return 0; 146 if (!exactmatch)
147 return 0;
129 148
130 exactmatch = ( OT_PEERFLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1; 149 was_seeder = (OT_PEERFLAG_D(match, peer_size) & PEER_FLAG_SEEDING) ? 2 : 1;
131 memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) ); 150 memmove(match, match + peer_size, end - match - peer_size);
132 151
133 vector->size--; 152 vector->size--;
134 vector_fixup_peers( vector ); 153 vector_fixup_peers(vector, peer_size);
135 return exactmatch; 154 return was_seeder;
136} 155}
137 156
138void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) { 157void vector_remove_torrent(ot_vector *vector, ot_torrent *match) {
139 ot_torrent *end = ((ot_torrent*)vector->data) + vector->size; 158 ot_torrent *end = ((ot_torrent *)vector->data) + vector->size;
140 159
141 if( !vector->size ) return; 160 if (!vector->size)
161 return;
142 162
143 /* If this is being called after a unsuccessful malloc() for peer_list 163 /* If this is being called after a unsuccessful malloc() for peer_list
144 in add_peer_to_torrent, match->peer_list actually might be NULL */ 164 in add_peer_to_torrent, match->peer_list actually might be NULL */
145 if( match->peer_list) free_peerlist( match->peer_list ); 165 free_peerlist(match->peer_list6);
166 free_peerlist(match->peer_list4);
146 167
147 memmove( match, match + 1, sizeof(ot_torrent) * ( end - match - 1 ) ); 168 memmove(match, match + 1, sizeof(ot_torrent) * (end - match - 1));
148 if( ( --vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && ( vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS ) ) { 169 if ((--vector->size * OT_VECTOR_SHRINK_THRESH < vector->space) && (vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS)) {
149 vector->space /= OT_VECTOR_SHRINK_RATIO; 170 vector->space /= OT_VECTOR_SHRINK_RATIO;
150 vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) ); 171 vector->data = realloc(vector->data, vector->space * sizeof(ot_torrent));
151 } 172 }
152} 173}
153 174
154void vector_clean_list( ot_vector * vector, int num_buckets ) { 175void vector_clean_list(ot_vector *vector, int num_buckets) {
155 while( num_buckets-- ) 176 while (num_buckets--)
156 free( vector[num_buckets].data ); 177 free(vector[num_buckets].data);
157 free( vector ); 178 free(vector);
158 return; 179 return;
159} 180}
160 181
161void vector_redistribute_buckets( ot_peerlist * peer_list ) { 182void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size) {
162 int tmp, bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1; 183 int tmp, bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1;
163 ot_vector * bucket_list_new, * bucket_list_old = &peer_list->peers; 184 ot_vector *bucket_list_new, *bucket_list_old = &peer_list->peers;
185 int (*sort_func)(const void *, const void *) = peer_size == OT_PEER_SIZE6 ? &vector_compare_peer6 : &vector_compare_peer4;
164 186
165 if( OT_PEERLIST_HASBUCKETS( peer_list ) ) { 187 if (OT_PEERLIST_HASBUCKETS(peer_list)) {
166 num_buckets_old = peer_list->peers.size; 188 num_buckets_old = peer_list->peers.size;
167 bucket_list_old = peer_list->peers.data; 189 bucket_list_old = peer_list->peers.data;
168 } 190 }
169 191
170 if( peer_list->peer_count < 255 ) 192 if (peer_list->peer_count < 255)
171 num_buckets_new = 1; 193 num_buckets_new = 1;
172 else if( peer_list->peer_count > 8192 ) 194 else if (peer_list->peer_count > 8192)
173 num_buckets_new = 64; 195 num_buckets_new = 64;
174 else if( peer_list->peer_count >= 512 && peer_list->peer_count < 4096 ) 196 else if (peer_list->peer_count >= 512 && peer_list->peer_count < 4096)
175 num_buckets_new = 16; 197 num_buckets_new = 16;
176 else if( peer_list->peer_count < 512 && num_buckets_old <= 16 ) 198 else if (peer_list->peer_count < 512 && num_buckets_old <= 16)
177 num_buckets_new = num_buckets_old; 199 num_buckets_new = num_buckets_old;
178 else if( peer_list->peer_count < 512 ) 200 else if (peer_list->peer_count < 512)
179 num_buckets_new = 1; 201 num_buckets_new = 1;
180 else if( peer_list->peer_count < 8192 && num_buckets_old > 1 ) 202 else if (peer_list->peer_count < 8192 && num_buckets_old > 1)
181 num_buckets_new = num_buckets_old; 203 num_buckets_new = num_buckets_old;
182 else 204 else
183 num_buckets_new = 16; 205 num_buckets_new = 16;
184 206
185 if( num_buckets_new == num_buckets_old ) 207 if (num_buckets_new == num_buckets_old)
186 return; 208 return;
187 209
188 /* Assume near perfect distribution */ 210 /* Assume near perfect distribution */
189 bucket_list_new = malloc( num_buckets_new * sizeof( ot_vector ) ); 211 bucket_list_new = malloc(num_buckets_new * sizeof(ot_vector));
190 if( !bucket_list_new) return; 212 if (!bucket_list_new)
191 bzero( bucket_list_new, num_buckets_new * sizeof( ot_vector ) ); 213 return;
214 bzero(bucket_list_new, num_buckets_new * sizeof(ot_vector));
192 215
193 tmp = peer_list->peer_count / num_buckets_new; 216 tmp = peer_list->peer_count / num_buckets_new;
194 bucket_size_new = OT_VECTOR_MIN_MEMBERS; 217 bucket_size_new = OT_VECTOR_MIN_MEMBERS;
195 while( bucket_size_new < tmp) 218 while (bucket_size_new < tmp)
196 bucket_size_new *= OT_VECTOR_GROW_RATIO; 219 bucket_size_new *= OT_VECTOR_GROW_RATIO;
197 220
198 /* preallocate vectors to hold all peers */ 221 /* preallocate vectors to hold all peers */
199 for( bucket=0; bucket<num_buckets_new; ++bucket ) { 222 for (bucket = 0; bucket < num_buckets_new; ++bucket) {
200 bucket_list_new[bucket].space = bucket_size_new; 223 bucket_list_new[bucket].space = bucket_size_new;
201 bucket_list_new[bucket].data = malloc( bucket_size_new * sizeof(ot_peer) ); 224 bucket_list_new[bucket].data = malloc(bucket_size_new * peer_size);
202 if( !bucket_list_new[bucket].data ) 225 if (!bucket_list_new[bucket].data)
203 return vector_clean_list( bucket_list_new, num_buckets_new ); 226 return vector_clean_list(bucket_list_new, num_buckets_new);
204 } 227 }
205 228
206 /* Now sort them into the correct bucket */ 229 /* Now sort them into the correct bucket */
207 for( bucket=0; bucket<num_buckets_old; ++bucket ) { 230 for (bucket = 0; bucket < num_buckets_old; ++bucket) {
208 ot_peer * peers_old = bucket_list_old[bucket].data, * peers_new; 231 ot_peer *peers_old = bucket_list_old[bucket].data;
209 int peer_count_old = bucket_list_old[bucket].size; 232 int peer_count_old = bucket_list_old[bucket].size;
210 while( peer_count_old-- ) { 233 while (peer_count_old--) {
211 ot_vector * bucket_dest = bucket_list_new; 234 ot_vector *bucket_dest = bucket_list_new;
212 if( num_buckets_new > 1 ) 235 if (num_buckets_new > 1)
213 bucket_dest += vector_hash_peer(peers_old, num_buckets_new); 236 bucket_dest += vector_hash_peer(peers_old, OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size), num_buckets_new);
214 if( bucket_dest->size + 1 > bucket_dest->space ) { 237 if (bucket_dest->size + 1 > bucket_dest->space) {
215 void * tmp = realloc( bucket_dest->data, sizeof(ot_peer) * OT_VECTOR_GROW_RATIO * bucket_dest->space ); 238 void *tmp = realloc(bucket_dest->data, peer_size * OT_VECTOR_GROW_RATIO * bucket_dest->space);
216 if( !tmp ) return vector_clean_list( bucket_list_new, num_buckets_new ); 239 if (!tmp)
240 return vector_clean_list(bucket_list_new, num_buckets_new);
217 bucket_dest->data = tmp; 241 bucket_dest->data = tmp;
218 bucket_dest->space *= OT_VECTOR_GROW_RATIO; 242 bucket_dest->space *= OT_VECTOR_GROW_RATIO;
219 } 243 }
220 peers_new = (ot_peer*)bucket_dest->data; 244 memcpy((ot_peer *)bucket_dest->data + peer_size * bucket_dest->size++, peers_old, peer_size);
221 memcpy(peers_new + bucket_dest->size++, peers_old++, sizeof(ot_peer)); 245 peers_old += peer_size;
222 } 246 }
223 } 247 }
224 248
225 /* Now sort each bucket to later allow bsearch */ 249 /* Now sort each bucket to later allow bsearch */
226 for( bucket=0; bucket<num_buckets_new; ++bucket ) 250 for (bucket = 0; bucket < num_buckets_new; ++bucket)
227 qsort( bucket_list_new[bucket].data, bucket_list_new[bucket].size, sizeof( ot_peer ), vector_compare_peer ); 251 qsort(bucket_list_new[bucket].data, bucket_list_new[bucket].size, peer_size, sort_func);
228 252
229 /* Everything worked fine. Now link new bucket_list to peer_list */ 253 /* Everything worked fine. Now link new bucket_list to peer_list */
230 if( OT_PEERLIST_HASBUCKETS( peer_list) ) 254 if (OT_PEERLIST_HASBUCKETS(peer_list))
231 vector_clean_list( (ot_vector*)peer_list->peers.data, peer_list->peers.size ); 255 vector_clean_list((ot_vector *)peer_list->peers.data, peer_list->peers.size);
232 else 256 else
233 free( peer_list->peers.data ); 257 free(peer_list->peers.data);
234 258
235 if( num_buckets_new > 1 ) { 259 if (num_buckets_new > 1) {
236 peer_list->peers.data = bucket_list_new; 260 peer_list->peers.data = bucket_list_new;
237 peer_list->peers.size = num_buckets_new; 261 peer_list->peers.size = num_buckets_new;
238 peer_list->peers.space = 0; /* Magic marker for "is list of buckets" */ 262 peer_list->peers.space = 0; /* Magic marker for "is list of buckets" */
@@ -240,27 +264,24 @@ void vector_redistribute_buckets( ot_peerlist * peer_list ) {
240 peer_list->peers.data = bucket_list_new->data; 264 peer_list->peers.data = bucket_list_new->data;
241 peer_list->peers.size = bucket_list_new->size; 265 peer_list->peers.size = bucket_list_new->size;
242 peer_list->peers.space = bucket_list_new->space; 266 peer_list->peers.space = bucket_list_new->space;
243 free( bucket_list_new ); 267 free(bucket_list_new);
244 } 268 }
245} 269}
246 270
247void vector_fixup_peers( ot_vector * vector ) { 271void vector_fixup_peers(ot_vector *vector, size_t peer_size) {
248 int need_fix = 0; 272 int need_fix = 0;
249 273
250 if( !vector->size ) { 274 if (!vector->size) {
251 free( vector->data ); 275 free(vector->data);
252 vector->data = NULL; 276 vector->data = NULL;
253 vector->space = 0; 277 vector->space = 0;
254 return; 278 return;
255 } 279 }
256 280
257 while( ( vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && 281 while ((vector->size * OT_VECTOR_SHRINK_THRESH < vector->space) && (vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS)) {
258 ( vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS ) ) {
259 vector->space /= OT_VECTOR_SHRINK_RATIO; 282 vector->space /= OT_VECTOR_SHRINK_RATIO;
260 need_fix++; 283 need_fix++;
261 } 284 }
262 if( need_fix ) 285 if (need_fix)
263 vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) ); 286 vector->data = realloc(vector->data, vector->space * peer_size);
264} 287}
265
266const char *g_version_vector_c = "$Source$: $Revision$\n";