content_server 1.1.0 → 1.2.0

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.
Files changed (137) hide show
  1. data/bin/backup_server +8 -20
  2. data/bin/content_server +8 -20
  3. data/bin/testing_memory +60 -0
  4. data/bin/testing_server +57 -0
  5. data/ext/run_in_background/mkrf_conf.rb +34 -0
  6. data/lib/content_data/content_data.rb +613 -0
  7. data/lib/content_data/version.rb +3 -0
  8. data/lib/content_data.rb +6 -0
  9. data/lib/content_server/backup_server.rb +65 -86
  10. data/lib/content_server/content_server.rb +47 -77
  11. data/lib/content_server/file_streamer.rb +27 -33
  12. data/lib/content_server/queue_copy.rb +154 -49
  13. data/lib/content_server/queue_indexer.rb +19 -11
  14. data/lib/content_server/remote_content.rb +41 -23
  15. data/lib/content_server/server.rb +91 -0
  16. data/lib/content_server/version.rb +1 -1
  17. data/lib/content_server.rb +0 -15
  18. data/lib/email/email.rb +87 -0
  19. data/lib/email/version.rb +3 -0
  20. data/lib/email.rb +4 -0
  21. data/lib/file_copy/copy.rb +68 -0
  22. data/lib/file_copy/version.rb +4 -0
  23. data/lib/file_copy.rb +4 -0
  24. data/lib/file_indexing/index_agent.rb +170 -0
  25. data/lib/file_indexing/indexer_patterns.rb +72 -0
  26. data/lib/file_indexing/version.rb +3 -0
  27. data/lib/file_indexing.rb +9 -0
  28. data/lib/file_monitoring/file_monitoring.rb +105 -0
  29. data/lib/file_monitoring/monitor_path.rb +304 -0
  30. data/lib/file_monitoring/version.rb +3 -0
  31. data/lib/file_monitoring.rb +29 -0
  32. data/lib/file_utils/file_generator/README +97 -0
  33. data/lib/file_utils/file_generator/file_generator.rb +156 -0
  34. data/lib/file_utils/file_utils.rb +260 -0
  35. data/lib/file_utils/version.rb +3 -0
  36. data/lib/file_utils.rb +4 -0
  37. data/lib/log/version.rb +3 -0
  38. data/lib/log.rb +188 -0
  39. data/lib/networking/tcp.rb +213 -0
  40. data/lib/networking/version.rb +3 -0
  41. data/lib/networking.rb +4 -0
  42. data/lib/params/version.rb +3 -0
  43. data/lib/params.rb +419 -0
  44. data/lib/process_monitoring/monitoring.rb +85 -0
  45. data/lib/process_monitoring/monitoring_info.rb +79 -0
  46. data/lib/process_monitoring/send_email.rb +40 -0
  47. data/lib/process_monitoring/thread_safe_hash.rb +77 -0
  48. data/lib/process_monitoring/version.rb +3 -0
  49. data/lib/process_monitoring.rb +6 -0
  50. data/lib/run_in_background/version.rb +3 -0
  51. data/lib/run_in_background.rb +432 -0
  52. data/lib/testing_memory/testing_memory.rb +187 -0
  53. data/lib/testing_server/testing_server.rb +236 -0
  54. data/lib/testing_server/version.rb +3 -0
  55. data/lib/testing_server.rb +12 -0
  56. data/lib/validations/index_validations.rb +106 -0
  57. data/lib/validations/version.rb +3 -0
  58. data/lib/validations.rb +4 -0
  59. data/spec/content_data/validations_spec.rb +113 -0
  60. data/spec/file_copy/copy_spec.rb +54 -0
  61. data/spec/file_indexing/index_agent_spec.rb +53 -0
  62. data/spec/networking/tcp_spec.rb +95 -0
  63. data/spec/validations/index_validations_spec.rb +77 -0
  64. data/test/content_data/content_data_test.rb +290 -0
  65. data/test/file_generator/file_generator_spec.rb +84 -0
  66. data/test/file_indexing/index_agent_test/New.txt +0 -0
  67. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/libexslt.dll +0 -0
  68. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/libxslt.dll +0 -0
  69. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/xsltproc.exe +0 -0
  70. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exslt.h +102 -0
  71. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exsltconfig.h +73 -0
  72. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exsltexports.h +140 -0
  73. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/libexslt.h +29 -0
  74. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/attributes.h +38 -0
  75. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/documents.h +93 -0
  76. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/extensions.h +262 -0
  77. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/extra.h +80 -0
  78. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/functions.h +78 -0
  79. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/imports.h +75 -0
  80. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/keys.h +53 -0
  81. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/libxslt.h +30 -0
  82. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/namespaces.h +68 -0
  83. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/numbersInternals.h +69 -0
  84. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/pattern.h +81 -0
  85. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/preproc.h +43 -0
  86. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/security.h +104 -0
  87. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/templates.h +77 -0
  88. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/transform.h +207 -0
  89. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/trio.h +216 -0
  90. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/triodef.h +220 -0
  91. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/variables.h +91 -0
  92. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/win32config.h +101 -0
  93. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xslt.h +103 -0
  94. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltInternals.h +1967 -0
  95. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltconfig.h +172 -0
  96. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltexports.h +142 -0
  97. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltlocale.h +57 -0
  98. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltutils.h +309 -0
  99. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltwin32config.h +105 -0
  100. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libexslt.lib +0 -0
  101. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libexslt_a.lib +0 -0
  102. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libxslt.lib +0 -0
  103. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libxslt_a.lib +0 -0
  104. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/readme.txt +22 -0
  105. data/test/file_indexing/index_agent_test/patterns.input +3 -0
  106. data/test/file_indexing/index_agent_test.rb +51 -0
  107. data/test/file_monitoring/file_monitoring_test/conf.yml +4 -0
  108. data/test/file_monitoring/file_monitoring_test/conf_win32.yml +5 -0
  109. data/test/file_monitoring/file_monitoring_test/log +56 -0
  110. data/test/file_monitoring/file_monitoring_test.rb +0 -0
  111. data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000 +1000 -0
  112. data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000.0 +1000 -0
  113. data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000.1 +1000 -0
  114. data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500 +1500 -0
  115. data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500.0 +1500 -0
  116. data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500.1 +1500 -0
  117. data/test/file_monitoring/monitor_path_test/test_file.500 +500 -0
  118. data/test/file_monitoring/monitor_path_test/test_file.500.0 +500 -0
  119. data/test/file_monitoring/monitor_path_test/test_file.500.1 +500 -0
  120. data/test/file_monitoring/monitor_path_test.rb +153 -0
  121. data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500 +1500 -0
  122. data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500.0 +1500 -0
  123. data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500.1 +1500 -0
  124. data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000 +1000 -0
  125. data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000.0 +1000 -0
  126. data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000.1 +1000 -0
  127. data/test/file_utils/fileutil_mksymlink_test/test_file.500 +500 -0
  128. data/test/file_utils/fileutil_mksymlink_test/test_file.500.0 +500 -0
  129. data/test/file_utils/fileutil_mksymlink_test/test_file.500.1 +500 -0
  130. data/test/file_utils/fileutil_mksymlink_test.rb +125 -0
  131. data/test/file_utils/time_modification_test.rb +132 -0
  132. data/test/params/params_spec.rb +280 -0
  133. data/test/params/params_test.rb +43 -0
  134. data/test/run_in_background/run_in_background_test.rb +122 -0
  135. data/test/run_in_background/test_app +57 -0
  136. metadata +272 -132
  137. data/lib/content_server/globals.rb +0 -10
