Class: FileMonitoring::DirStat

Inherits:
Object
  • Object
show all
Defined in:
lib/file_monitoring/monitor_path.rb

Overview

This class holds current state of directory and methods to control changes

Constant Summary collapse

@@log =
nil

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ DirStat

Initializes new directory monitoring object

Arguments:

  • path - Dir location



129
130
131
132
133
134
135
136
137
138
139
# File 'lib/file_monitoring/monitor_path.rb', line 129

def initialize(path)
  @path = path
  @dirs = {}
  @files = {}
  @non_utf8_paths = {}  # Hash: ["path" -> true|false]

  # indicates if path EXISTS in file system.
  #   If true, file will not be removed during removed_unmarked_paths phase.
  @marked = false

end

Instance Attribute Details

#markedObject

Returns the value of attribute marked.



115
116
117
# File 'lib/file_monitoring/monitor_path.rb', line 115

def marked
  @marked
end

#pathObject

Returns the value of attribute path.



115
116
117
# File 'lib/file_monitoring/monitor_path.rb', line 115

def path
  @path
end

Class Method Details

.set_log(log) ⇒ Object



119
120
121
# File 'lib/file_monitoring/monitor_path.rb', line 119

def self.set_log (log)
  @@log = log
end

Instance Method Details

#has_dir?(path) ⇒ Boolean

Checks that there is a sub-folder with a given path.

Returns:

  • (Boolean)


196
197
198
# File 'lib/file_monitoring/monitor_path.rb', line 196

def has_dir?(path)
  @dirs.has_key?(path)
end

#has_file?(path) ⇒ Boolean

Checks that there is a file with a given path.

Returns:

  • (Boolean)


201
202
203
# File 'lib/file_monitoring/monitor_path.rb', line 201

def has_file?(path)
  @files.has_key?(path)
end

#indexObject



360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# File 'lib/file_monitoring/monitor_path.rb', line 360

def index
  files_enum = @files.each_value
  index_counter = $indexed_file_count  # to check if files where actually indexed
  loop do
    file_stat = files_enum.next rescue break
    file_stat.index  # file index
  end
  GC.start if index_counter != $indexed_file_count  # GC only if files where indexed

  dirs_enum = @dirs.each_value
  loop do
    dir_stat = dirs_enum.next rescue break
    dir_stat.index  # dir recursive call
  end
end

#load_instance(sub_paths, sub_paths_index, size, modification_time) ⇒ Object

add instance while initializing tree using content data from file Parameters:

sub_paths - Array of sub paths of the instance which is added to tree
            Example:
              instance path = /dir1/dir2/file_name
                Sub path 1: /dir1
                Sub path 2: /dir1/dir2
                Sub path 3: /dir1/dir2/file_name
            sub paths would create DirStat objs or FileStat(FileStat create using last sub path).
sub_paths_index - the index indicates the next sub path to insert to the tree
                  the index will be raised at each recursive call down the tree
size - the instance size to insert to the tree
modification_time - the instance modification_time to insert to the tree


154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/file_monitoring/monitor_path.rb', line 154

def load_instance(sub_paths, sub_paths_index, size, modification_time)
  # initialize dirs and files. This will indicate that the current DirStat is not new.
  @dirs = {} unless @dirs
  @files = {} unless @files
  if sub_paths.size-1 == sub_paths_index
    # Add File case - index points to last entry - leaf case.
    file_stat = FileStat.new(sub_paths[sub_paths_index], FileStatEnum::STABLE, size, modification_time, true)
    add_file(file_stat)
  else
    # Add Dir to tree if not present. index points to new dir path.
    dir_stat = @dirs[sub_paths[sub_paths_index]]
    #create new dir if not exist
    unless dir_stat
      dir_stat = DirStat.new(sub_paths[sub_paths_index])
      add_dir(dir_stat)
    end
    # continue recursive call on tree with next sub path index
    dir_stat.load_instance(sub_paths, sub_paths_index+1, size, modification_time)
  end
end

#monitorObject

Recursively, read files and dirs from file system (using Glob) Handle new filesdirs. Change state for existing filesdirs Index stable files Remove non existing filesdirs is handled in method: remove_unmarked_paths



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'lib/file_monitoring/monitor_path.rb', line 267

