MDL-34290 update all references after the source is changed

- When several records in {files} have the same record in {files_reference} and the synchronisation is performed, we need to update
all records in {files} so all files know if source is changed and that sync was performed;
- also when local moodle file content is changed we immediately update all files referencing to it (therefore sync of references
to the local files is unnecessary);
This commit is contained in:
Marina Glancy 2012-07-31 09:02:13 +08:00
parent a3c94686aa
commit 14b7e50001
3 changed files with 103 additions and 28 deletions

View File

@ -804,10 +804,6 @@ function file_save_draft_area_files($draftitemid, $contextid, $component, $filea
continue;
}
// Replaced file content
if ($oldfile->get_contenthash() != $newfile->get_contenthash()) {
$oldfile->replace_content_with($newfile);
}
// Updated author
if ($oldfile->get_author() != $newfile->get_author()) {
$oldfile->set_author($newfile->get_author());
@ -827,16 +823,18 @@ function file_save_draft_area_files($draftitemid, $contextid, $component, $filea
$oldfile->set_sortorder($newfile->get_sortorder());
}
// Update file size
if ($oldfile->get_filesize() != $newfile->get_filesize()) {
$oldfile->set_filesize($newfile->get_filesize());
}
// Update file timemodified
if ($oldfile->get_timemodified() != $newfile->get_timemodified()) {
$oldfile->set_timemodified($newfile->get_timemodified());
}
// Replaced file content
if ($oldfile->get_contenthash() != $newfile->get_contenthash() || $oldfile->get_filesize() != $newfile->get_filesize()) {
$oldfile->replace_content_with($newfile);
// push changes to all local files that are referencing this file
$fs->update_references_to_storedfile($this);
}
// unchanged file or directory - we keep it as is
unset($newhashes[$oldhash]);
if (!$oldfile->is_directory()) {

View File

@ -1805,6 +1805,39 @@ class file_storage {
return $this->search_references_count(self::pack_reference($params));
}
/**
* Updates all files that are referencing this file with the new contenthash
* and filesize
*
* @param stored_file $storedfile
*/
public function update_references_to_storedfile(stored_file $storedfile) {
global $CFG;
$params = array();
$params['contextid'] = $storedfile->get_contextid();
$params['component'] = $storedfile->get_component();
$params['filearea'] = $storedfile->get_filearea();
$params['itemid'] = $storedfile->get_itemid();
$params['filename'] = $storedfile->get_filename();
$params['filepath'] = $storedfile->get_filepath();
$reference = self::pack_reference($params);
$referencehash = sha1($reference);
$sql = "SELECT repositoryid, id FROM {files_reference}
WHERE referencehash = ? and reference = ?";
$rs = $DB->get_recordset_sql($sql, array($referencehash, $reference));
$now = time();
foreach ($rs as $record) {
require_once($CFG->dirroot.'/repository/lib.php');
$repo = repository::get_instance($record->repositoryid);
$lifetime = $repo->get_reference_file_lifetime($reference);
$this->update_references($record->id, $now, $lifetime,
$storedfile->get_contenthash(), $storedfile->get_filesize(), 0);
}
$rs->close();
}
/**
* Convert file alias to local file
*
@ -1997,4 +2030,40 @@ class file_storage {
return $DB->get_field('files_reference', 'id',
array('repositoryid' => $repositoryid, 'referencehash' => sha1($reference)), $strictness);
}
/**
* Updates a reference to the external resource and all files that use it
*
* This function is called after synchronisation of an external file and updates the
* contenthash, filesize and status of all files that reference this external file
* as well as time last synchronised and sync lifetime (how long we don't need to call
* synchronisation for this reference).
*
* @param int $referencefileid
* @param int $lastsync
* @param int $lifetime
* @param string $contenthash
* @param int $filesize
* @param int $status 0 if ok or 666 if source is missing
*/
public function update_references($referencefileid, $lastsync, $lifetime, $contenthash, $filesize, $status) {
global $DB;
$referencefileid = clean_param($referencefileid, PARAM_INT);
$lastsync = clean_param($lastsync, PARAM_INT);
$lifetime = clean_param($lifetime, PARAM_INT);
validate_param($contenthash, PARAM_TEXT, NULL_NOT_ALLOWED);
$filesize = clean_param($filesize, PARAM_INT);
$status = clean_param($status, PARAM_INT);
$params = array('contenthash' => $contenthash,
'filesize' => $filesize,
'status' => $status,
'referencefileid' => $referencefileid,
'lastsync' => $lastsync,
'lifetime' => $lifetime);
$DB->execute('UPDATE {files} SET contenthash = :contenthash, filesize = :filesize,
status = :status, referencelastsync = :lastsync, referencelifetime = :lifetime
WHERE referencefileid = :referencefileid', $params);
$data = array('id' => $referencefileid, 'lastsync' => $lastsync, 'lifetime' => $lifetime);
$DB->update_record('files_reference', (object)$data);
}
}

View File

@ -195,6 +195,7 @@ class stored_file {
public function replace_content_with(stored_file $storedfile) {
$contenthash = $storedfile->get_contenthash();
$this->set_contenthash($contenthash);
$this->set_filesize($storedfile->get_filesize());
}
/**
@ -877,36 +878,43 @@ class stored_file {
* We update contenthash, filesize and status in files table if changed
* and we always update lastsync in files_reference table
*
* @param type $contenthash
* @param type $filesize
* @param string $contenthash
* @param int $filesize
* @param int $status
* @param int $lifetime the life time of this synchronisation results
*/
public function set_synchronized($contenthash, $filesize, $status = 0) {
public function set_synchronized($contenthash, $filesize, $status = 0, $lifetime = null) {
global $DB;
if (!$this->is_external_file()) {
return;
}
$now = time();
$filerecord = new stdClass();
if ($this->get_contenthash() !== $contenthash) {
$filerecord->contenthash = $contenthash;
if ($contenthash != $this->file_record->contenthash) {
$oldcontenthash = $this->file_record->contenthash;
}
if ($this->get_filesize() != $filesize) {
$filerecord->filesize = $filesize;
if ($lifetime === null) {
$lifetime = $this->file_record->referencelifetime;
}
if ($this->get_status() != $status) {
$filerecord->status = $status;
// this will update all entries in {files} that have the same filereference id
$this->fs->update_references($this->file_record->referencefileid, $now, $lifetime, $contenthash, $filesize, $status);
// we don't need to call update() for this object, just set the values of changed fields
$this->file_record->contenthash = $contenthash;
$this->file_record->filesize = $filesize;
$this->file_record->status = $status;
$this->file_record->referencelastsync = $now;
$this->file_record->referencelifetime = $lifetime;
if (isset($oldcontenthash)) {
$this->fs->deleted_file_cleanup($oldcontenthash);
}
$filerecord->referencelastsync = $now; // TODO MDL-33416 remove this
if (!empty($filerecord)) {
$this->update($filerecord);
}
$DB->set_field('files_reference', 'lastsync', $now, array('id'=>$this->get_referencefileid()));
// $this->file_record->lastsync = $now; // TODO MDL-33416 uncomment or remove
}
public function set_missingsource() {
$this->set_synchronized($this->get_contenthash(), 0, 666);
/**
* Sets the error status for a file that could not be synchronised
*
* @param int $lifetime the life time of this synchronisation results
*/
public function set_missingsource($lifetime = null) {
$this->set_synchronized($this->get_contenthash(), $this->get_filesize(), 666, $lifetime);
}
/**