@@ -2,16 +2,17 @@ require 'thread'
2
2
 
3
3
  require 'content_server/file_streamer'
4
4
  require 'file_indexing/index_agent'
5
- require 'content_server/globals'
5
+ require 'content_server/server'
6
6
  require 'log'
7
7
  require 'networking/tcp'
8
8
  require 'params'
9
9
 
10
-
11
10
  module ContentServer
12
11
  Params.integer('ack_timeout', 5, 'Timeout of ack from backup server in seconds.')
13
-
12
+ Params.integer('local_timeout', 60, 'Timeout of content being under copy process.')
13
+ Params.integer('max_copy_streams', 5, 'max contents being copied at once.')
14
14
  # Copy message types.
15
+ :SEND_COPY_MESSAGE
15
16
  :ACK_MESSAGE
16
17
  :COPY_MESSAGE
17
18
  :SEND_COPY_MESSAGE
@@ -20,6 +21,119 @@ module ContentServer
20
21
  :ABORT_COPY # Asks the sender to abort file copy.
21
22
  :RESET_RESUME_COPY # Sends the stream sender to resend chunk or resume from different offset.
22
23
 
24
+ class FileCopyManager
25
+ def initialize(copy_input_queue, file_streamer)
26
+ @copy_input_queue = copy_input_queue
27
+ @file_streamer = file_streamer
28
+ @max_contents_under_copy = Params['max_copy_streams']
29
+ @contents_under_copy = {}
30
+ @contents_to_copy = {}
31
+ @contents_to_copy_queue = Queue.new
32
+ @keeper = Mutex.new
33
+ @clean_time_out_thread = clean_time_out_thread
34
+ end
35
+
36
+ # Add content to copy process. If already in copy process or waiting for copy then skip.
37
+ # If no open places for copy then put in waiting list
38
+ def add_content(checksum, path)
39
+ Log.debug2("Try to add content:#{checksum} to copy waiting list")
40
+ @keeper.synchronize{
41
+ # if content is being copied or waiting then skip it
42
+ if !@contents_under_copy[checksum]
43
+ if !@contents_to_copy[checksum]
44
+ if @contents_under_copy.size < @max_contents_under_copy
45
+ @contents_under_copy[checksum] = [path, false, Time.now]
46
+ $process_vars.set('contents under copy', @contents_under_copy.size)
47
+ @copy_input_queue.push([:SEND_ACK_MESSAGE, checksum])
48
+ $process_vars.set('Copy File Queue Size', @copy_input_queue.size)
49
+ else
50
+ # no place in copy streams. Add to waiting list
51
+ Log.debug2("add content:#{checksum} to copy waiting list")
52
+ @contents_to_copy[checksum] = true # replace with a set
53
+ @contents_to_copy_queue.push([checksum, path])
54
+ $process_vars.set('contents to copy queue', @contents_to_copy_queue.size)
55
+ end
56
+ else
57
+ Log.debug2("content:#{checksum} already in waiting list. skipping.")
58
+ end
59
+ else
60
+ Log.debug2("content:#{checksum} is being copied. skipping.")
61
+ end
62
+ }
63
+ end
64
+
65
+ def receive_ack(checksum)
66
+ @keeper.synchronize{
67
+ content_record = @contents_under_copy[checksum]
68
+ if content_record
69
+ if !content_record[1]
70
+ path = content_record[0]
71
+ Log.debug1("Streaming to backup server. content: #{checksum} path:#{path}.")
72
+ @file_streamer.start_streaming(checksum, path)
73
+ # updating Ack
74
+ content_record[1] = true
75
+ else
76
+ Log.warning("File already received ack: #{checksum}")
77
+ end
78
+ else
79
+ Log.warning("File was aborted or copied: #{checksum}")
80
+ end
81
+ }
82
+ end
83
+
84
+ def remove_content(checksum)
85
+ @keeper.synchronize{
86
+ Log.debug3("removing checksum:#{checksum} from contents under copy")
87
+ @contents_under_copy.delete(checksum)
88
+ $process_vars.set('contents under copy', @contents_under_copy.size)
89
+ #1 place is became available. Put another file in copy process if waiting
90
+ if (@contents_to_copy_queue.size > 0)
91
+ new_content = @contents_to_copy_queue.pop
92
+ $process_vars.set('contents to copy queue', @contents_to_copy_queue.size)
93
+ @contents_to_copy.delete(new_content[0])
94
+ @contents_under_copy[new_content[0]] = [new_content[1], false, Time.now]
95
+ $process_vars.set('contents under copy', @contents_under_copy.size)
96
+ @copy_input_queue.push([:SEND_ACK_MESSAGE, new_content[0]])
97
+ $process_vars.set('Copy File Queue Size', @copy_input_queue.size)
98
+ end
99
+ }
100
+ end
101
+
102
+ # clean timed out contents
103
+ def clean_time_out_thread
104
+ @thread = Thread.new do
105
+ loop {
106
+ sleep 10
107
+ @keeper.synchronize{
108
+ # clean timed out contents
109
+ time_now = Time.now
110
+ new_contents_under_copy = {}
111
+ @contents_under_copy.each_key { |checksum|
112
+ if time_now - @contents_under_copy[checksum][2] > Params['local_timeout']
113
+ @contents_under_copy.delete(checksum)
114
+ $process_vars.set('contents under copy', @contents_under_copy.size)
115
+ Log.warning("Content:#{checksum} has timed out on copy process")
116
+ @file_streamer.abort_streaming(checksum)
117
+ if (@contents_to_copy_queue.size > 0)
118
+ new_content = @contents_to_copy_queue.pop
119
+ $process_vars.set('contents to copy queue', @contents_to_copy_queue.size)
120
+ @contents_to_copy.delete(new_content[0])
121
+ new_contents_under_copy[new_content[0]] = new_content[1]
122
+ end
123
+ end
124
+ }
125
+ new_contents_under_copy.each_key { |checksum|
126
+ @contents_under_copy[checksum.clone] = [new_contents_under_copy[checksum].clone, false, time_now]
127
+ $process_vars.set('contents under copy', @contents_under_copy.size)
128
+ @copy_input_queue.push([:SEND_ACK_MESSAGE, checksum])
129
+ $process_vars.set('Copy File Queue Size', @copy_input_queue.size)
130
+ }
131
+ }
132
+ }
133
+ end
134
+ end
135
+ end
136
+
23
137
  # Simple copier, gets inputs events (files to copy), requests ack from backup to copy
