summaryrefslogtreecommitdiff
path: root/ot_vector.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_vector.c')
-rw-r--r--ot_vector.c242
1 files changed, 130 insertions, 112 deletions
diff --git a/ot_vector.c b/ot_vector.c
index 2a632b2..2bc07b5 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,62 @@ 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);
66 65
67 if( *exactmatch ) return match; 66 if (*exactmatch)
67 return match;
68 68
69 if( vector->size + 1 > vector->space ) { 69 if (vector->size + 1 > vector->space) {
70 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; 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 ); 71 uint8_t *new_data = realloc(vector->data, new_space * member_size);
72 if( !new_data ) return NULL; 72 if (!new_data)
73 return NULL;
73 /* Adjust pointer if it moved by realloc */ 74 /* Adjust pointer if it moved by realloc */
74 match = new_data + (match - (uint8_t*)vector->data); 75 match = new_data + (match - (uint8_t *)vector->data);
75 76
76 vector->data = new_data; 77 vector->data = new_data;
77 vector->space = new_space; 78 vector->space = new_space;
78 } 79 }
79 memmove( match + member_size, match, ((uint8_t*)vector->data) + member_size * vector->size - match ); 80 memmove(match + member_size, match, ((uint8_t *)vector->data) + member_size * vector->size - match);
80 81
81 vector->size++; 82 vector->size++;
82 return match; 83 return match;
83} 84}
84 85
85ot_peer *vector_find_or_insert_peer( ot_vector *vector, ot_peer *peer, int *exactmatch ) { 86ot_peer *vector_find_or_insert_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch) {
86 ot_peer *match; 87 ot_peer *match, *end;
88 const size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
89 size_t match_to_end;
87 90
88 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */ 91 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */
89 if( vector->space < vector->size ) 92 if (vector->space < vector->size)
90 vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size ); 93 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 ); 94 match = binary_search(peer, vector->data, vector->size, peer_size, compare_size, exactmatch);
92 95
93 if( *exactmatch ) return match; 96 if (*exactmatch)
97 return match;
94 98
95 if( vector->size + 1 > vector->space ) { 99 /* 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; 100 end = (ot_peer *)vector->data + vector->size * peer_size;
97 ot_peer *new_data = realloc( vector->data, new_space * sizeof(ot_peer) ); 101 match_to_end = end - match;
98 if( !new_data ) return NULL; 102
103 if (vector->size + 1 > vector->space) {
104 ptrdiff_t offset = match - (ot_peer *)vector->data;
105 size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS;
106 ot_peer *new_data = realloc(vector->data, new_space * peer_size);
107
108 if (!new_data)
109 return NULL;
99 /* Adjust pointer if it moved by realloc */ 110 /* Adjust pointer if it moved by realloc */
100 match = new_data + (match - (ot_peer*)vector->data); 111 match = new_data + offset;
101 112
102 vector->data = new_data; 113 vector->data = new_data;
103 vector->space = new_space; 114 vector->space = new_space;
104 } 115 }
105 memmove( match + 1, match, sizeof(ot_peer) * ( ((ot_peer*)vector->data) + vector->size - match ) ); 116
117 /* Here we're guaranteed to have enough space in vector to move the block of peers after insertion point */
118 memmove(match + peer_size, match, match_to_end);
106 119
107 vector->size++; 120 vector->size++;
108 return match; 121 return match;
@@ -113,126 +126,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 126 1 if a non-seeding peer was removed
114 2 if a seeding peer was removed 127 2 if a seeding peer was removed
115*/ 128*/
116int vector_remove_peer( ot_vector *vector, ot_peer *peer ) { 129int vector_remove_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size) {
117 int exactmatch; 130 int exactmatch, was_seeder;
118 ot_peer *match, *end; 131 ot_peer *match, *end;
132 size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size);
119 133
120 if( !vector->size ) return 0; 134 if (!vector->size)
135 return 0;
121 136
122 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */ 137 /* If space is zero but size is set, we're dealing with a list of vector->size buckets */
123 if( vector->space < vector->size ) 138 if (vector->space < vector->size)
124 vector = ((ot_vector*)vector->data) + vector_hash_peer(peer, vector->size ); 139 vector = ((ot_vector *)vector->data) + vector_hash_peer(peer, compare_size, vector->size);
125 140
126 end = ((ot_peer*)vector->data) + vector->size; 141 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 ); 142 match = (ot_peer *)binary_search(peer, vector->data, vector->size, peer_size, compare_size, &exactmatch);
128 if( !exactmatch ) return 0; 143 if (!exactmatch)
144 return 0;
129 145
130 exactmatch = ( OT_PEERFLAG( match ) & PEER_FLAG_SEEDING ) ? 2 : 1; 146 was_seeder = (OT_PEERFLAG_D(match, peer_size) & PEER_FLAG_SEEDING) ? 2 : 1;
131 memmove( match, match + 1, sizeof(ot_peer) * ( end - match - 1 ) ); 147 memmove(match, match + peer_size, end - match - peer_size);
132 148
133 vector->size--; 149 vector->size--;
134 vector_fixup_peers( vector ); 150 vector_fixup_peers(vector, peer_size);
135 return exactmatch; 151 return was_seeder;
136} 152}
137 153
138void vector_remove_torrent( ot_vector *vector, ot_torrent *match ) { 154void vector_remove_torrent(ot_vector *vector, ot_torrent *match) {
139 ot_torrent *end = ((ot_torrent*)vector->data) + vector->size; 155 ot_torrent *end = ((ot_torrent *)vector->data) + vector->size;
140 156
141 if( !vector->size ) return; 157 if (!vector->size)
158 return;
142 159
143 /* If this is being called after a unsuccessful malloc() for peer_list 160 /* 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 */ 161 in add_peer_to_torrent, match->peer_list actually might be NULL */
145 if( match->peer_list) free_peerlist( match->peer_list ); 162 free_peerlist(match->peer_list6);
163 free_peerlist(match->peer_list4);
146 164
147 memmove( match, match + 1, sizeof(ot_torrent) * ( end - match - 1 ) ); 165 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 ) ) { 166 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; 167 vector->space /= OT_VECTOR_SHRINK_RATIO;
150 vector->data = realloc( vector->data, vector->space * sizeof( ot_torrent ) ); 168 vector->data = realloc(vector->data, vector->space * sizeof(ot_torrent));
151 } 169 }
152} 170}
153 171
154void vector_clean_list( ot_vector * vector, int num_buckets ) { 172void vector_clean_list(ot_vector *vector, int num_buckets) {
155 while( num_buckets-- ) 173 while (num_buckets--)
156 free( vector[num_buckets].data ); 174 free(vector[num_buckets].data);
157 free( vector ); 175 free(vector);
158 return; 176 return;
159} 177}
160 178
161void vector_redistribute_buckets( ot_peerlist * peer_list ) { 179void 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; 180 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; 181 ot_vector *bucket_list_new, *bucket_list_old = &peer_list->peers;
182 int (*sort_func)(const void *, const void *) = peer_size == OT_PEER_SIZE6 ? &vector_compare_peer6 : &vector_compare_peer4;
164 183
165 if( OT_PEERLIST_HASBUCKETS( peer_list ) ) { 184 if (OT_PEERLIST_HASBUCKETS(peer_list)) {
166 num_buckets_old = peer_list->peers.size; 185 num_buckets_old = peer_list->peers.size;
167 bucket_list_old = peer_list->peers.data; 186 bucket_list_old = peer_list->peers.data;
168 } 187 }
169 188
170 if( peer_list->peer_count < 255 ) 189 if (peer_list->peer_count < 255)
171 num_buckets_new = 1; 190 num_buckets_new = 1;
172 else if( peer_list->peer_count > 8192 ) 191 else if (peer_list->peer_count > 8192)
173 num_buckets_new = 64; 192 num_buckets_new = 64;
174 else if( peer_list->peer_count >= 512 && peer_list->peer_count < 4096 ) 193 else if (peer_list->peer_count >= 512 && peer_list->peer_count < 4096)
175 num_buckets_new = 16; 194 num_buckets_new = 16;
176 else if( peer_list->peer_count < 512 && num_buckets_old <= 16 ) 195 else if (peer_list->peer_count < 512 && num_buckets_old <= 16)
177 num_buckets_new = num_buckets_old; 196 num_buckets_new = num_buckets_old;
178 else if( peer_list->peer_count < 512 ) 197 else if (peer_list->peer_count < 512)
179 num_buckets_new = 1; 198 num_buckets_new = 1;
180 else if( peer_list->peer_count < 8192 && num_buckets_old > 1 ) 199 else if (peer_list->peer_count < 8192 && num_buckets_old > 1)
181 num_buckets_new = num_buckets_old; 200 num_buckets_new = num_buckets_old;
182 else 201 else
183 num_buckets_new = 16; 202 num_buckets_new = 16;
184 203
185 if( num_buckets_new == num_buckets_old ) 204 if (num_buckets_new == num_buckets_old)
186 return; 205 return;
187 206
188 /* Assume near perfect distribution */ 207 /* Assume near perfect distribution */
189 bucket_list_new = malloc( num_buckets_new * sizeof( ot_vector ) ); 208 bucket_list_new = malloc(num_buckets_new * sizeof(ot_vector));
190 if( !bucket_list_new) return; 209 if (!bucket_list_new)
191 bzero( bucket_list_new, num_buckets_new * sizeof( ot_vector ) ); 210 return;
211 bzero(bucket_list_new, num_buckets_new * sizeof(ot_vector));
192 212
193 tmp = peer_list->peer_count / num_buckets_new; 213 tmp = peer_list->peer_count / num_buckets_new;
194 bucket_size_new = OT_VECTOR_MIN_MEMBERS; 214 bucket_size_new = OT_VECTOR_MIN_MEMBERS;
195 while( bucket_size_new < tmp) 215 while (bucket_size_new < tmp)
196 bucket_size_new *= OT_VECTOR_GROW_RATIO; 216 bucket_size_new *= OT_VECTOR_GROW_RATIO;
197 217
198 /* preallocate vectors to hold all peers */ 218 /* preallocate vectors to hold all peers */
199 for( bucket=0; bucket<num_buckets_new; ++bucket ) { 219 for (bucket = 0; bucket < num_buckets_new; ++bucket) {
200 bucket_list_new[bucket].space = bucket_size_new; 220 bucket_list_new[bucket].space = bucket_size_new;
201 bucket_list_new[bucket].data = malloc( bucket_size_new * sizeof(ot_peer) ); 221 bucket_list_new[bucket].data = malloc(bucket_size_new * peer_size);
202 if( !bucket_list_new[bucket].data ) 222 if (!bucket_list_new[bucket].data)
203 return vector_clean_list( bucket_list_new, num_buckets_new ); 223 return vector_clean_list(bucket_list_new, num_buckets_new);
204 } 224 }
205 225
206 /* Now sort them into the correct bucket */ 226 /* Now sort them into the correct bucket */
207 for( bucket=0; bucket<num_buckets_old; ++bucket ) { 227 for (bucket = 0; bucket < num_buckets_old; ++bucket) {
208 ot_peer * peers_old = bucket_list_old[bucket].data, * peers_new; 228 ot_peer *peers_old = bucket_list_old[bucket].data;
209 int peer_count_old = bucket_list_old[bucket].size; 229 int peer_count_old = bucket_list_old[bucket].size;
210 while( peer_count_old-- ) { 230 while (peer_count_old--) {
211 ot_vector * bucket_dest = bucket_list_new; 231 ot_vector *bucket_dest = bucket_list_new;
212 if( num_buckets_new > 1 ) 232 if (num_buckets_new > 1)
213 bucket_dest += vector_hash_peer(peers_old, num_buckets_new); 233 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 ) { 234 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 ); 235 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 ); 236 if (!tmp)
237 return vector_clean_list(bucket_list_new, num_buckets_new);
217 bucket_dest->data = tmp; 238 bucket_dest->data = tmp;
218 bucket_dest->space *= OT_VECTOR_GROW_RATIO; 239 bucket_dest->space *= OT_VECTOR_GROW_RATIO;
219 } 240 }
220 peers_new = (ot_peer*)bucket_dest->data; 241 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)); 242 peers_old += peer_size;
222 } 243 }
223 } 244 }
224 245
225 /* Now sort each bucket to later allow bsearch */ 246 /* Now sort each bucket to later allow bsearch */
226 for( bucket=0; bucket<num_buckets_new; ++bucket ) 247 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 ); 248 qsort(bucket_list_new[bucket].data, bucket_list_new[bucket].size, peer_size, sort_func);
228 249
229 /* Everything worked fine. Now link new bucket_list to peer_list */ 250 /* Everything worked fine. Now link new bucket_list to peer_list */
230 if( OT_PEERLIST_HASBUCKETS( peer_list) ) 251 if (OT_PEERLIST_HASBUCKETS(peer_list))
231 vector_clean_list( (ot_vector*)peer_list->peers.data, peer_list->peers.size ); 252 vector_clean_list((ot_vector *)peer_list->peers.data, peer_list->peers.size);
232 else 253 else
233 free( peer_list->peers.data ); 254 free(peer_list->peers.data);
234 255
235 if( num_buckets_new > 1 ) { 256 if (num_buckets_new > 1) {
236 peer_list->peers.data = bucket_list_new; 257 peer_list->peers.data = bucket_list_new;
237 peer_list->peers.size = num_buckets_new; 258 peer_list->peers.size = num_buckets_new;
238 peer_list->peers.space = 0; /* Magic marker for "is list of buckets" */ 259 peer_list->peers.space = 0; /* Magic marker for "is list of buckets" */
@@ -240,27 +261,24 @@ void vector_redistribute_buckets( ot_peerlist * peer_list ) {
240 peer_list->peers.data = bucket_list_new->data; 261 peer_list->peers.data = bucket_list_new->data;
241 peer_list->peers.size = bucket_list_new->size; 262 peer_list->peers.size = bucket_list_new->size;
242 peer_list->peers.space = bucket_list_new->space; 263 peer_list->peers.space = bucket_list_new->space;
243 free( bucket_list_new ); 264 free(bucket_list_new);
244 } 265 }
245} 266}
246 267
247void vector_fixup_peers( ot_vector * vector ) { 268void vector_fixup_peers(ot_vector *vector, size_t peer_size) {
248 int need_fix = 0; 269 int need_fix = 0;
249 270
250 if( !vector->size ) { 271 if (!vector->size) {
251 free( vector->data ); 272 free(vector->data);
252 vector->data = NULL; 273 vector->data = NULL;
253 vector->space = 0; 274 vector->space = 0;
254 return; 275 return;
255 } 276 }
256 277
257 while( ( vector->size * OT_VECTOR_SHRINK_THRESH < vector->space ) && 278 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; 279 vector->space /= OT_VECTOR_SHRINK_RATIO;
260 need_fix++; 280 need_fix++;
261 } 281 }
262 if( need_fix ) 282 if (need_fix)
263 vector->data = realloc( vector->data, vector->space * sizeof( ot_peer ) ); 283 vector->data = realloc(vector->data, vector->space * peer_size);
264} 284}
265
266const char *g_version_vector_c = "$Source$: $Revision$\n";