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.
- data/bin/backup_server +8 -20
- data/bin/content_server +8 -20
- data/bin/testing_memory +60 -0
- data/bin/testing_server +57 -0
- data/ext/run_in_background/mkrf_conf.rb +34 -0
- data/lib/content_data/content_data.rb +613 -0
- data/lib/content_data/version.rb +3 -0
- data/lib/content_data.rb +6 -0
- data/lib/content_server/backup_server.rb +65 -86
- data/lib/content_server/content_server.rb +47 -77
- data/lib/content_server/file_streamer.rb +27 -33
- data/lib/content_server/queue_copy.rb +154 -49
- data/lib/content_server/queue_indexer.rb +19 -11
- data/lib/content_server/remote_content.rb +41 -23
- data/lib/content_server/server.rb +91 -0
- data/lib/content_server/version.rb +1 -1
- data/lib/content_server.rb +0 -15
- data/lib/email/email.rb +87 -0
- data/lib/email/version.rb +3 -0
- data/lib/email.rb +4 -0
- data/lib/file_copy/copy.rb +68 -0
- data/lib/file_copy/version.rb +4 -0
- data/lib/file_copy.rb +4 -0
- data/lib/file_indexing/index_agent.rb +170 -0
- data/lib/file_indexing/indexer_patterns.rb +72 -0
- data/lib/file_indexing/version.rb +3 -0
- data/lib/file_indexing.rb +9 -0
- data/lib/file_monitoring/file_monitoring.rb +105 -0
- data/lib/file_monitoring/monitor_path.rb +304 -0
- data/lib/file_monitoring/version.rb +3 -0
- data/lib/file_monitoring.rb +29 -0
- data/lib/file_utils/file_generator/README +97 -0
- data/lib/file_utils/file_generator/file_generator.rb +156 -0
- data/lib/file_utils/file_utils.rb +260 -0
- data/lib/file_utils/version.rb +3 -0
- data/lib/file_utils.rb +4 -0
- data/lib/log/version.rb +3 -0
- data/lib/log.rb +188 -0
- data/lib/networking/tcp.rb +213 -0
- data/lib/networking/version.rb +3 -0
- data/lib/networking.rb +4 -0
- data/lib/params/version.rb +3 -0
- data/lib/params.rb +419 -0
- data/lib/process_monitoring/monitoring.rb +85 -0
- data/lib/process_monitoring/monitoring_info.rb +79 -0
- data/lib/process_monitoring/send_email.rb +40 -0
- data/lib/process_monitoring/thread_safe_hash.rb +77 -0
- data/lib/process_monitoring/version.rb +3 -0
- data/lib/process_monitoring.rb +6 -0
- data/lib/run_in_background/version.rb +3 -0
- data/lib/run_in_background.rb +432 -0
- data/lib/testing_memory/testing_memory.rb +187 -0
- data/lib/testing_server/testing_server.rb +236 -0
- data/lib/testing_server/version.rb +3 -0
- data/lib/testing_server.rb +12 -0
- data/lib/validations/index_validations.rb +106 -0
- data/lib/validations/version.rb +3 -0
- data/lib/validations.rb +4 -0
- data/spec/content_data/validations_spec.rb +113 -0
- data/spec/file_copy/copy_spec.rb +54 -0
- data/spec/file_indexing/index_agent_spec.rb +53 -0
- data/spec/networking/tcp_spec.rb +95 -0
- data/spec/validations/index_validations_spec.rb +77 -0
- data/test/content_data/content_data_test.rb +290 -0
- data/test/file_generator/file_generator_spec.rb +84 -0
- data/test/file_indexing/index_agent_test/New.txt +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/libexslt.dll +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/libxslt.dll +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/xsltproc.exe +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exslt.h +102 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exsltconfig.h +73 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exsltexports.h +140 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/libexslt.h +29 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/attributes.h +38 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/documents.h +93 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/extensions.h +262 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/extra.h +80 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/functions.h +78 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/imports.h +75 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/keys.h +53 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/libxslt.h +30 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/namespaces.h +68 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/numbersInternals.h +69 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/pattern.h +81 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/preproc.h +43 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/security.h +104 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/templates.h +77 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/transform.h +207 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/trio.h +216 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/triodef.h +220 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/variables.h +91 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/win32config.h +101 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xslt.h +103 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltInternals.h +1967 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltconfig.h +172 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltexports.h +142 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltlocale.h +57 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltutils.h +309 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltwin32config.h +105 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libexslt.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libexslt_a.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libxslt.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libxslt_a.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/readme.txt +22 -0
- data/test/file_indexing/index_agent_test/patterns.input +3 -0
- data/test/file_indexing/index_agent_test.rb +51 -0
- data/test/file_monitoring/file_monitoring_test/conf.yml +4 -0
- data/test/file_monitoring/file_monitoring_test/conf_win32.yml +5 -0
- data/test/file_monitoring/file_monitoring_test/log +56 -0
- data/test/file_monitoring/file_monitoring_test.rb +0 -0
- data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000 +1000 -0
- data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000.0 +1000 -0
- data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000.1 +1000 -0
- data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500 +1500 -0
- data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500.0 +1500 -0
- data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500.1 +1500 -0
- data/test/file_monitoring/monitor_path_test/test_file.500 +500 -0
- data/test/file_monitoring/monitor_path_test/test_file.500.0 +500 -0
- data/test/file_monitoring/monitor_path_test/test_file.500.1 +500 -0
- data/test/file_monitoring/monitor_path_test.rb +153 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500 +1500 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500.0 +1500 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500.1 +1500 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000 +1000 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000.0 +1000 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000.1 +1000 -0
- data/test/file_utils/fileutil_mksymlink_test/test_file.500 +500 -0
- data/test/file_utils/fileutil_mksymlink_test/test_file.500.0 +500 -0
- data/test/file_utils/fileutil_mksymlink_test/test_file.500.1 +500 -0
- data/test/file_utils/fileutil_mksymlink_test.rb +125 -0
- data/test/file_utils/time_modification_test.rb +132 -0
- data/test/params/params_spec.rb +280 -0
- data/test/params/params_test.rb +43 -0
- data/test/run_in_background/run_in_background_test.rb +122 -0
- data/test/run_in_background/test_app +57 -0
- metadata +272 -132
- 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/
|
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 == :
|
57
|
-
Log.debug1
|
58
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
137
|
-
|
138
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
198
|
-
|
199
|
-
|
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
|
-
|
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/
|
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
|
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 =
|
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.
|
36
|
+
Log.debug1 "Indexing file:'#{path}'."
|
34
37
|
checksum = calc_SHA1(path)
|
35
|
-
|
36
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
16
|
-
|
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
|
-
|
32
|
-
if
|
33
|
-
|
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
|
-
|
43
|
-
|
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
|
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
|
-
|
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
|
-
|
75
|
-
|
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
|
-
|
84
|
-
|
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
|
data/lib/content_server.rb
CHANGED
@@ -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
|