farce 0.1.0-arm-linux-gnu → 0.2.0-arm-linux-gnu
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +80 -1
- data/README.md +72 -16
- data/docs/gems/dry-types.md +8 -8
- data/docs/modes.md +67 -10
- data/ext/farce/atom.c +37 -22
- data/ext/farce/bounded_map.c +17 -13
- data/ext/farce/containers.h +15 -0
- data/ext/farce/counter.c +13 -18
- data/ext/farce/exchanger.c +5 -1
- data/ext/farce/farce.c +1 -1
- data/ext/farce/flag.c +39 -3
- data/ext/farce/io.c +3 -3
- data/ext/farce/lock.c +17 -23
- data/ext/farce/map.c +88 -66
- data/ext/farce/priority_queue.c +55 -43
- data/ext/farce/queue.c +10 -4
- data/ext/farce/reactor.c +52 -25
- data/ext/farce/reactor.h +1 -1
- data/ext/farce/signal.c +5 -1
- data/ext/farce/transaction.c +20 -24
- data/ext/farce/tree_map.c +33 -18
- data/ext/farce/trie.c +81 -43
- data/ext/farce/unshareable.c +168 -19
- data/ext/farce/unshared_io_pool.h +21 -12
- data/ext/farce/unshared_signal.c +13 -2
- data/ext/farce/unshared_wait.h +3 -0
- data/ext/farce/vector.c +82 -18
- data/ext/farce/weak_map.c +75 -63
- data/lib/farce/_yard/macros.rb +18 -3
- data/lib/farce/abstract/flag.rb +73 -0
- data/lib/farce/abstract/queue.rb +4 -3
- data/lib/farce/abstract/scheduler.rb +3 -3
- data/lib/farce/abstract/set.rb +17 -5
- data/lib/farce/abstract/sorted_set.rb +2 -2
- data/lib/farce/abstract/timer_queue.rb +49 -10
- data/lib/farce/abstract/vector.rb +510 -28
- data/lib/farce/atom.rb +1 -1
- data/lib/farce/class_mirror.rb +20 -7
- data/lib/farce/config.rb +7 -1
- data/lib/farce/engine/jvm/flag.rb +15 -3
- data/lib/farce/engine/ruby/3.4/farce.so +0 -0
- data/lib/farce/engine/ruby/4.0/farce.so +0 -0
- data/lib/farce/engine/ruby/shared/require_hook.rb +18 -0
- data/lib/farce/engine/ruby.rb +7 -0
- data/lib/farce/engine/shared/unshared_vector.rb +31 -4
- data/lib/farce/engine/shared/vector.rb +8 -0
- data/lib/farce/engine/shared/weak_map/index.rb +14 -1
- data/lib/farce/engine/truffleruby/native/flag.rb +15 -3
- data/lib/farce/envelope.rb +54 -7
- data/lib/farce/exchanger.rb +1 -1
- data/lib/farce/flag.rb +2 -0
- data/lib/farce/integrations/active_support.rb +1 -1
- data/lib/farce/integrations/bson.rb +1 -1
- data/lib/farce/integrations/cbor.rb +1 -1
- data/lib/farce/integrations/concurrent.rb +3 -3
- data/lib/farce/integrations/date.rb +8 -0
- data/lib/farce/integrations/dry_types.rb +7 -4
- data/lib/farce/integrations/json.rb +2 -2
- data/lib/farce/integrations/msgpack.rb +1 -1
- data/lib/farce/integrations/oj.rb +3 -4
- data/lib/farce/integrations/psych.rb +1 -1
- data/lib/farce/integrations/ractor_sharing.rb +1 -1
- data/lib/farce/integrations/sorted_set.rb +1 -1
- data/lib/farce/integrations/weakref.rb +9 -1
- data/lib/farce/integrations/yajl.rb +3 -3
- data/lib/farce/integrations.rb +33 -23
- data/lib/farce/internal/flag_waiting.rb +30 -0
- data/lib/farce/internal/freeze.rb +8 -3
- data/lib/farce/internal/map_value_modes.rb +1 -1
- data/lib/farce/internal/scheduler_lifecycle.rb +1 -1
- data/lib/farce/lazy.rb +4 -4
- data/lib/farce/lazy_ref.rb +3 -3
- data/lib/farce/lfu_map.rb +1 -1
- data/lib/farce/local/flag.rb +4 -0
- data/lib/farce/local/scoped.rb +1 -1
- data/lib/farce/lru_map.rb +1 -1
- data/lib/farce/map.rb +2 -2
- data/lib/farce/mode_manager/smart_rule.rb +138 -0
- data/lib/farce/mode_manager.rb +12 -3
- data/lib/farce/molecule.rb +2 -2
- data/lib/farce/pool.rb +1 -1
- data/lib/farce/port.rb +4 -4
- data/lib/farce/priority_queue.rb +1 -1
- data/lib/farce/proxy/register.rb +6 -0
- data/lib/farce/proxy/supervisor.rb +1 -1
- data/lib/farce/proxy.rb +7 -2
- data/lib/farce/queue.rb +1 -1
- data/lib/farce/scheduler.rb +2 -2
- data/lib/farce/set.rb +1 -1
- data/lib/farce/sorted_set.rb +1 -1
- data/lib/farce/timer_queue.rb +20 -6
- data/lib/farce/transaction/vector.rb +43 -9
- data/lib/farce/transaction/wrapper.rb +14 -0
- data/lib/farce/tree_map.rb +1 -1
- data/lib/farce/unsafe/lfu_map.rb +2 -0
- data/lib/farce/unsafe/lru_map.rb +2 -0
- data/lib/farce/unsafe/tree_map.rb +2 -0
- data/lib/farce/unshareable.rb +8 -19
- data/lib/farce/unshared/atom.rb +3 -0
- data/lib/farce/unshared/lfu_map.rb +2 -0
- data/lib/farce/unshared/lru_map.rb +2 -0
- data/lib/farce/unshared/map.rb +3 -0
- data/lib/farce/unshared/set.rb +1 -0
- data/lib/farce/unshared/sorted_set.rb +1 -0
- data/lib/farce/unshared/tree_map.rb +5 -1
- data/lib/farce/unshared/vector.rb +3 -0
- data/lib/farce/unshared/weak_atom.rb +5 -1
- data/lib/farce/unshared/weak_key_map.rb +3 -0
- data/lib/farce/unshared/weak_map.rb +3 -0
- data/lib/farce/unshared/weak_set.rb +1 -0
- data/lib/farce/unshared/weak_value_map.rb +3 -0
- data/lib/farce/vector.rb +44 -19
- data/lib/farce/version.rb +1 -1
- data/lib/farce.rb +11 -8
- metadata +5 -1
data/ext/farce/map.c
CHANGED
|
@@ -92,6 +92,7 @@ typedef struct {
|
|
|
92
92
|
} map_timeout_t;
|
|
93
93
|
|
|
94
94
|
typedef struct {
|
|
95
|
+
VALUE self;
|
|
95
96
|
VALUE fiber;
|
|
96
97
|
VALUE thread;
|
|
97
98
|
VALUE scheduler;
|
|
@@ -101,9 +102,10 @@ typedef struct {
|
|
|
101
102
|
* before taking a native mutex so a Ractor GC barrier can never wait on a
|
|
102
103
|
* peer that is blocked on that mutex. */
|
|
103
104
|
static map_execution_context_t
|
|
104
|
-
map_current_execution_context(
|
|
105
|
+
map_current_execution_context(VALUE self)
|
|
105
106
|
{
|
|
106
107
|
map_execution_context_t context = {
|
|
108
|
+
.self = self,
|
|
107
109
|
.fiber = rb_fiber_current(),
|
|
108
110
|
.thread = rb_thread_current(),
|
|
109
111
|
.scheduler = rb_fiber_scheduler_current(),
|
|
@@ -206,18 +208,18 @@ static void
|
|
|
206
208
|
map_compact(void *pointer)
|
|
207
209
|
{
|
|
208
210
|
map_t *map = pointer;
|
|
209
|
-
|
|
210
|
-
|
|
211
|
+
containers_gc_update(&map->comparing_owner);
|
|
212
|
+
containers_gc_update(&map->comparing_thread);
|
|
211
213
|
for (map_reservation_t *reservation = map->reservations; reservation; reservation = reservation->next) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
214
|
+
containers_gc_update(&reservation->key);
|
|
215
|
+
containers_gc_update(&reservation->fiber);
|
|
216
|
+
containers_gc_update(&reservation->thread);
|
|
215
217
|
}
|
|
216
218
|
if (!map->slots) return;
|
|
217
219
|
for (size_t index = 0; index < map->capacity; index++) {
|
|
218
220
|
if (map->slots[index].state == MAP_OCCUPIED) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
+
containers_gc_update(&map->slots[index].key);
|
|
222
|
+
containers_gc_update(&map->slots[index].value);
|
|
221
223
|
}
|
|
222
224
|
}
|
|
223
225
|
}
|
|
@@ -265,7 +267,11 @@ static const rb_data_type_t map_type = {
|
|
|
265
267
|
.dsize = map_memsize,
|
|
266
268
|
.dcompact = map_compact,
|
|
267
269
|
},
|
|
268
|
-
.flags =
|
|
270
|
+
.flags =
|
|
271
|
+
RUBY_TYPED_WB_PROTECTED |
|
|
272
|
+
RUBY_TYPED_FROZEN_SHAREABLE |
|
|
273
|
+
RUBY_TYPED_FREE_IMMEDIATELY |
|
|
274
|
+
FARCE_TYPED_THREAD_SAFE_FREE,
|
|
269
275
|
};
|
|
270
276
|
|
|
271
277
|
static const rb_data_type_t unshared_map_type = {
|
|
@@ -277,7 +283,7 @@ static const rb_data_type_t unshared_map_type = {
|
|
|
277
283
|
.dcompact = map_compact,
|
|
278
284
|
},
|
|
279
285
|
.parent = &map_type,
|
|
280
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
286
|
+
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | FARCE_TYPED_THREAD_SAFE_FREE,
|
|
281
287
|
};
|
|
282
288
|
|
|
283
289
|
static size_t
|
|
@@ -297,7 +303,7 @@ static const rb_data_type_t unshared_key_lock_type = {
|
|
|
297
303
|
.dsize = key_lock_memsize,
|
|
298
304
|
.dcompact = map_compact,
|
|
299
305
|
},
|
|
300
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
306
|
+
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | FARCE_TYPED_THREAD_SAFE_FREE,
|
|
301
307
|
};
|
|
302
308
|
|
|
303
309
|
static void
|
|
@@ -319,9 +325,15 @@ static const rb_data_type_t shared_key_lock_type = {
|
|
|
319
325
|
.dsize = key_lock_memsize,
|
|
320
326
|
.dcompact = map_compact,
|
|
321
327
|
},
|
|
322
|
-
.flags =
|
|
328
|
+
.flags =
|
|
329
|
+
RUBY_TYPED_WB_PROTECTED |
|
|
330
|
+
RUBY_TYPED_FROZEN_SHAREABLE |
|
|
331
|
+
RUBY_TYPED_FREE_IMMEDIATELY |
|
|
332
|
+
FARCE_TYPED_THREAD_SAFE_FREE,
|
|
323
333
|
};
|
|
324
334
|
|
|
335
|
+
/* Buffer growth also runs under the state mutex. Keep the allocator pair
|
|
336
|
+
* consistent and avoid Ruby allocators that can trigger GC in that section. */
|
|
325
337
|
static map_slot_t *
|
|
326
338
|
allocate_slots(size_t capacity)
|
|
327
339
|
{
|
|
@@ -546,8 +558,8 @@ map_keys_equal(
|
|
|
546
558
|
int state = 0;
|
|
547
559
|
|
|
548
560
|
map->comparing = true;
|
|
549
|
-
map->comparing_owner
|
|
550
|
-
map->comparing_thread
|
|
561
|
+
RB_OBJ_WRITE(context->self, &map->comparing_owner, context->fiber);
|
|
562
|
+
RB_OBJ_WRITE(context->self, &map->comparing_thread, context->thread);
|
|
551
563
|
pthread_mutex_unlock(&map->lock);
|
|
552
564
|
|
|
553
565
|
VALUE result = rb_protect(map_eql_protected, (VALUE)&arguments, &state);
|
|
@@ -735,10 +747,10 @@ map_begin_reservation_locked(
|
|
|
735
747
|
pthread_mutex_unlock(&map->lock);
|
|
736
748
|
rb_memerror();
|
|
737
749
|
}
|
|
738
|
-
reservation->key
|
|
750
|
+
RB_OBJ_WRITE(context->self, &reservation->key, key);
|
|
739
751
|
reservation->hash = hash;
|
|
740
|
-
reservation->fiber
|
|
741
|
-
reservation->thread
|
|
752
|
+
RB_OBJ_WRITE(context->self, &reservation->fiber, context->fiber);
|
|
753
|
+
RB_OBJ_WRITE(context->self, &reservation->thread, context->thread);
|
|
742
754
|
reservation->invalidated = false;
|
|
743
755
|
reservation->next = map->reservations;
|
|
744
756
|
map->reservations = reservation;
|
|
@@ -826,13 +838,13 @@ map_store_locked(
|
|
|
826
838
|
map_slot_t *slot = &map->slots[index];
|
|
827
839
|
if (!found) {
|
|
828
840
|
if (slot->state == MAP_TOMBSTONE) map->tombstones--;
|
|
829
|
-
slot->key
|
|
841
|
+
RB_OBJ_WRITE(self, &slot->key, key);
|
|
830
842
|
slot->hash = hash;
|
|
831
843
|
slot->state = MAP_OCCUPIED;
|
|
832
844
|
map->size++;
|
|
833
845
|
map->iteration_epoch++;
|
|
834
846
|
}
|
|
835
|
-
slot->value
|
|
847
|
+
RB_OBJ_WRITE(self, &slot->value, value);
|
|
836
848
|
map_notify_waiters_locked(map);
|
|
837
849
|
return value;
|
|
838
850
|
}
|
|
@@ -914,7 +926,7 @@ map_initialize(int argc, VALUE *argv, VALUE self)
|
|
|
914
926
|
map_init_context_t context = {
|
|
915
927
|
.self = self,
|
|
916
928
|
.map = map,
|
|
917
|
-
.execution = map_current_execution_context(),
|
|
929
|
+
.execution = map_current_execution_context(self),
|
|
918
930
|
};
|
|
919
931
|
rb_hash_foreach(mapping, map_initialize_entry, (VALUE)&context);
|
|
920
932
|
}
|
|
@@ -941,7 +953,7 @@ map_get(VALUE self, VALUE key)
|
|
|
941
953
|
}
|
|
942
954
|
pthread_mutex_unlock(&map->lock);
|
|
943
955
|
|
|
944
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
956
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
945
957
|
map_lock_state(map, &execution);
|
|
946
958
|
index = map_find_slot(map, key, hash, &found, &execution);
|
|
947
959
|
if (found) result = map->slots[index].value;
|
|
@@ -987,7 +999,7 @@ map_fetch(int argc, VALUE *argv, VALUE self)
|
|
|
987
999
|
st_index_t hash = map_key_hash(map, key);
|
|
988
1000
|
bool found;
|
|
989
1001
|
VALUE result = Qnil;
|
|
990
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
1002
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
991
1003
|
map_lock_state(map, &execution);
|
|
992
1004
|
size_t index = map_find_slot(map, key, hash, &found, &execution);
|
|
993
1005
|
if (found) result = map->slots[index].value;
|
|
@@ -1029,7 +1041,7 @@ map_set(VALUE self, VALUE key, VALUE value)
|
|
|
1029
1041
|
}
|
|
1030
1042
|
pthread_mutex_unlock(&map->lock);
|
|
1031
1043
|
|
|
1032
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
1044
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
1033
1045
|
map_lock_for_key(map, key, hash, &execution);
|
|
1034
1046
|
map_store_locked(self, map, key, value, hash, &execution);
|
|
1035
1047
|
pthread_mutex_unlock(&map->lock);
|
|
@@ -1145,7 +1157,7 @@ map_key_p(VALUE self, VALUE key)
|
|
|
1145
1157
|
key = map_prepare_key(map, key);
|
|
1146
1158
|
st_index_t hash = map_key_hash(map, key);
|
|
1147
1159
|
bool found;
|
|
1148
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
1160
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
1149
1161
|
map_lock_state(map, &execution);
|
|
1150
1162
|
(void)map_find_slot(map, key, hash, &found, &execution);
|
|
1151
1163
|
pthread_mutex_unlock(&map->lock);
|
|
@@ -1160,7 +1172,7 @@ map_getkey(VALUE self, VALUE key)
|
|
|
1160
1172
|
st_index_t hash = map_key_hash(map, key);
|
|
1161
1173
|
bool found;
|
|
1162
1174
|
VALUE result = Qnil;
|
|
1163
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
1175
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
1164
1176
|
map_lock_state(map, &execution);
|
|
1165
1177
|
size_t index = map_find_slot(map, key, hash, &found, &execution);
|
|
1166
1178
|
if (found) result = map->compare_keys_by_identity ? key : map->slots[index].key;
|
|
@@ -1178,7 +1190,7 @@ map_delete(VALUE self, VALUE key)
|
|
|
1178
1190
|
rb_check_frozen(self);
|
|
1179
1191
|
bool found;
|
|
1180
1192
|
VALUE result = Qnil;
|
|
1181
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
1193
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
1182
1194
|
map_lock_for_key(map, key, hash, &execution);
|
|
1183
1195
|
size_t index = map_find_slot(map, key, hash, &found, &execution);
|
|
1184
1196
|
if (RB_OBJ_FROZEN(self)) {
|
|
@@ -1204,7 +1216,7 @@ map_clear(VALUE self)
|
|
|
1204
1216
|
{
|
|
1205
1217
|
rb_check_frozen(self);
|
|
1206
1218
|
map_t *map = get_map(self);
|
|
1207
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
1219
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
1208
1220
|
map_lock_state(map, &execution);
|
|
1209
1221
|
map_invalidate_reservations_locked(map);
|
|
1210
1222
|
for (size_t index = 0; index < map->capacity; index++) {
|
|
@@ -1290,7 +1302,7 @@ map_store_if_absent(int argc, VALUE *argv, VALUE self)
|
|
|
1290
1302
|
map_operation_t operation = {
|
|
1291
1303
|
.self = self,
|
|
1292
1304
|
.map = map,
|
|
1293
|
-
.execution = map_current_execution_context(),
|
|
1305
|
+
.execution = map_current_execution_context(self),
|
|
1294
1306
|
.key = key,
|
|
1295
1307
|
.complete = false,
|
|
1296
1308
|
};
|
|
@@ -1371,7 +1383,7 @@ map_compare_and_set(int argc, VALUE *argv, VALUE self)
|
|
|
1371
1383
|
map_operation_t operation = {
|
|
1372
1384
|
.self = self,
|
|
1373
1385
|
.map = map,
|
|
1374
|
-
.execution = map_current_execution_context(),
|
|
1386
|
+
.execution = map_current_execution_context(self),
|
|
1375
1387
|
.key = key,
|
|
1376
1388
|
.argument = expected,
|
|
1377
1389
|
.replacement = replacement,
|
|
@@ -1457,7 +1469,7 @@ map_modify(VALUE self, VALUE key)
|
|
|
1457
1469
|
key = map_prepare_key(map, key);
|
|
1458
1470
|
map_operation_t operation = {
|
|
1459
1471
|
.self = self,
|
|
1460
|
-
.execution = map_current_execution_context(),
|
|
1472
|
+
.execution = map_current_execution_context(self),
|
|
1461
1473
|
.map = map,
|
|
1462
1474
|
.key = key,
|
|
1463
1475
|
.complete = false,
|
|
@@ -1520,7 +1532,7 @@ map_upsert(int argc, VALUE *argv, VALUE self)
|
|
|
1520
1532
|
map_operation_t operation = {
|
|
1521
1533
|
.self = self,
|
|
1522
1534
|
.map = map,
|
|
1523
|
-
.execution = map_current_execution_context(),
|
|
1535
|
+
.execution = map_current_execution_context(self),
|
|
1524
1536
|
.key = key,
|
|
1525
1537
|
.complete = false,
|
|
1526
1538
|
};
|
|
@@ -1571,7 +1583,7 @@ map_size(VALUE self)
|
|
|
1571
1583
|
{
|
|
1572
1584
|
map_t *map = get_map(self);
|
|
1573
1585
|
size_t size;
|
|
1574
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
1586
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
1575
1587
|
map_lock_state(map, &execution);
|
|
1576
1588
|
size = map->size;
|
|
1577
1589
|
pthread_mutex_unlock(&map->lock);
|
|
@@ -1587,9 +1599,9 @@ map_enumerator_size(VALUE self, VALUE arguments, VALUE enumerator)
|
|
|
1587
1599
|
}
|
|
1588
1600
|
|
|
1589
1601
|
static VALUE
|
|
1590
|
-
map_entries_snapshot(map_t *map)
|
|
1602
|
+
map_entries_snapshot(VALUE self, map_t *map)
|
|
1591
1603
|
{
|
|
1592
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
1604
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
1593
1605
|
for (;;) {
|
|
1594
1606
|
size_t capacity;
|
|
1595
1607
|
map_lock_state(map, &execution);
|
|
@@ -1598,22 +1610,27 @@ map_entries_snapshot(map_t *map)
|
|
|
1598
1610
|
|
|
1599
1611
|
long reserved_entries = (long)(capacity * 2);
|
|
1600
1612
|
VALUE entries = rb_ary_new_capa(reserved_entries);
|
|
1601
|
-
rb_ary_resize(entries, reserved_entries);
|
|
1602
1613
|
map_lock_state(map, &execution);
|
|
1603
1614
|
if (map->size > capacity) {
|
|
1604
1615
|
pthread_mutex_unlock(&map->lock);
|
|
1605
1616
|
continue;
|
|
1606
1617
|
}
|
|
1607
|
-
|
|
1608
|
-
|
|
1618
|
+
/* The private array has capacity for every pair. Bulk appends cannot
|
|
1619
|
+
* grow it or trigger GC while the state mutex is held. */
|
|
1620
|
+
VALUE batch[64];
|
|
1621
|
+
long length = 0;
|
|
1609
1622
|
for (size_t index = 0; index < map->capacity; index++) {
|
|
1610
1623
|
map_slot_t *slot = &map->slots[index];
|
|
1611
1624
|
if (slot->state != MAP_OCCUPIED) continue;
|
|
1612
|
-
|
|
1613
|
-
|
|
1625
|
+
batch[length++] = slot->key;
|
|
1626
|
+
batch[length++] = slot->value;
|
|
1627
|
+
if (length == 64) {
|
|
1628
|
+
rb_ary_cat(entries, batch, length);
|
|
1629
|
+
length = 0;
|
|
1630
|
+
}
|
|
1614
1631
|
}
|
|
1632
|
+
if (length) rb_ary_cat(entries, batch, length);
|
|
1615
1633
|
pthread_mutex_unlock(&map->lock);
|
|
1616
|
-
if (entry_count < reserved_entries) rb_ary_resize(entries, entry_count);
|
|
1617
1634
|
return entries;
|
|
1618
1635
|
}
|
|
1619
1636
|
}
|
|
@@ -1621,11 +1638,11 @@ map_entries_snapshot(map_t *map)
|
|
|
1621
1638
|
static VALUE
|
|
1622
1639
|
map_keys(VALUE self)
|
|
1623
1640
|
{
|
|
1624
|
-
VALUE entries = map_entries_snapshot(get_map(self));
|
|
1641
|
+
VALUE entries = map_entries_snapshot(self, get_map(self));
|
|
1625
1642
|
long entry_count = RARRAY_LEN(entries);
|
|
1626
1643
|
VALUE keys = rb_ary_new_capa(entry_count / 2);
|
|
1627
1644
|
for (long index = 0; index < entry_count; index += 2) {
|
|
1628
|
-
rb_ary_push(keys,
|
|
1645
|
+
rb_ary_push(keys, rb_ary_entry(entries, index));
|
|
1629
1646
|
}
|
|
1630
1647
|
RB_GC_GUARD(entries);
|
|
1631
1648
|
return keys;
|
|
@@ -1635,10 +1652,10 @@ static VALUE
|
|
|
1635
1652
|
map_each(VALUE self)
|
|
1636
1653
|
{
|
|
1637
1654
|
RETURN_SIZED_ENUMERATOR(self, 0, NULL, map_enumerator_size);
|
|
1638
|
-
VALUE entries = map_entries_snapshot(get_map(self));
|
|
1655
|
+
VALUE entries = map_entries_snapshot(self, get_map(self));
|
|
1639
1656
|
long entry_count = RARRAY_LEN(entries);
|
|
1640
1657
|
for (long index = 0; index < entry_count; index += 2) {
|
|
1641
|
-
rb_yield(rb_assoc_new(
|
|
1658
|
+
rb_yield(rb_assoc_new(rb_ary_entry(entries, index), rb_ary_entry(entries, index + 1)));
|
|
1642
1659
|
}
|
|
1643
1660
|
RB_GC_GUARD(entries);
|
|
1644
1661
|
return self;
|
|
@@ -1652,18 +1669,17 @@ map_each_live(VALUE self)
|
|
|
1652
1669
|
{
|
|
1653
1670
|
RETURN_SIZED_ENUMERATOR(self, 0, NULL, map_enumerator_size);
|
|
1654
1671
|
map_t *map = get_map(self);
|
|
1655
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
1672
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
1656
1673
|
size_t cursor = 0;
|
|
1657
1674
|
uint64_t epoch = 0;
|
|
1658
1675
|
bool started = false;
|
|
1659
1676
|
const long batch_slots = 64;
|
|
1660
|
-
|
|
1661
|
-
|
|
1677
|
+
/* C-stack roots keep this bounded batch alive across Ruby yields. */
|
|
1678
|
+
VALUE batch[64];
|
|
1662
1679
|
|
|
1663
1680
|
for (;;) {
|
|
1664
|
-
VALUE *storage = RARRAY_PTR(batch);
|
|
1665
1681
|
for (long index = 0; index < batch_slots; index++) {
|
|
1666
|
-
|
|
1682
|
+
batch[index] = Qnil;
|
|
1667
1683
|
}
|
|
1668
1684
|
map_lock_state(map, &execution);
|
|
1669
1685
|
if (started && epoch != map->iteration_epoch) {
|
|
@@ -1676,16 +1692,17 @@ map_each_live(VALUE self)
|
|
|
1676
1692
|
while (cursor < map->capacity && length < batch_slots) {
|
|
1677
1693
|
map_slot_t *slot = &map->slots[cursor++];
|
|
1678
1694
|
if (slot->state != MAP_OCCUPIED) continue;
|
|
1679
|
-
|
|
1680
|
-
|
|
1695
|
+
batch[length++] = slot->key;
|
|
1696
|
+
batch[length++] = slot->value;
|
|
1681
1697
|
}
|
|
1682
1698
|
pthread_mutex_unlock(&map->lock);
|
|
1683
1699
|
if (length == 0) break;
|
|
1684
1700
|
for (long index = 0; index < length; index += 2) {
|
|
1685
|
-
rb_yield(rb_assoc_new(
|
|
1701
|
+
rb_yield(rb_assoc_new(batch[index], batch[index + 1]));
|
|
1686
1702
|
}
|
|
1687
1703
|
}
|
|
1688
|
-
RB_GC_GUARD(batch);
|
|
1704
|
+
RB_GC_GUARD(batch[0]);
|
|
1705
|
+
RB_GC_GUARD(batch[63]);
|
|
1689
1706
|
return self;
|
|
1690
1707
|
}
|
|
1691
1708
|
|
|
@@ -1693,10 +1710,10 @@ static VALUE
|
|
|
1693
1710
|
map_each_key(VALUE self)
|
|
1694
1711
|
{
|
|
1695
1712
|
RETURN_SIZED_ENUMERATOR(self, 0, NULL, map_enumerator_size);
|
|
1696
|
-
VALUE entries = map_entries_snapshot(get_map(self));
|
|
1713
|
+
VALUE entries = map_entries_snapshot(self, get_map(self));
|
|
1697
1714
|
long entry_count = RARRAY_LEN(entries);
|
|
1698
1715
|
for (long index = 0; index < entry_count; index += 2) {
|
|
1699
|
-
rb_yield(
|
|
1716
|
+
rb_yield(rb_ary_entry(entries, index));
|
|
1700
1717
|
}
|
|
1701
1718
|
RB_GC_GUARD(entries);
|
|
1702
1719
|
return self;
|
|
@@ -1706,10 +1723,10 @@ static VALUE
|
|
|
1706
1723
|
map_each_value(VALUE self)
|
|
1707
1724
|
{
|
|
1708
1725
|
RETURN_SIZED_ENUMERATOR(self, 0, NULL, map_enumerator_size);
|
|
1709
|
-
VALUE entries = map_entries_snapshot(get_map(self));
|
|
1726
|
+
VALUE entries = map_entries_snapshot(self, get_map(self));
|
|
1710
1727
|
long entry_count = RARRAY_LEN(entries);
|
|
1711
1728
|
for (long index = 1; index < entry_count; index += 2) {
|
|
1712
|
-
rb_yield(
|
|
1729
|
+
rb_yield(rb_ary_entry(entries, index));
|
|
1713
1730
|
}
|
|
1714
1731
|
RB_GC_GUARD(entries);
|
|
1715
1732
|
return self;
|
|
@@ -1729,7 +1746,7 @@ map_get_with_timeout(int argc, VALUE *argv, VALUE self)
|
|
|
1729
1746
|
key = map_prepare_key(map, key);
|
|
1730
1747
|
st_index_t hash = map_key_hash(map, key);
|
|
1731
1748
|
map_timeout_t timeout = map_parse_timeout(keyword_values[0] == Qundef ? Qnil : keyword_values[0]);
|
|
1732
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
1749
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
1733
1750
|
if (!map_lock_for_key_with_timeout(map, key, hash, &timeout, &execution)) {
|
|
1734
1751
|
return map_timeout_result();
|
|
1735
1752
|
}
|
|
@@ -1759,7 +1776,7 @@ map_store_with_timeout(int argc, VALUE *argv, VALUE self)
|
|
|
1759
1776
|
st_index_t hash = map_key_hash(map, key);
|
|
1760
1777
|
rb_check_frozen(self);
|
|
1761
1778
|
map_timeout_t timeout = map_parse_timeout(keyword_values[0] == Qundef ? Qnil : keyword_values[0]);
|
|
1762
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
1779
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
1763
1780
|
if (!map_lock_for_key_with_timeout(map, key, hash, &timeout, &execution)) {
|
|
1764
1781
|
return map_timeout_result();
|
|
1765
1782
|
}
|
|
@@ -1786,7 +1803,7 @@ map_swap(int argc, VALUE *argv, VALUE self)
|
|
|
1786
1803
|
st_index_t hash = map_key_hash(map, key);
|
|
1787
1804
|
rb_check_frozen(self);
|
|
1788
1805
|
map_timeout_t timeout = map_parse_timeout(keyword_values[0] == Qundef ? Qnil : keyword_values[0]);
|
|
1789
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
1806
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
1790
1807
|
if (!map_lock_for_key_with_timeout(map, key, hash, &timeout, &execution)) {
|
|
1791
1808
|
return map_timeout_result();
|
|
1792
1809
|
}
|
|
@@ -1826,7 +1843,7 @@ map_wait_for_value(int argc, VALUE *argv, VALUE self, bool non_nil)
|
|
|
1826
1843
|
if (!non_nil) map_check_value(map, expected);
|
|
1827
1844
|
st_index_t hash = map_key_hash(map, key);
|
|
1828
1845
|
map_timeout_t timeout = map_parse_timeout(keyword_values[0] == Qundef ? Qnil : keyword_values[0]);
|
|
1829
|
-
map_execution_context_t execution = map_current_execution_context();
|
|
1846
|
+
map_execution_context_t execution = map_current_execution_context(self);
|
|
1830
1847
|
|
|
1831
1848
|
for (;;) {
|
|
1832
1849
|
bool found;
|
|
@@ -1881,7 +1898,7 @@ map_update(int argc, VALUE *argv, VALUE self)
|
|
|
1881
1898
|
map_operation_t operation = {
|
|
1882
1899
|
.self = self,
|
|
1883
1900
|
.map = map,
|
|
1884
|
-
.execution = map_current_execution_context(),
|
|
1901
|
+
.execution = map_current_execution_context(self),
|
|
1885
1902
|
.key = key,
|
|
1886
1903
|
.complete = false,
|
|
1887
1904
|
};
|
|
@@ -2006,7 +2023,7 @@ key_lock_synchronize(VALUE self, VALUE key)
|
|
|
2006
2023
|
map_t *map = &storage->core;
|
|
2007
2024
|
map_operation_t operation = {
|
|
2008
2025
|
.map = map,
|
|
2009
|
-
.execution = map_current_execution_context(),
|
|
2026
|
+
.execution = map_current_execution_context(self),
|
|
2010
2027
|
.key = key,
|
|
2011
2028
|
.complete = false,
|
|
2012
2029
|
};
|
|
@@ -2050,6 +2067,11 @@ map_transaction_apply(farce_transaction_entry_t *entry)
|
|
|
2050
2067
|
copy->capacity = capacity;
|
|
2051
2068
|
copy->size = size;
|
|
2052
2069
|
copy->tombstones = tombstones;
|
|
2070
|
+
for (size_t i = 0; i < map->capacity; i++) {
|
|
2071
|
+
if (map->slots[i].state != MAP_OCCUPIED) continue;
|
|
2072
|
+
RB_OBJ_WRITTEN(entry->source, Qundef, map->slots[i].key);
|
|
2073
|
+
RB_OBJ_WRITTEN(entry->source, Qundef, map->slots[i].value);
|
|
2074
|
+
}
|
|
2053
2075
|
}
|
|
2054
2076
|
|
|
2055
2077
|
static void
|
|
@@ -2063,8 +2085,8 @@ map_transaction_reserve(farce_transaction_entry_t *entry, VALUE fiber, VALUE thr
|
|
|
2063
2085
|
{
|
|
2064
2086
|
map_t *map = entry->source_data;
|
|
2065
2087
|
map->comparing = FARCE_TRANSACTION_RESERVED;
|
|
2066
|
-
map->comparing_owner
|
|
2067
|
-
map->comparing_thread
|
|
2088
|
+
RB_OBJ_WRITE(entry->source, &map->comparing_owner, fiber);
|
|
2089
|
+
RB_OBJ_WRITE(entry->source, &map->comparing_thread, thread);
|
|
2068
2090
|
}
|
|
2069
2091
|
|
|
2070
2092
|
static void
|
|
@@ -2085,7 +2107,7 @@ map_freeze(VALUE self)
|
|
|
2085
2107
|
pthread_mutex_lock(&map->lock);
|
|
2086
2108
|
if (map->comparing == FARCE_TRANSACTION_RESERVED) {
|
|
2087
2109
|
pthread_mutex_unlock(&map->lock);
|
|
2088
|
-
map_execution_context_t context = map_current_execution_context();
|
|
2110
|
+
map_execution_context_t context = map_current_execution_context(self);
|
|
2089
2111
|
map_lock_state(map, &context);
|
|
2090
2112
|
}
|
|
2091
2113
|
rb_obj_freeze(self);
|