$self->{offset} = $offset || 0;
}
+sub update_cache
+{
+ my ($self) = @_;
+
+ $self->{dbh}->begin_work();
+
+ my $query = "
+ SELECT JobId from Job
+ WHERE JobId NOT IN (SELECT JobId FROM brestore_knownjobid) AND JobStatus IN ('T', 'f', 'A') ORDER BY JobId";
+ my $jobs = $self->dbh_selectall_arrayref($query);
+
+ $self->update_brestore_table(map { $_->[0] } @$jobs);
+
+ print STDERR "Cleaning path visibility\n";
+
+ my $nb = $self->dbh_do("
+ DELETE FROM brestore_pathvisibility
+ WHERE NOT EXISTS
+ (SELECT 1 FROM Job WHERE JobId=brestore_pathvisibility.JobId)");
+
+ print STDERR "$nb rows affected\n";
+ print STDERR "Cleaning known jobid\n";
+
+ $nb = $self->dbh_do("
+ DELETE FROM brestore_knownjobid
+ WHERE NOT EXISTS
+ (SELECT 1 FROM Job WHERE JobId=brestore_knownjobid.JobId)");
+
+ print STDERR "$nb rows affected\n";
+
+ $self->{dbh}->commit();
+}
+
+sub update_brestore_table
+{
+ my ($self, @jobs) = @_;
+
+ $self->debug(\@jobs);
+
+ foreach my $job (sort {$a <=> $b} @jobs)
+ {
+ my $query = "SELECT 1 FROM brestore_knownjobid WHERE JobId = $job";
+ my $retour = $self->dbh_selectrow_arrayref($query);
+ next if ($retour and ($retour->[0] == 1)); # We have allready done this one ...
+
+ print STDERR "Inserting path records for JobId $job\n";
+ $query = "INSERT INTO brestore_pathvisibility (PathId, JobId)
+ (SELECT DISTINCT PathId, JobId FROM File WHERE JobId = $job)";
+
+ $self->dbh_do($query);
+
+ # Now we have to do the directory recursion stuff to determine missing visibility
+ # We try to avoid recursion, to be as fast as possible
+ # We also only work on not allready hierarchised directories...
+
+ print STDERR "Creating missing recursion paths for $job\n";
+
+ $query = "SELECT brestore_pathvisibility.PathId, Path FROM brestore_pathvisibility
+ JOIN Path ON( brestore_pathvisibility.PathId = Path.PathId)
+ LEFT JOIN brestore_pathhierarchy ON (brestore_pathvisibility.PathId = brestore_pathhierarchy.PathId)
+ WHERE brestore_pathvisibility.JobId = $job
+ AND brestore_pathhierarchy.PathId IS NULL
+ ORDER BY Path";
+
+ my $sth = $self->dbh_prepare($query);
+ $sth->execute();
+ my $pathid; my $path;
+ $sth->bind_columns(\$pathid,\$path);
+
+ while ($sth->fetch)
+ {
+ $self->build_path_hierarchy($path,$pathid);
+ }
+ $sth->finish();
+
+ # Great. We have calculated all dependancies. We can use them to add the missing pathids ...
+ # This query gives all parent pathids for a given jobid that aren't stored.
+ # It has to be called until no record is updated ...
+ $query = "
+ INSERT INTO brestore_pathvisibility (PathId, JobId) (
+ SELECT a.PathId,$job
+ FROM
+ (SELECT DISTINCT h.PPathId AS PathId
+ FROM brestore_pathhierarchy AS h
+ JOIN brestore_pathvisibility AS p ON (h.PathId=p.PathId)
+ WHERE p.JobId=$job) AS a
+ LEFT JOIN
+ (SELECT PathId
+ FROM brestore_pathvisibility
+ WHERE JobId=$job) AS b
+ ON (a.PathId = b.PathId)
+ WHERE b.PathId IS NULL)";
+
+ my $rows_affected;
+ while (($rows_affected = $self->dbh_do($query)) and ($rows_affected !~ /^0/))
+ {
+ print STDERR "Recursively adding $rows_affected records from $job\n";
+ }
+ # Job's done
+ $query = "INSERT INTO brestore_knownjobid (JobId) VALUES ($job)";
+ $self->dbh_do($query);
+ }
+}
+
+sub parent_dir
+{
+ my ($path) = @_;
+ # Root Unix case :
+ if ($path eq '/')
+ {
+ return '';
+ }
+ # Root Windows case :
+ if ($path =~ /^[a-z]+:\/$/i)
+ {
+ return '';
+ }
+ # Split
+ my @tmp = split('/',$path);
+ # We remove the last ...
+ pop @tmp;
+ my $tmp = join ('/',@tmp) . '/';
+ return $tmp;
+}
+
+sub build_path_hierarchy
+{
+ my ($self, $path,$pathid)=@_;
+ # Does the ppathid exist for this ? we use a memory cache...
+ # In order to avoid the full loop, we consider that if a dir is allready in the
+ # brestore_pathhierarchy table, then there is no need to calculate all the hierarchy
+ while ($path ne '')
+ {
+ if (! $self->{cache_ppathid}->{$pathid})
+ {
+ my $query = "SELECT PPathId FROM brestore_pathhierarchy WHERE PathId = ?";
+ my $sth2 = $self->{dbh}->prepare_cached($query);
+ $sth2->execute($pathid);
+ # Do we have a result ?
+ if (my $refrow = $sth2->fetchrow_arrayref)
+ {
+ $self->{cache_ppathid}->{$pathid}=$refrow->[0];
+ $sth2->finish();
+ # This dir was in the db ...
+ # It means we can leave, the tree has allready been built for
+ # this dir
+ return 1;
+ } else {
+ $sth2->finish();
+ # We have to create the record ...
+ # What's the current p_path ?
+ my $ppath = parent_dir($path);
+ my $ppathid = $self->return_pathid_from_path($ppath);
+ $self->{cache_ppathid}->{$pathid}= $ppathid;
+
+ $query = "INSERT INTO brestore_pathhierarchy (pathid, ppathid) VALUES (?,?)";
+ $sth2 = $self->{dbh}->prepare_cached($query);
+ $sth2->execute($pathid,$ppathid);
+ $sth2->finish();
+ $path = $ppath;
+ $pathid = $ppathid;
+ }
+ } else {
+ # It's allready in the cache.
+ # We can leave, no time to waste here, all the parent dirs have allready
+ # been done
+ return 1;
+ }
+ }
+ return 1;
+}
+
+sub return_pathid_from_path
+{
+ my ($self, $path) = @_;
+ my $query = "SELECT PathId FROM Path WHERE Path = ?";
+
+ #print STDERR $query,"\n" if $debug;
+ my $sth = $self->{dbh}->prepare_cached($query);
+ $sth->execute($path);
+ my $result =$sth->fetchrow_arrayref();
+ $sth->finish();
+ if (defined $result)
+ {
+ return $result->[0];
+
+ } else {
+ # A bit dirty : we insert into path, and we have to be sure
+ # we aren't deleted by a purge. We still need to insert into path to get
+ # the pathid, because of mysql
+ $query = "INSERT INTO Path (Path) VALUES (?)";
+ #print STDERR $query,"\n" if $debug;
+ $sth = $self->{dbh}->prepare_cached($query);
+ $sth->execute($path);
+ $sth->finish();
+
+ $query = "SELECT PathId FROM Path WHERE Path = ?";
+ #print STDERR $query,"\n" if $debug;
+ $sth = $self->{dbh}->prepare_cached($query);
+ $sth->execute($path);
+ $result = $sth->fetchrow_arrayref();
+ $sth->finish();
+ return $result->[0];
+ }
+}
+
sub ls_files
{
my ($self) = @_;
return @CurrentJobIds;
}
+sub dbh_selectrow_arrayref
+{
+ my ($self, $query) = @_;
+ $self->debug($query, up => 1);
+ return $self->{dbh}->selectrow_arrayref($query);
+}
# Returns list of versions of a file that could be restored
# returns an array of
}
$bvfs->set_curjobids(@jobid);
+
+
$bvfs->set_limits($args->{limit}, $args->{offset});
print CGI::header('application/x-javascript');
print "]\n";
}
+if (CGI::param('init')) {
+ $bvfs->update_brestore_table(@jobid);
+}
+
my $pathid = CGI::param('node') || '';
my $path = CGI::param('path');
Ext.brestore.jobid=0;
Ext.brestore.client='';
+Ext.brestore.path='';
+Ext.brestore.root_path='';
+
+
+function get_node_path(node)
+{
+ var temp='';
+ for (var p = node; p; p = p.parentNode) {
+ if (p.parentNode) {
+ if (p.text == '/') {
+ temp = p.text + temp;
+ } else {
+ temp = p.text + '/' + temp;
+ }
+ }
+ }
+ return Ext.brestore.root_path + temp;
+}
+
function ext_init()
{
// set the root node
var root = new Ext.tree.AsyncTreeNode({
- text: 'Root',
+ text: 'Select a job',
draggable:false,
id:'source'
});
tree.render();
// root.expand();
- tree.on('click', function(e) {
+ tree.on('click', function(node, event) {
+ Ext.brestore.path = get_node_path(node);
+
file_store.removeAll();
file_store.load({params:{action: 'list_files',
jobid:Ext.brestore.jobid,
- node:e.id}
+ node:node.id}
});
return true;
});
id: 'name', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 })
header: 'File',
dataIndex: 'name',
- width: 250,
+ width: 100,
css: 'white-space:normal;'
},{
header: "Size",
},{
header: "Date",
dataIndex: 'mtime',
- width: 50
+ width: 100
},{
dataIndex: 'pathid',
hidden: true
return true;
});
+ // TODO: selection only when using dblclick
files_grid.selModel.on('rowselect', function(e,i,r) {
Ext.brestore.filename = r.json[3];
file_versions_store.load({params:{action: 'list_versions',
{name: 'fileid' },
{name: 'filenameid'},
{name: 'pathid' },
+ {name: 'name' },
{name: 'size', type: 'int' },
{name: 'mtime', type: 'date', dateFormat: 'Y-m-d h:i:s'}
]))
var file_selection_cm = new Ext.grid.ColumnModel([{
id: 'name', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 })
+ header: "Name",
dataIndex: 'name',
- hidden: true
+ width: 250
},{
header: "JobId",
+ width: 50,
dataIndex: 'jobid'
},{
header: "Size",
},{
header: "Date",
dataIndex: 'mtime',
- width: 50
+ width: 100
},{
dataIndex: 'pathid',
hidden: true
ddGroup : 'TreeDD',
copy:false,
notifyDrop : function(dd, e, data){
-// if (data.selections) {
-// alert("grid");
-// }
-//
-// if (data.node) {
-// alert("tree");
-// }
-//
- file_selection_store.add(
- new file_selection_record({
- jobid:1,
- fileid:1,
- filenameid:1,
- pathid:1,
- size:1,
- mtime:'2007-01-01 01:00:00'
- })
- );
-
- return true;
-// var sm=grid.getSelectionModel();
-// var rows=sm.getSelections();
-// var cindex=dd.getDragData(e).rowIndex;
-// for(i = 0; i < rows.length; i++) {
-// rowData=ds.getById(rows[i].id);
-// if(!this.copy)
-// ds.remove(ds.getById(rows[i].id));
-// ds.insert(cindex,rowData);
-// };
+ var r;
+ //TODO: gerer la multi-selection
+ if (data.selections) {
+ if (data.grid.id == 'div-files') {
+ for(var i=0;i<data.selections.length;i++) {
+ r = new file_selection_record({
+ jobid: Ext.brestore.jobid,
+ fileid: data.selections[i].json[0],
+ filenameid:data.selections[i].json[1],
+ pathid: data.selections[i].json[2],
+ name: Ext.brestore.path + data.selections[i].json[3],
+ size: data.selections[i].json[4],
+ mtime: data.selections[i].json[5]
+ });
+ file_selection_store.add(r)
+ }
+ }
+
+ if (data.grid.id == 'div-file-versions') {
+ r = new file_selection_record({
+ jobid: data.selections[0].json[3],
+ fileid: data.selections[0].json[0],
+ filenameid:data.selections[0].json[1],
+ pathid: data.selections[0].json[2],
+ name: Ext.brestore.path + Ext.brestore.filename,
+ size: data.selections[0].json[7],
+ mtime: data.selections[0].json[8]
+ });
+ file_selection_store.add(r)
+ }
+ }
+
+ if (data.node) {
+ var path= get_node_path(data.node);
+ r = new file_selection_record({
+ jobid: Ext.brestore.jobid,
+ fileid: 0,
+ filenameid:0,
+ pathid: data.node.id,
+ name: path,
+ size: 4096,
+ mtime: 0
+ });
+ file_selection_store.add(r)
+ }
+
+ return true;
+
+// var sm=grid.getSelectionModel();
+// var rows=sm.getSelections();
+// var cindex=dd.getDragData(e).rowIndex;
+// for(i = 0; i < rows.length; i++) {
+// rowData=ds.getById(rows[i].id);
+// if(!this.copy)
+// ds.remove(ds.getById(rows[i].id));
+// ds.insert(cindex,rowData);
+// };
}
});
},{
header: "InChanger",
dataIndex: 'inchanger',
+ width: 60,
renderer: rd_vol_is_online
},{
header: "Volume",
dataIndex: 'volume'
},{
header: "JobId",
+ width: 50,
dataIndex: 'jobid'
},{
header: "Size",
},{
header: "Date",
dataIndex: 'mtime',
- width: 50
+ width: 100
},{
header: "MD5",
dataIndex: 'md5',
- width: 50
+ width: 160
},{
dataIndex: 'pathid',
hidden: true
job_combo.on('select', function(e,c) {
// TODO: choose between date and jobid here (with a toolbar bp ?)
Ext.brestore.jobid = c.json[0];
+ Ext.brestore.root_path='';
root.setText("Root");
tree_loader.baseParams = { action:'list_dirs',
+ init:1,
jobid:Ext.brestore.jobid };
root.reload();
});
cls:'x-btn-text-icon',
handler: function() {
var where = where_field.getValue();
+ Ext.brestore.root_path=where;
root.setText(where);
tree_loader.baseParams = { action:'list_dirs',
jobid:Ext.brestore.jobid,
split: true, initialSize: 300
},
east: {
- split: true, initialSize: 500
+ split: true, initialSize: 550
},
west: {
split: true, initialSize: 300
},
center: {
- initialSize: 600
+ initialSize: 450
}
});