content_server 1.1.0 → 1.2.0

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