24
138
  # then copies one file.
25
139
  class FileCopyServer
@@ -33,16 +147,19 @@ module ContentServer
33
147
  @copy_prepare = {}
34
148
  @file_streamer = FileStreamer.new(method(:send_chunk))
35
149
  Log.debug3("initialize FileCopyServer on port:#{port}")
150
+ @file_copy_manager = FileCopyManager.new(@copy_input_queue, @file_streamer)
36
151
  end
37
152
 
38
153
  def send_chunk(*arg)
39
154
  @copy_input_queue.push([:COPY_CHUNK, arg])
155
+ $process_vars.set('Copy File Queue Size', @copy_input_queue.size)
40
156
  end
41
157
 
42
158
  def receive_message(addr_info, message)
43
159
  # Add ack message to copy queue.
44
160
  Log.debug2("Content server Copy message received: #{message}")
45
161
  @copy_input_queue.push(message)
162
+ $process_vars.set('Copy File Queue Size', @copy_input_queue.size)
46
163
  end
47
164
 
48
165
  def run()
@@ -51,44 +168,38 @@ module ContentServer
51
168
  threads << Thread.new do
52
169
  while true do
53
170
  Log.debug1 'Waiting on copy files events.'
54
- message_type, message_content = @copy_input_queue.pop
171
+ (message_type, message_content) = @copy_input_queue.pop
172
+ $process_vars.set('Copy File Queue Size', @copy_input_queue.size)
173
+ Log.debug1("Content copy message:#{[message_type, message_content]}")
55
174
 