def monitor

  # Algorithm:
  # assume that current dir is present
  # ls (glob) the dir path for child dirs and files
  # if child file is not already present, add it as new, mark it and handle its state
  # if file already present, mark it and handle its state.
  # if child dir is not already present, add it as new, mark it and propagates
  #    the recursive call
  # if child dir already present, mark it and handle its state
  # marked files will not be remove in next remove phase

  # ls (glob) the dir path for child dirs and files
  globed_paths_enum = Dir.glob(@path + "/*").to_enum
  loop do
    globed_path = globed_paths_enum.next rescue break

    # if symlink - skip
    next if File.symlink?(globed_path)

    # UTF-8 - keep only files with names in
    next if @non_utf8_paths[globed_path]
    check_utf_8_encoding_file = globed_path.clone
    unless check_utf_8_encoding_file.force_encoding("UTF-8").valid_encoding?
      Log.warning("Non UTF-8 file name '#{check_utf_8_encoding_file}', skipping.")
      @non_utf8_paths[globed_path]=true
      check_utf_8_encoding_file=nil
      next
    end

    # Get File \ Dir status
    globed_path_stat = File.lstat(globed_path) rescue next  # File or dir removed from OS file system
    if globed_path_stat.file?
      # File case
      child_stat = @files[globed_path]
      if child_stat
        # file child exists in Tree
        child_stat.marked = true
        if child_stat.changed?(globed_path_stat)
          # Update changed status
          child_stat.state = FileStatEnum::CHANGED
          child_stat.cycles = 0
          child_stat.size = globed_path_stat.size
          child_stat.modification_time = globed_path_stat.mtime.to_i
          @@log.info("CHANGED file: " + globed_path)
          @@log.outputters[0].flush if Params['log_flush_each_message']
          #Log.debug1("CHANGED file: #{globed_path}")
          # remove file with changed checksum. File will be added once indexed
          $local_content_data_lock.synchronize{
            $local_content_data.remove_instance(Params['local_server_name'], globed_path)
          }
        else
          # File status is the same
          if child_stat.state != FileStatEnum::STABLE
            child_stat.state = FileStatEnum::UNCHANGED
            child_stat.cycles += 1
            if child_stat.cycles >= ::FileMonitoring.stable_state
              child_stat.state = FileStatEnum::STABLE
              @@log.info("STABLE file: " + globed_path)
              @@log.outputters[0].flush if Params['log_flush_each_message']
            else
              @@log.info("UNCHANGED file: " + globed_path)
              @@log.outputters[0].flush if Params['log_flush_each_message']
            end
          end
        end
      else
        # new File child:
        child_stat = FileStat.new(globed_path, FileStatEnum::NEW,
                                  globed_path_stat.size, globed_path_stat.mtime.to_i)
        @@log.info("NEW file: " + globed_path)
        @@log.outputters[0].flush if Params['log_flush_each_message']
        child_stat.marked = true
        add_file(child_stat)
      end
    else
      # Dir
      child_stat = @dirs[globed_path]
      # Add Dir if not exists in Tree
      unless child_stat
        child_stat = DirStat.new(globed_path)
        add_dir(child_stat)
        @@log.info("NEW dir: " + globed_path)
        @@log.outputters[0].flush if Params['log_flush_each_message']
      end
      child_stat.marked = true
      #recursive call for dirs
      child_stat.monitor
    end
  end
  GC.start
end

#removed_unmarked_pathsObject

Recursively, remove non existing files and dirs in Tree



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/file_monitoring/monitor_path.rb', line 220

def removed_unmarked_paths
  #remove dirs
  dirs_enum = @dirs.each_value
  loop do
    dir_stat = dirs_enum.next rescue break
    if dir_stat.marked
      dir_stat.marked = false  # unset flag for next monitoring\index\remove phase
      #recursive call
      dir_stat.removed_unmarked_paths
    else
      # directory is not marked. Remove it, since it does not exist.
      #Log.debug1("Non Existing dir: %s", file_stat.path)
      @@log.info("NON_EXISTING dir: " + dir_stat.path)
      @@log.outputters[0].flush if Params['log_flush_each_message']
      # remove file with changed checksum
      $local_content_data_lock.synchronize{
        $local_content_data.remove_directory(dir_stat.path, Params['local_server_name'])
      }
      rm_dir(dir_stat)
    end
  end

  #remove files
  files_enum = @files.each_value
  loop do
    file_stat = files_enum.next rescue break
    if file_stat.marked
      file_stat.marked = false  # unset flag for next monitoring\index\remove phase
    else
      # file not marked meaning it is no longer exist. Remove.
      #Log.debug1("Non Existing file: %s", file_stat.path)
      @@log.info("NON_EXISTING file: " + file_stat.path)
      @@log.outputters[0].flush if Params['log_flush_each_message']
      # remove file with changed checksum
      $local_content_data_lock.synchronize{
        $local_content_data.remove_instance(Params['local_server_name'], file_stat.path)
      }
      rm_file(file_stat)
    end
  end
end

#to_s(indent = 0) ⇒ Object

Returns string which contains path and state of this directory as well as it’s structure.



206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/file_monitoring/monitor_path.rb', line 206

def to_s(indent = 0)
  indent_increment = 2
  child_indent = indent + indent_increment
  res = super
  @files.each_value do |file|
    res += "\n" + file.to_s(child_indent)
  end if @files
  @dirs.each_value do |dir|
    res += "\n" + dir.to_s(child_indent)
  end if @dirs
  res
end