semian 0.7.1 → 0.7.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|