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.
- 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
|