Thread Ordnerstruktur in DB abbilden - evt. eigene DB (File) schreiben? (34 answers)
Opened by lousek at 2011-02-24 00:10

topeg
 2011-03-02 00:18
#146169 #146169
User since
2006-07-10
2611 Artikel
BenutzerIn

user image
Ich habe mir das Ganze mal gründlich angeschaut und mir ist dabei ein logischer Fehler bei deiner Herangehensweise aufgefallen, wenn du das Dateisystem durchsuchst.
Wenn ich den Code richtig lese, setzt du Auch Verzeichnisse in der DB obwohl du nur die Dateien haben willst, weiterhin löscht du ganze Bäume weil ein Ordner-Pfad bisher stimmt.
Beispiel:
Verzeichnisstruktur gegeben:
Code: (dl )
1
2
3
4
5
6
data/
test1/
bla1
bla2
bla3/
usw

"tree" aus der DB:
Code: (dl )
1
2
3
4
5
6
7
8
9
{
data => {
test1 => {
bla1 => 'X',
bla2 => 'X',
bla3 => {},
}
}
}

Wenn du nun unten Anfängst zu testen so wird gleich "data" gelöscht, da es ja im 'tree' vorkommt. Die restlichen Prüfungen sind nicht mehr Aussagekräftig und erzeugen einen "tree" dessen Enden "undef" sind (auch für leere Verzeichnisse).
Ein Lösung wäre "am Ende" von Dateisystem anzufangen und dich zur Wurzel vor zuarbeiten.
Oder Du erzeugst auch für das Dateisystem ein Baum, und Vergleichst den mit dem der aus der DB generiert wurde. Das wäre auch der weg den ich gehen würde.

Dein Script mal dahingehend überarbeitet, aber noch nicht getestet. Es können noch Fehler enthalten sein:
more (36.6kb):
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#!/usr/bin/perl

use strict;
use warnings;
use DBI;
use File::Find;
use Data::Dumper;

# Connect to DB
my $dbh = connect_db("ofrs","localhost","ofrs","ofrs");

# Set time before import
my $stime = time;

# Sync a replication folder on the disk with the database
checkFS($dbh,"/data/test1");

# Set time after import
my $etime = time;
my $endtime = ($etime - $stime);

# Print needed time
print "Needed $endtime seconds ...\n";
$dbh->disconnect();

########################################################################

sub connect_db
{
  my ($db,$host,$user,$pass)=@_;
  return DBI->connect(
                        "DBI:mysql:$db:$host",
                        $user,
                        $pass,
                        { RaiseError => 1, AutoCommit => 0 }
                      ) or die($DBI::errstr);
}

# sync a replication folder on the disk with the database
# Syntax: checkFS($repPath)
# Return value: none
sub checkFS
{
  # Set & define variables
  my ($dbh, $base_path) = @_;

  # create the hash-tree for this path / replication folder
  my $fs_tree = makeFSTree($base_path);

  # insert missing files in the DB
  syncDBwithFS($dbh,$fs_tree,$base_path);

  # Create Tree from the DB
  my $db_tree = makeDBTree($dbh, $base_path);

  # compare FS and DB Trees
  my $diff_tree=compareTrees($db_tree,$fs_tree);

  # build the pathes from the hashes left in the hash-tree
  my $onlyDB = buildPathes($diff_tree);

  # print the pathes out
  print "OnlyDB-Pathes:\n";
  print Dumper($onlyDB);
}

# Creates a hash tree for a replication folder using the pathes in the database
# Syntax: makeDBTree($dbh, $repFolder)
# Return Value: hash-tree (hash)
sub makeDBTree
{
  # Set & define the variables
  my ($dbh,$base_path)=@_;
  my $tree={};

  # Run query
  my $sth = $dbh->prepare('SELECT path FROM dir WHERE path LIKE "?"');
  $sth->execute($base_path.'%');

  # Use the query results ...
  while (my @result = $sth->fetchrow_array)
  {
    # ... and add each path to the hash-tree
    addToTree($tree, $result[0], 'X');
  }

  $sth->finish();

  # return the hash-tree
  return $tree;
}

# Syntax: makeFSTree($repFolder)
# Return Value: hash-tree (hash)
sub makeFSTree
{
  my $tree={};

  find(sub{
      return if($_=~/^\.{1,2}$/);
      my $path=$File::Find::name;
      my $end='X';
      $end={} if(-d $path);
      addToTree($tree, $path, $end);
    }, @_);

  return $tree;
}

# insert missing files in the DB
# Syntax: syncDBwithFS($dbh,$tree,$repFolder)
# Return Value: none
sub syncDBwithFS
{
  my ($dbh,$fs_tree,$base_path)=@_;
  my $sth=$dbh->prepare('INSERT IGNORE INTO dir (path) VALUES ("?")');
  __syncDBwithFS($sth,$fs_tree,$base_path);
  $sth->finish();
}

# private ...
sub __syncDBwithFS
{
  my ($sth,$fs_tree,$base_path)=@_;
  while(my ($key,$val)=each(%$fs_tree))
  {
    my $path="$base_path/$key";
    if($val && ref($val) eq 'HASH')
    { __syncDBwithFS($sth,$val,$path); }
    else
    { $sth->execute($path); }
  }
}

# add a Path to the hash-tree
# Syntax: addToTree($tree,$path)
# Return value: none
sub addToTree {
  # Set & define the variables
  my ($tree,$path,$end) = @_;

  # Split the path up to its parts
  my @parts = split('/',$path);

  # Delete the first (empty) part
  shift @parts;

  # Delete the trailing slash at the end of the path if exists
  my $file=1;
  unless($parts[-1])
  {
    $file=0;
    pop(@parts);
  }

  # build the hash-tree for this path
  my $ref=\$tree;
  $ref=\$$ref->{$_} for(@parts);

  $$ref=$end;
}

# compare two trees
# returns a tree of missing elemnts in second tree
# Syntax: addToTree($tree,$tree)
# Return value: $tree
sub compareTrees
{
  my ($tree_a,$tree_b)=@_;
  my $tree_diff={};

  while(my ($key,$val)=each(%$tree_a))
  {
    if(exists($tree_b->{$key}))
    {
      if(ref($tree_b->{$key}) eq 'HASH')
      {
        my $ret=compareTrees($val,$tree_b->{$key});
        $tree_diff->{$key}=$ret if($ret && keys(%$ret));
      }
    }
    else
    { $tree_diff->{$key}=$val; }
  }

  return $tree_diff;
}

# build the pathes from the hash-tree
# Syntax: buildPathes($tree)
# Return value: path-list (array-reference)
sub buildPathes
{
  # Set & define variables
  my $tree=shift;
  my $path=shift // '';
  my @list;

  # walk through all levels and sort them
  for my $name (sort(keys(%$tree)))
  {
    my $elm=$tree->{$name};

    if($elm && ref($elm) eq 'HASH')
    {
      # run the function recursive
      my $lst=buildPathes($elm,"$path/$name");
      push(@list,@$lst);
    }
    else
    { push(@list,"$path/$name"); }
  }

  # return the list of pathes from the hash-tree
  return \@list;
}

View full thread Ordnerstruktur in DB abbilden - evt. eigene DB (File) schreiben?