semian 0.7.1 → 0.7.4
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/ext/semian/resource.c +7 -1
- data/ext/semian/resource.h +1 -0
- data/ext/semian/semian.c +1 -0
- data/ext/semian/sysv_semaphores.c +37 -2
- data/ext/semian/tickets.c +18 -24
- data/ext/semian/tickets.h +2 -2
- data/ext/semian/types.h +3 -2
- data/lib/semian/circuit_breaker.rb +1 -1
- data/lib/semian/net_http.rb +11 -20
- data/lib/semian/protected_resource.rb +2 -2
- data/lib/semian/resource.rb +2 -1
- data/lib/semian/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4701f3daa0b3ff3ed0f7a2a60ae025d023a4b2c
|
4
|
+
data.tar.gz: 464b2d490be5404dbabd1ed50d15b84e5bdd7e11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65122ec1d4ef4c7cb337ac00d4f8838d38b6ac8777b1e4a64d52b2381cb0b9938fa1cc85da3e6fabc88aa98c7e48cde73c253d090597fdb3ddf1b0f5f4399734
|
7
|
+
data.tar.gz: 545e6a6b3350bf4e06156945d84c5a89d2d57dc75d7e0a3dc83cbe385b8ba8a5a8585c21cc85bb9328591ecce027b0cc522772be221dcf72304f3c0769dbb402
|
data/ext/semian/resource.c
CHANGED
@@ -63,7 +63,12 @@ semian_resource_acquire(int argc, VALUE *argv, VALUE self)
|
|
63
63
|
}
|
64
64
|
}
|
65
65
|
|
66
|
-
|
66
|
+
VALUE wait_time = Qnil;
|
67
|
+
if (res.wait_time >= 0) {
|
68
|
+
wait_time = LONG2NUM(res.wait_time);
|
69
|
+
}
|
70
|
+
|
71
|
+
return rb_ensure(rb_yield, wait_time, cleanup_semian_resource_acquire, self);
|
67
72
|
}
|
68
73
|
|
69
74
|
VALUE
|
@@ -219,6 +224,7 @@ semian_resource_initialize(VALUE self, VALUE id, VALUE tickets, VALUE quota, VAL
|
|
219
224
|
ms_to_timespec(c_timeout * 1000, &res->timeout);
|
220
225
|
res->name = strdup(c_id_str);
|
221
226
|
res->quota = c_quota;
|
227
|
+
res->wait_time = -1;
|
222
228
|
|
223
229
|
// Initialize the semaphore set
|
224
230
|
initialize_semaphore_set(res, c_id_str, c_permissions, c_tickets, c_quota);
|
data/ext/semian/resource.h
CHANGED
data/ext/semian/semian.c
CHANGED
@@ -53,6 +53,7 @@ void Init_semian()
|
|
53
53
|
rb_define_method(cResource, "reset_registered_workers!", semian_resource_reset_workers, 0);
|
54
54
|
rb_define_method(cResource, "unregister_worker", semian_resource_unregister_worker, 0);
|
55
55
|
|
56
|
+
id_wait_time = rb_intern("wait_time");
|
56
57
|
id_timeout = rb_intern("timeout");
|
57
58
|
|
58
59
|
if (semctl(0, 0, SEM_INFO, &info_buf) == -1) {
|
@@ -1,4 +1,5 @@
|
|
1
1
|
#include "sysv_semaphores.h"
|
2
|
+
#include <time.h>
|
2
3
|
|
3
4
|
static key_t
|
4
5
|
generate_key(const char *name);
|
@@ -12,6 +13,9 @@ wait_for_new_semaphore_set(key_t key, long permissions);
|
|
12
13
|
static void
|
13
14
|
initialize_new_semaphore_values(int sem_id, long permissions);
|
14
15
|
|
16
|
+
static long
|
17
|
+
diff_timespec_ms(struct timespec *end, struct timespec *begin);
|
18
|
+
|
15
19
|
// Generate string rep for sem indices for debugging puproses
|
16
20
|
static const char *SEMINDEX_STRING[] = {
|
17
21
|
FOREACH_SEMINDEX(GENERATE_STRING)
|
@@ -59,9 +63,23 @@ initialize_semaphore_set(semian_resource_t* res, const char* id_str, long permis
|
|
59
63
|
rb_raise(eInternal, "error incrementing registered workers, errno: %d (%s)", errno, strerror(errno));
|
60
64
|
}
|
61
65
|
|
66
|
+
int state = 0;
|
62
67
|
sem_meta_lock(res->sem_id); // Sets otime for the first time by acquiring the sem lock
|
63
|
-
|
68
|
+
|
69
|
+
configure_tickets_args_t configure_tickets_args = (configure_tickets_args_t){
|
70
|
+
.sem_id = res->sem_id,
|
71
|
+
.tickets = tickets,
|
72
|
+
.quota = quota,
|
73
|
+
};
|
74
|
+
rb_protect(
|
75
|
+
configure_tickets,
|
76
|
+
(VALUE)&configure_tickets_args,
|
77
|
+
&state);
|
78
|
+
|
64
79
|
sem_meta_unlock(res->sem_id);
|
80
|
+
if (state) {
|
81
|
+
rb_jump_tag(state);
|
82
|
+
}
|
65
83
|
}
|
66
84
|
|
67
85
|
void
|
@@ -142,12 +160,21 @@ acquire_semaphore(void *p)
|
|
142
160
|
{
|
143
161
|
semian_resource_t *res = (semian_resource_t *) p;
|
144
162
|
res->error = 0;
|
163
|
+
res->wait_time = -1;
|
145
164
|
#ifdef DEBUG
|
146
165
|
print_sem_vals(res->sem_id);
|
147
166
|
#endif
|
167
|
+
|
168
|
+
struct timespec begin, end;
|
169
|
+
int benchmark_result = clock_gettime(CLOCK_MONOTONIC, &begin);
|
148
170
|
if (perform_semop(res->sem_id, SI_SEM_TICKETS, -1, SEM_UNDO, &res->timeout) == -1) {
|
149
171
|
res->error = errno;
|
150
172
|
}
|
173
|
+
if (benchmark_result == 0) {
|
174
|
+
if (clock_gettime(CLOCK_MONOTONIC, &end) == 0) {
|
175
|
+
res->wait_time = diff_timespec_ms(&end, &begin);
|
176
|
+
}
|
177
|
+
}
|
151
178
|
return NULL;
|
152
179
|
}
|
153
180
|
|
@@ -211,7 +238,7 @@ wait_for_new_semaphore_set(key_t key, long permissions)
|
|
211
238
|
for (i = 0; i < ((INTERNAL_TIMEOUT * MICROSECONDS_IN_SECOND) / INIT_WAIT); i++) {
|
212
239
|
|
213
240
|
if (semctl(sem_id, 0, IPC_STAT, sem_opts) == -1) {
|
214
|
-
raise_semian_syscall_error("
|
241
|
+
raise_semian_syscall_error("semctl()", errno);
|
215
242
|
}
|
216
243
|
|
217
244
|
// If a semop has been performed by someone else, the values must be initialized
|
@@ -231,3 +258,11 @@ wait_for_new_semaphore_set(key_t key, long permissions)
|
|
231
258
|
|
232
259
|
return sem_id;
|
233
260
|
}
|
261
|
+
|
262
|
+
static long
|
263
|
+
diff_timespec_ms(struct timespec *end, struct timespec *begin)
|
264
|
+
{
|
265
|
+
long end_ms = (end->tv_sec * 1e3) + (end->tv_nsec / 1e6);
|
266
|
+
long begin_ms = (begin->tv_sec * 1e3) + (begin->tv_nsec / 1e6);
|
267
|
+
return end_ms - begin_ms;
|
268
|
+
}
|
data/ext/semian/tickets.c
CHANGED
@@ -2,20 +2,19 @@
|
|
2
2
|
|
3
3
|
// Update the ticket count for static ticket tracking
|
4
4
|
static VALUE
|
5
|
-
update_ticket_count(
|
5
|
+
update_ticket_count(int sem_id, int count);
|
6
6
|
|
7
7
|
static int
|
8
8
|
calculate_quota_tickets(int sem_id, double quota);
|
9
9
|
|
10
10
|
// Must be called with the semaphore meta lock already acquired
|
11
|
-
|
12
|
-
configure_tickets(
|
11
|
+
VALUE
|
12
|
+
configure_tickets(VALUE value)
|
13
13
|
{
|
14
|
-
|
15
|
-
update_ticket_count_t tc;
|
14
|
+
configure_tickets_args_t *args = (configure_tickets_args_t *)value;
|
16
15
|
|
17
|
-
if (quota > 0) {
|
18
|
-
tickets = calculate_quota_tickets(sem_id, quota);
|
16
|
+
if (args->quota > 0) {
|
17
|
+
args->tickets = calculate_quota_tickets(args->sem_id, args->quota);
|
19
18
|
}
|
20
19
|
|
21
20
|
/*
|
@@ -23,10 +22,10 @@ configure_tickets(int sem_id, int tickets, double quota)
|
|
23
22
|
We need to throw an error if we set it to 0 during initialization.
|
24
23
|
Otherwise, we back out of here completely.
|
25
24
|
*/
|
26
|
-
if (get_sem_val(sem_id, SI_SEM_CONFIGURED_TICKETS) == 0 && tickets == 0) {
|
25
|
+
if (get_sem_val(args->sem_id, SI_SEM_CONFIGURED_TICKETS) == 0 && args->tickets == 0) {
|
27
26
|
rb_raise(eSyscall, "More than 0 tickets must be specified when initializing semaphore");
|
28
|
-
} else if (tickets == 0) {
|
29
|
-
return;
|
27
|
+
} else if (args->tickets == 0) {
|
28
|
+
return Qnil;
|
30
29
|
}
|
31
30
|
|
32
31
|
/*
|
@@ -34,31 +33,26 @@ configure_tickets(int sem_id, int tickets, double quota)
|
|
34
33
|
count, we need to resize the count. We do this by adding the delta of
|
35
34
|
(tickets - current_configured_tickets) to the semaphore value.
|
36
35
|
*/
|
37
|
-
if (get_sem_val(sem_id, SI_SEM_CONFIGURED_TICKETS) != tickets) {
|
38
|
-
|
39
|
-
tc.sem_id = sem_id;
|
40
|
-
tc.tickets = tickets;
|
41
|
-
rb_protect((VALUE (*)(VALUE)) update_ticket_count, (VALUE) &tc, &state);
|
42
|
-
|
43
|
-
if (state) {
|
44
|
-
rb_jump_tag(state);
|
45
|
-
}
|
36
|
+
if (get_sem_val(args->sem_id, SI_SEM_CONFIGURED_TICKETS) != args->tickets) {
|
37
|
+
update_ticket_count(args->sem_id, args->tickets);
|
46
38
|
}
|
39
|
+
|
40
|
+
return Qnil;
|
47
41
|
}
|
48
42
|
|
49
43
|
static VALUE
|
50
|
-
update_ticket_count(
|
44
|
+
update_ticket_count(int sem_id, int tickets)
|
51
45
|
{
|
52
46
|
short delta;
|
53
47
|
struct timespec ts = { 0 };
|
54
48
|
ts.tv_sec = INTERNAL_TIMEOUT;
|
55
49
|
|
56
|
-
delta =
|
50
|
+
delta = tickets - get_sem_val(sem_id, SI_SEM_CONFIGURED_TICKETS);
|
57
51
|
|
58
52
|
#ifdef DEBUG
|
59
|
-
print_sem_vals(
|
53
|
+
print_sem_vals(sem_id);
|
60
54
|
#endif
|
61
|
-
if (perform_semop(
|
55
|
+
if (perform_semop(sem_id, SI_SEM_TICKETS, delta, 0, &ts) == -1) {
|
62
56
|
if (delta < 0 && errno == EAGAIN) {
|
63
57
|
rb_raise(eTimeout, "timeout while trying to update ticket count");
|
64
58
|
} else {
|
@@ -66,7 +60,7 @@ update_ticket_count(update_ticket_count_t *tc)
|
|
66
60
|
}
|
67
61
|
}
|
68
62
|
|
69
|
-
if (semctl(
|
63
|
+
if (semctl(sem_id, SI_SEM_CONFIGURED_TICKETS, SETVAL, tickets) == -1) {
|
70
64
|
rb_raise(eInternal, "error configuring ticket count, errno: %d (%s)", errno, strerror(errno));
|
71
65
|
}
|
72
66
|
|
data/ext/semian/tickets.h
CHANGED
@@ -7,7 +7,7 @@ For logic specific to manipulating semian ticket counts
|
|
7
7
|
#include "sysv_semaphores.h"
|
8
8
|
|
9
9
|
// Set initial ticket values upon resource creation
|
10
|
-
|
11
|
-
configure_tickets(
|
10
|
+
VALUE
|
11
|
+
configure_tickets(VALUE);
|
12
12
|
|
13
13
|
#endif // SEMIAN_TICKETS_H
|
data/ext/semian/types.h
CHANGED
@@ -20,11 +20,11 @@ union semun {
|
|
20
20
|
(Linux-specific) */
|
21
21
|
};
|
22
22
|
|
23
|
-
// To update the ticket count
|
24
23
|
typedef struct {
|
25
24
|
int sem_id;
|
26
25
|
int tickets;
|
27
|
-
|
26
|
+
double quota;
|
27
|
+
} configure_tickets_args_t;
|
28
28
|
|
29
29
|
// Internal semaphore structure
|
30
30
|
typedef struct {
|
@@ -35,6 +35,7 @@ typedef struct {
|
|
35
35
|
uint64_t key;
|
36
36
|
char *strkey;
|
37
37
|
char *name;
|
38
|
+
long wait_time;
|
38
39
|
} semian_resource_t;
|
39
40
|
|
40
41
|
#endif // SEMIAN_TYPES_H
|
@@ -113,7 +113,7 @@ module Semian
|
|
113
113
|
str = "[#{self.class.name}] State transition from #{@state.value} to #{new_state}."
|
114
114
|
str << " success_count=#{@successes.value} error_count=#{@errors.size}"
|
115
115
|
str << " success_count_threshold=#{@success_count_threshold} error_count_threshold=#{@error_count_threshold}"
|
116
|
-
str << " error_timeout=#{@error_timeout} error_last_at=\"#{@
|
116
|
+
str << " error_timeout=#{@error_timeout} error_last_at=\"#{@errors.last}\""
|
117
117
|
Semian.logger.info(str)
|
118
118
|
end
|
119
119
|
end
|
data/lib/semian/net_http.rb
CHANGED
@@ -43,15 +43,6 @@ module Semian
|
|
43
43
|
::SystemCallError, # includes ::Errno::EINVAL, ::Errno::ECONNRESET, ::Errno::ECONNREFUSED, ::Errno::ETIMEDOUT, and more
|
44
44
|
].freeze # Net::HTTP can throw many different errors, this tries to capture most of them
|
45
45
|
|
46
|
-
# The naked methods are exposed as `raw_query` and `raw_connect` for instrumentation purpose
|
47
|
-
def self.included(base)
|
48
|
-
base.send(:alias_method, :raw_transport_request, :transport_request)
|
49
|
-
base.send(:remove_method, :transport_request)
|
50
|
-
|
51
|
-
base.send(:alias_method, :raw_connect, :connect)
|
52
|
-
base.send(:remove_method, :connect)
|
53
|
-
end
|
54
|
-
|
55
46
|
class << self
|
56
47
|
attr_accessor :exceptions
|
57
48
|
attr_reader :semian_configuration
|
@@ -88,26 +79,26 @@ module Semian
|
|
88
79
|
end
|
89
80
|
|
90
81
|
def connect
|
91
|
-
return
|
92
|
-
acquire_semian_resource(adapter: :http, scope: :connection) {
|
82
|
+
return super if disabled?
|
83
|
+
acquire_semian_resource(adapter: :http, scope: :connection) { super }
|
93
84
|
end
|
94
85
|
|
95
|
-
def transport_request(
|
96
|
-
return
|
86
|
+
def transport_request(*)
|
87
|
+
return super if disabled?
|
97
88
|
acquire_semian_resource(adapter: :http, scope: :query) do
|
98
|
-
|
99
|
-
handle_error_responses(res)
|
100
|
-
res
|
89
|
+
handle_error_responses(super)
|
101
90
|
end
|
102
91
|
end
|
103
92
|
|
104
93
|
private
|
105
94
|
|
106
|
-
def handle_error_responses(
|
107
|
-
|
108
|
-
|
95
|
+
def handle_error_responses(result)
|
96
|
+
if raw_semian_options.fetch(:open_circuit_server_errors, false)
|
97
|
+
semian_resource.mark_failed(result) if result.is_a?(::Net::HTTPServerError)
|
98
|
+
end
|
99
|
+
result
|
109
100
|
end
|
110
101
|
end
|
111
102
|
end
|
112
103
|
|
113
|
-
Net::HTTP.
|
104
|
+
Net::HTTP.prepend(Semian::NetHTTP)
|
@@ -46,8 +46,8 @@ module Semian
|
|
46
46
|
if @bulkhead.nil?
|
47
47
|
yield self
|
48
48
|
else
|
49
|
-
@bulkhead.acquire(timeout: timeout) do
|
50
|
-
Semian.notify(:success, self, scope, adapter)
|
49
|
+
@bulkhead.acquire(timeout: timeout) do |wait_time|
|
50
|
+
Semian.notify(:success, self, scope, adapter, wait_time)
|
51
51
|
yield self
|
52
52
|
end
|
53
53
|
end
|
data/lib/semian/resource.rb
CHANGED
data/lib/semian/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: semian
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Francis
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2017-
|
13
|
+
date: 2017-11-07 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rake-compiler
|
@@ -179,7 +179,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
179
179
|
version: '0'
|
180
180
|
requirements: []
|
181
181
|
rubyforge_project:
|
182
|
-
rubygems_version: 2.5.2
|
182
|
+
rubygems_version: 2.5.2.1
|
183
183
|
signing_key:
|
184
184
|
specification_version: 4
|
185
185
|
summary: Bulkheading for Ruby with SysV semaphores
|