56
- if message_type == :COPY_MESSAGE
57
- Log.debug1 "Copy files event: #{message_content}"
58
- # Prepare source,dest map for copy.
175
+ if message_type == :SEND_ACK_MESSAGE
176
+ Log.debug1("Sending ack for: #{message_content}")
177
+ @backup_tcp.send_obj([:ACK_MESSAGE, [message_content, Time.now.to_i]])
178
+ elsif message_type == :COPY_MESSAGE
59
179
  message_content.each_instance { |checksum, size, content_mod_time, instance_mod_time, server, path|
60
- if !@copy_prepare.key?(checksum) || !@copy_prepare[checksum][1]
61
- @copy_prepare[checksum] = [path, false]
62
- Log.debug1("Sending ack for: #{checksum}")
63
- @backup_tcp.send_obj([:ACK_MESSAGE, [checksum, Time.now.to_i]])
64
- end
180
+ @file_copy_manager.add_content(checksum, path)
65
181
  }
66
182
  elsif message_type == :ACK_MESSAGE
67
183
  # Received ack from backup, copy file if all is good.
68
184
  # The timestamp is of local content server! not backup server!
69
185
  timestamp, ack, checksum = message_content
70
-
71
186
  Log.debug1("Ack (#{ack}) received for content: #{checksum}, timestamp: #{timestamp} " \
72
187
  "now: #{Time.now.to_i}")
73
188
 
74
189
  # Copy file if ack (does not exists on backup and not too much time passed)
75
190
  if ack
76
191
  if (Time.now.to_i - timestamp < Params['ack_timeout'])
77
- if !@copy_prepare.key?(checksum) || @copy_prepare[checksum][1]
78
- Log.warning("File was aborted, copied, or started copy just now: #{checksum}")
79
- else
80
- path = @copy_prepare[checksum][0]
81
- Log.info "Streaming to backup server. content: #{checksum} path:#{path}."
82
- @file_streamer.start_streaming(checksum, path)
83
- # Ack received, setting prepare to true
84
- @copy_prepare[checksum][1] = true
85
- end
192
+ @file_copy_manager.receive_ack(checksum)
86
193
  else
87
194
  Log.debug1("Ack timed out span: #{Time.now.to_i - timestamp} > " \
88
195
  "timeout: #{Params['ack_timeout']}")
196
+ # remove only content under copy
197
+ @file_copy_manager.remove_content(checksum)
89
198
  end
90
199
  else
91
200
  Log.debug1('Ack is false');
201
+ # remove content under copy and content in waiting list
202
+ @file_copy_manager.remove_content(checksum)
92
203
  end
93
204
  elsif message_type == :COPY_CHUNK_FROM_REMOTE
94
205
  checksum = message_content
@@ -97,21 +208,20 @@ module ContentServer
97
208
  # We open the message here for printing info and deleting copy_prepare!
98
209
  file_checksum, offset, file_size, content, content_checksum = message_content
99
210
  Log.debug1("Send chunk for file #{file_checksum}, offset: #{offset} " \
100
- "filesize: #{file_size}.")
211
+ "filesize: #{file_size}, checksum:#{content_checksum}")
101
212
  # Blocking send.
102
213
  @backup_tcp.send_obj([:COPY_CHUNK, message_content])
103
214
  if content.nil? and content_checksum.nil?
104
- @copy_prepare.delete(file_checksum)
215
+ # Sending enf of file and removing file from list
216
+ @file_copy_manager.remove_content(file_checksum)
105
217
  end
106
218
  elsif message_type == :ABORT_COPY
107
219
  Log.debug1("Aborting file copy: #{message_content}")
108
- if @copy_prepare.key?(message_content)
109
- Log.debug1("Aborting: #{@copy_prepare[message_content][0]}")
110
- @copy_prepare.delete(message_content)
111
- end
112
220
  @file_streamer.abort_streaming(message_content)
221
+ # remove only content under copy
222
+ @file_copy_manager.remove_content(message_content)
113
223
  elsif message_type == :RESET_RESUME_COPY
114
- file_checksum, new_offset = message_content
224
+ (file_checksum, new_offset) = message_content
115
225
  Log.debug1("Resetting/Resuming file (#{file_checksum}) copy to #{new_offset}")
