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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5d7a8e836a1f026b0dc5afcf4454f9949fcb44e0
4
- data.tar.gz: 68858abd9489ecb207656472ff910a7f6ad824ce
3
+ metadata.gz: a4701f3daa0b3ff3ed0f7a2a60ae025d023a4b2c
4
+ data.tar.gz: 464b2d490be5404dbabd1ed50d15b84e5bdd7e11
5
5
  SHA512:
6
- metadata.gz: 1cacd63d08f2fc3b7f42509295b3735ed8948c9185a8a236af5be737226e89dbf7614eec29f6f7d3d26cce5e05f66a6ef3a550b5081c1e0736575427702b912b
7
- data.tar.gz: f736999b06d706947b2ba81170c4fbd1f5b6d2fa909c4058d60806e918cea1bad5d6757726929feb1f8fa382d8a013f9ac6827527067dff6cb886a27c3e282e7
6
+ metadata.gz: 65122ec1d4ef4c7cb337ac00d4f8838d38b6ac8777b1e4a64d52b2381cb0b9938fa1cc85da3e6fabc88aa98c7e48cde73c253d090597fdb3ddf1b0f5f4399734
7
+ data.tar.gz: 545e6a6b3350bf4e06156945d84c5a89d2d57dc75d7e0a3dc83cbe385b8ba8a5a8585c21cc85bb9328591ecce027b0cc522772be221dcf72304f3c0769dbb402
@@ -63,7 +63,12 @@ semian_resource_acquire(int argc, VALUE *argv, VALUE self)
63
63
  }
64
64
  }
65
65
 
66
- return rb_ensure(rb_yield, self, cleanup_semian_resource_acquire, self);
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);
@@ -10,6 +10,7 @@ Functions here are associated with rubyland operations.
10
10
  #include "sysv_semaphores.h"
11
11
 
12
12
  // Ruby variables
13
+ ID id_wait_time;
13
14
  ID id_timeout;
14
15
  int system_max_semaphore_count;
15
16
 
@@ -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
- configure_tickets(res->sem_id, tickets, quota);
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("semget()", errno);
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
+ }
@@ -2,20 +2,19 @@
2
2
 
3
3
  // Update the ticket count for static ticket tracking
4
4
  static VALUE
5
- update_ticket_count(update_ticket_count_t *tc);
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
- void
12
- configure_tickets(int sem_id, int tickets, double quota)
11
+ VALUE
12
+ configure_tickets(VALUE value)
13
13
  {
14
- int state = 0;
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(update_ticket_count_t *tc)
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 = tc->tickets - get_sem_val(tc->sem_id, SI_SEM_CONFIGURED_TICKETS);
50
+ delta = tickets - get_sem_val(sem_id, SI_SEM_CONFIGURED_TICKETS);
57
51
 
58
52
  #ifdef DEBUG
59
- print_sem_vals(tc->sem_id);
53
+ print_sem_vals(sem_id);
60
54
  #endif
61
- if (perform_semop(tc->sem_id, SI_SEM_TICKETS, delta, 0, &ts) == -1) {
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(tc->sem_id, SI_SEM_CONFIGURED_TICKETS, SETVAL, tc->tickets) == -1) {
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
 
@@ -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
- void
11
- configure_tickets(int sem_id, int tickets, double quota);
10
+ VALUE
11
+ configure_tickets(VALUE);
12
12
 
13
13
  #endif // SEMIAN_TICKETS_H
@@ -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
- } update_ticket_count_t;
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=\"#{@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
@@ -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 raw_connect if disabled?
92
- acquire_semian_resource(adapter: :http, scope: :connection) { raw_connect }
82
+ return super if disabled?
83
+ acquire_semian_resource(adapter: :http, scope: :connection) { super }
93
84
  end
94
85
 
95
- def transport_request(req, &block)
96
- return raw_transport_request(req, &block) if disabled?
86
+ def transport_request(*)
87
+ return super if disabled?
97
88
  acquire_semian_resource(adapter: :http, scope: :query) do
98
- res = raw_transport_request(req, &block)
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(res)
107
- return unless raw_semian_options.fetch(:open_circuit_server_errors, false)
108
- semian_resource.mark_failed(res) if res.is_a?(::Net::HTTPServerError)
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.include(Semian::NetHTTP)
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
@@ -28,7 +28,8 @@ module Semian
28
28
  end
29
29
 
30
30
  def acquire(*)
31
- yield self
31
+ wait_time = 0
32
+ yield wait_time
32
33
  end
33
34
 
34
35
  def count
@@ -1,3 +1,3 @@
1
1
  module Semian
2
- VERSION = '0.7.1'
2
+ VERSION = '0.7.4'
3
3
  end
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.1
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-06-23 00:00:00.000000000 Z
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