116
226
  @file_streamer.reset_streaming(file_checksum, new_offset)
117
227
  else
@@ -124,20 +234,17 @@ module ContentServer
124
234
  end # class QueueCopy
125
235
 
126
236
  class FileCopyClient
127
- def initialize(host, port, dynamic_content_data)
237
+ def initialize(host, port)
128
238
  @local_queue = Queue.new
129
- @dynamic_content_data = dynamic_content_data
130
239
  @tcp_client = Networking::TCPClient.new(host, port, method(:handle_message))
131
240
  @file_receiver = FileReceiver.new(method(:done_copy),
132
241
  method(:abort_copy),
133
242
  method(:reset_copy))
134
243
  @local_thread = Thread.new do
135
244
  loop do
136
- pop_queue = @local_queue.pop
137
- if Params['enable_monitoring']
138
- ::ContentServer::Globals.process_vars.set('File Copy Client queue', @local_queue.size)
139
- end
140
- handle(@local_queue.pop)
245
+ pop_data = @local_queue.pop
246
+ $process_vars.set('File Copy Client queue', @local_queue.size)
247
+ handle(pop_data)
141
248
  end
142
249
  end
143
250
  @local_thread.abort_on_exception = true
@@ -163,42 +270,40 @@ module ContentServer
163
270
  end
164
271
 
165
272
  def done_copy(local_file_checksum, local_path)
166
- if Params['enable_monitoring']
167
- ::ContentServer::Globals.process_vars.inc('num_files_received')
168
- end
273
+ $process_vars.inc('num_files_received')
169
274
  Log.debug1("Done copy file: #{local_path}, #{local_file_checksum}")
170
275
  end
171
276
 
172
277
  def handle_message(message)
173
278
  Log.debug3('QueueFileReceiver handle message')
174
279
  @local_queue.push(message)
175
- if Params['enable_monitoring']
176
- ::ContentServer::Globals.process_vars.set('File Copy Client queue', @local_queue.size)
177
- end
280
+ $process_vars.set('File Copy Client queue', @local_queue.size)
178
281
  end
179
282
 
180
283
  # This is a function which receives the messages (file or ack) and return answer in case
181
284
  # of ack. Note that it is being executed from the class thread only!
182
285
  def handle(message)
183
286
  message_type, message_content = message
287
+ Log.debug1("backup copy message: Type #{message_type}. message: #{message_content}")
184
288
  if message_type == :SEND_COPY_MESSAGE
185
- Log.debug1("Requesting files to copy.")
186
- Log.debug2("Files requested: #{message_content.to_s}")
187
289
  bytes_written = @tcp_client.send_obj([:COPY_MESSAGE, message_content])
188
290
  Log.debug2("Sending copy message succeeded? bytes_written: #{bytes_written}.")
189
291
  elsif message_type == :COPY_CHUNK
190
- Log.debug1('Chunk received.')
191
292
  if @file_receiver.receive_chunk(*message_content)
192
293
  file_checksum, offset, file_size, content, content_checksum = message_content
193
294
  @tcp_client.send_obj([:COPY_CHUNK_FROM_REMOTE, file_checksum])
295
+ else
296
+ file_checksum, offset, file_size, content, content_checksum = message_content
297
+ Log.error("receive_chunk failed for chunk checksum:#{content_checksum}")
194
298
  end
195
299
  elsif message_type == :ACK_MESSAGE
196
300
  checksum, timestamp = message_content
197
- # Here we should check file existence
198
- Log.info("Returning ack for content: #{checksum}, timestamp: #{timestamp}")
199
- Log.debug1("Ack: #{!@dynamic_content_data.exists?(checksum)}")
301
+ # check if checksum exists in final destination
302
+ dest_path = FileReceiver.destination_filename(Params['backup_destination_folder'][0]['path'], checksum)
303
+ need_to_copy = !File.exists?(dest_path)
304
+ Log.debug1("Returning ack for content:'#{checksum}' timestamp:'#{timestamp}' Ack:'#{need_to_copy}'")
200
305
  @tcp_client.send_obj([:ACK_MESSAGE, [timestamp,
201
- !@dynamic_content_data.exists?(checksum),
306
+ need_to_copy,
202
307
  checksum]])
203
308
  elsif message_type == :ABORT_COPY
204
309
  @tcp_client.send_obj([:ABORT_COPY, message_content])
@@ -1,6 +1,6 @@
1
1
  require 'file_indexing/index_agent'
2
2
  require 'file_indexing/indexer_patterns'
3
- require 'content_server/globals'
3
+ require 'content_server/server'
4
4
  require 'log'
5
5
  require 'params'
6
6
 
@@ -10,9 +10,8 @@ module ContentServer
10
10
  # content data updates into output queue.
11
11
  class QueueIndexer
12
12
 
13
- def initialize(input_queue, local_dynamic_content_data)
13
+ def initialize(input_queue)
14
14
  @input_queue = input_queue
15
- @local_dynamic_content_data = local_dynamic_content_data
16
15
  end
17
16
 
18
17
  # index files and add to copy queue
@@ -24,20 +23,25 @@ module ContentServer
24
23
  while true do
25
24
  Log.debug1 'Waiting on index input queue.'
26
25
  (state, is_dir, path, mtime, size) = @input_queue.pop
26
+ $process_vars.set('monitor to index queue size', @input_queue.size)
27
27
  Log.debug1 "index event: state:#{state}, dir?#{is_dir}, path:#{path}, mtime:#{mtime}, size:#{size}."
28
28
  if state == FileMonitoring::FileStatEnum::STABLE && !is_dir
29
29
  # Calculating checksum
30
- instance_stats = @local_dynamic_content_data.stats_by_location([Params['local_server_name'], path])
30
+ instance_stats = nil # definition
31
+ $local_content_data_lock.synchronize{
32
+ instance_stats = $local_content_data.stats_by_location([Params['local_server_name'], path])
33
+ }
31
34
  Log.debug1("instance !#{instance_stats}! mtime: #{mtime.to_i}, size: #{size}")
32
35
  if instance_stats.nil? || mtime.to_i != instance_stats[1] || size != instance_stats[0]
33
- Log.info "Indexing file:'#{path}'."
36
+ Log.debug1 "Indexing file:'#{path}'."
34
37
  checksum = calc_SHA1(path)
35
- if Params['enable_monitoring']
36
- ::ContentServer::Globals.process_vars.inc('indexed_files')
37
- end
38
+ $process_vars.inc('indexed_files')
39
+ $indexed_file_count += 1
38
40
  Log.debug1("Index info:checksum:#{checksum} size:#{size} time:#{mtime.to_i}")
39
41
  Log.debug1('Adding index to content data. put in queue for dynamic update.')
40
- @local_dynamic_content_data.add_instance(checksum, size, Params['local_server_name'], path, mtime.to_i)
42
+ $local_content_data_lock.synchronize{
43
+ $local_content_data.add_instance(checksum, size, Params['local_server_name'], path, mtime.to_i)
44
+ }
41
45
  else
42
46
  Log.info("Skip file #{path} indexing (shallow check passed)")
43
47
  end
@@ -46,12 +50,16 @@ module ContentServer
46
50
  Log.debug2("NonExisting/Changed (file): #{path}")
47
51
  # Remove file but only when non-existing.
48
52
  Log.debug1("File to remove: #{path}")
49
- @local_dynamic_content_data.remove_instance([Params['local_server_name'],path])
53
+ $local_content_data_lock.synchronize{
54
+ $local_content_data.remove_instance(Params['local_server_name'], path)
55
+ }
50
56
  elsif state == FileMonitoring::FileStatEnum::NON_EXISTING && is_dir
51
57
  Log.debug2("NonExisting/Changed (dir): #{path}")
52
58
  # Remove directory but only when non-existing.
53
59
  Log.debug1("Directory to remove: #{path}")
54
- @local_dynamic_content_data.remove_directory(path, Params['local_server_name'])
60
+ $local_content_data_lock.synchronize{
61
+ $local_content_data.remove_directory(Params['local_server_name'], path)
62
+ }
55
63
  else
56
64
  Log.debug1("This case should not be handled: #{state}, #{is_dir}, #{path}.")
57
65
  end
@@ -1,6 +1,5 @@
1
1
  require 'thread'
2
2
 
3
- require 'content_data/dynamic_content_data'
4
3
  require 'log'
5
4
  require 'networking/tcp'
6
5
  require 'params'
@@ -10,42 +9,51 @@ module ContentServer
10
9
  Params.integer('remote_content_fetch_timeout', 10, 'Remote content desired freshness in seconds.')
11
10
  Params.integer('remote_content_save_timeout', 60*60, 'Remote content force refresh in seconds.')
12
11
 
13
- # TODO(kolman): Use only one tcp/ip socket by utilizing one NQueue for many queues!
12
+ # Remote content Client
13
+ # Remote Content (client) - Periodically requests remote content (content server) from Remote Content Server.
14
+ # Stores locally the remote content data structure.
15
+ # Remote content client protocol based on time.
16
+ # Each n seconds it requests content from Remote Content Client connects to server (tcp/ip) and waits for request.
17
+ # remote_content_save_timeout is pre defined in config-backup_server.yml
14
18
  class RemoteContentClient
15
- def initialize(dynamic_content_data, host, port, local_backup_folder)
16
- @dynamic_content_data = dynamic_content_data
19
+ # initializes class variables
20
+ # @param host [ host] host address
21
+ # @param port[ port] port TCP/IP port
22
+ # @param local_backup_folder [local_backup_folder] pre defined folder for backup
23
+ def initialize(host, port, local_backup_folder)
17
24
  @remote_tcp = Networking::TCPClient.new(host, port, method(:receive_content))
18
25
  @last_fetch_timestamp = nil
19
26
  @last_save_timestamp = nil
27
+ @last_content_data_id = nil
20
28
  @content_server_content_data_path = File.join(local_backup_folder, 'remote',
21
29
  host + '_' + port.to_s)
22
30
  Log.debug3("Initialized RemoteContentClient: host:#{host} port:#{port} local_backup_folder:#{local_backup_folder}")
23
31
  end
24
32
 
33
+ # Receives content data, and writes it to file
34
+ # Unchanged data will not be saved
35
+ # @param message [Message] ContentData object
25
36
  def receive_content(message)
26
- Log.debug1("Backup server received Remote content data:#{message.to_s}")
27
37
  Log.info("Backup server received Remote content data")
28
- @dynamic_content_data.update(message)
29
38
  @last_fetch_timestamp = Time.now.to_i
30
39
 
31
- save_time_span = Params['remote_content_save_timeout']
32
- if !@last_save_timestamp.nil?
33
- save_time_span = Time.now.to_i - @last_save_timestamp
34
- end
35
-
36
- if save_time_span >= Params['remote_content_save_timeout']
37
- @last_save_timestamp = Time.now.to_i
38
- write_to = File.join(@content_server_content_data_path,
39
- @last_save_timestamp.to_s + '.cd')
40
+ # Update remote content data and write to file if changed ContentData received
41
+ if(message.unique_id != @last_content_data_id)
42
+ path = File.join(@content_server_content_data_path, @last_save_timestamp.to_s + '.cd')
40
43
  FileUtils.makedirs(@content_server_content_data_path) unless \
41
44
  File.directory?(@content_server_content_data_path)
42
- count = File.open(write_to, 'wb') { |f| f.write(message.to_s) }
43
- Log.debug1("Written content data to file:#{write_to}.")
45
+ $remote_content_data_lock.synchronize{
46
+ $remote_content_data = message
47
+ $remote_content_data.to_file(path)
48
+ @last_content_data_id = message.unique_id # save last content data ID
49
+ }
50
+ Log.debug1("Written content data to file:#{path}.")
44
51
  else
45
52
  Log.debug1("No need to write remote content data, it has not changed.")
46
53
  end
47
54
  end
48
55
 
56
+ # Runs Remote content client
49
57
  def run()
50
58
  Log.debug1("Running remote content client.")
51
59
  threads = []
@@ -55,13 +63,13 @@ module ContentServer
55
63
  loop do
56
64
  # if need content data
57
65
  sleep_time_span = Params['remote_content_save_timeout']
58
- if !@last_fetch_timestamp.nil?
66
+ if @last_fetch_timestamp
59
67
  sleep_time_span = Time.now.to_i - @last_fetch_timestamp
60
68
  end
61
69
  Log.debug1("sleep_time_span: #{sleep_time_span}")
62
70
  if sleep_time_span >= Params['remote_content_save_timeout']
63
71
  # Send ping!
64
- bytes_written = @remote_tcp.send_obj(nil)
72
+ @remote_tcp.send_obj(nil)
65
73
  Log.info("sending ping request for remote content data!")
66
74
  end
67
75
  sleep(sleep_time_span) if sleep_time_span > 0
@@ -70,21 +78,31 @@ module ContentServer
70
78
  end
71
79
  end
72
80
 
81
+ # Remote Content Server
82
+ # Simple TCP server.
83
+ #It connects to server and listens to incoming requests. After receiving the request it sends local content data structure.
73
84
  class RemoteContentServer
74
- def initialize(dynamic_content_data, port)
75
- @dynamic_content_data = dynamic_content_data
85
+ # initializes class variables
86
+ def initialize(port)
76
87
  @tcp_server = Networking::TCPServer.new(port, method(:content_requested))
77
88
  Log.debug3("initialize RemoteContentServer on port:#{port}")
78
89
  end
79
90
 
91
+ # content_requested
92
+ # @param addr_info [addr_info] address information
93
+ # @param message [message] Content Data
80
94
  def content_requested(addr_info, message)
81
95
  # Send response.
82
96
  Log.info("Content server received content data request")
83
- Log.debug1("Sending content data:#{@dynamic_content_data.last_content_data}")
84
- @tcp_server.send_obj(@dynamic_content_data.last_content_data)
97
+ $local_content_data_lock.synchronize{
98
+ Log.debug1("Sending content data:#{$local_content_data}")
99
+ @tcp_server.send_obj($local_content_data)
100
+ }
85
101
  Log.info('Content server sent content data')
86
102
  end
87
103
 
104
+ # Open TCP/IP Thread
105
+ # @return [run_server] (see #run_server)run TCP server definition in tcp.rb
88
106
  def tcp_thread
89
107
  return @tcp_server.tcp_thread if @tcp_server != nil
90
108
  nil
@@ -0,0 +1,91 @@
1
+ require 'log'
2
+ require 'params'
3
+ require 'process_monitoring/thread_safe_hash'
4
+
5
+
6
+ module ContentServer
7
+
8
+ # Flags combined for content and backup server.
9
+ Params.string('local_server_name', `hostname`.strip, 'local server name')
10
+ Params.path('tmp_path', '~/.bbfs/tmp', 'tmp path for temporary files')
11
+
12
+ Params.path('local_content_data_path', '', 'ContentData file path.')
13
+
14
+ # Monitoring
15
+ Params.boolean('enable_monitoring', false, 'Whether to enable process monitoring or not.')
16
+ Params.integer('process_vars_delay', 3, 'pulling time of variables')
17
+
18
+ # Handling thread exceptions.
19
+ Params.boolean('abort_on_exception', true, 'Any exception in any thread will abort the run.')
20
+
21
+ Params.integer('data_flush_delay', 300, 'Number of seconds to delay content data file flush to disk.')
22
+
23
+ #using module method fot globals initialization due to the use of 'Params'.
24
+ def init_globals
25
+ $process_vars = ThreadSafeHash::ThreadSafeHashMonitored.new(Params['enable_monitoring'])
26
+ $tmp_content_data_file = nil # will be init during execution
27
+ $testing_memory_active = false
28
+ $testing_memory_log = nil
29
+ $indexed_file_count = 0
30
+ $local_content_data = nil
31
+ $local_content_data_lock = nil
32
+ $remote_content_data_lock = nil
33
+ $remote_content_data = nil
34
+ end
35
+
36
+ def handle_program_termination(exception)
37
+ #Write exception message to console
38
+ message = "\nInterrupt or Exit happened in server:'#{Params['service_name']}'.\n" +
39
+ "Exception type:'#{exception.class}'.\n" +
40
+ "Exception message:'#{exception.message}'.\n" +
41
+ "Stopping process.\n" +
42
+ "Backtrace:\n#{exception.backtrace.join("\n")}"
43
+ puts(message)
44
+
45
+ # force write content data to file
46
+ if $local_content_data
47
+ puts("\nForce writing local content data to #{Params['local_content_data_path']}.")
48
+ $local_content_data.to_file($tmp_content_data_file)
49
+ File.rename($tmp_content_data_file, Params['local_content_data_path'])
50
+ end
51
+
52
+ #Write exception message to log and mail(if enabled)
53
+ Log.error(message)
54
+ end
55
+
56
+ def monitor_general_process_vars
57
+ objects_counters = {}
58
+ objects_counters["Time"] = Time.now.to_i
59
+ while true do
60
+ current_objects_counters = {}
61
+ sleep(Params['process_vars_delay'])
62
+ time = Time.now
63
+ $process_vars.set('time', time)
64
+ current_objects_counters['Time'] = time.to_i
65
+ count = ObjectSpace.each_object(String).count
66
+ $process_vars.set('String count', count)
67
+ current_objects_counters['String'] = count
68
+ count = ObjectSpace.each_object(ContentData::ContentData).count
69
+ $process_vars.set('ContentData count', count)
70
+ current_objects_counters['ContentData'] = count
71
+ dir_count = ObjectSpace.each_object(FileMonitoring::DirStat).count
72
+ $process_vars.set('DirStat count', dir_count)
73
+ current_objects_counters['DirStat'] = dir_count
74
+ file_count = ObjectSpace.each_object(FileMonitoring::FileStat).count
75
+ $process_vars.set('FileStat count', file_count-dir_count)
76
+ current_objects_counters['FileStat'] = file_count-dir_count
77
+
78
+ # Generate report and update global counters
79
+ report = ""
80
+ current_objects_counters.each_key { |type|
81
+ objects_counters[type] = 0 unless objects_counters[type]
82
+ diff = current_objects_counters[type] - objects_counters[type]
83
+ report += "Type:#{type} raised in:#{diff} \n"
84
+ objects_counters[type] = current_objects_counters[type]
85
+ }
86
+ Log.info("MEM REPORT at:#{time}:\n#{report}\n")
87
+ end
88
+ end
89
+
90
+ module_function :init_globals, :handle_program_termination, :monitor_general_process_vars
91
+ end
@@ -1,3 +1,3 @@
1
1
  module ContentServer
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -1,17 +1,2 @@
1
- require 'content_server/content_server'
2
- require 'content_server/backup_server'
3
-
4
1
  module ContentServer
5
- # Flags combined for content and backup server.
6
- Params.path('local_content_data_path', '', 'ContentData file path.')
7
-
8
- # Monitoring
9
- Params.boolean('enable_monitoring', false, 'Whether to enable process monitoring or not.')
10
- Params.integer('process_vars_delay', 3, 'pulling time of variables')
11
-
12
- # Handling thread exceptions.
13
- Params.boolean('abort_on_exception', true, 'Any exception in any thread will abort the run.')
14
-
15
- Params.integer('data_flush_delay', 300, 'Number of seconds to delay content data file flush to disk.')
16
-
17
2
  end # module ContentServer