clear sparse flag on files that complete on windows

This commit is contained in:
Arvid Norberg 2010-01-09 18:40:05 +00:00
parent c1ea06f373
commit d498c129ab
9 changed files with 103 additions and 40 deletions

View File

@ -1,3 +1,4 @@
* clear sparse flag on files that complete on windows
* support retry-after header for web seeds
* replaced boost.filesystem with custom functions
* replaced dependency on boost.thread by asio's internal thread primitives

View File

@ -6257,6 +6257,7 @@ The interface looks like this::
virtual bool rename_file(int file, std::string const& new_name) = 0;
virtual bool release_files() = 0;
virtual bool delete_files() = 0;
virtual void finalize_file(int index) {}
virtual ~storage_interface() {}
// non virtual functions
@ -6482,6 +6483,21 @@ following members::
void release_memory();
};
finalize_file()
---------------
::
virtual void finalize_file(int index);
This function is called each time a file is completely downloaded. The
storage implementation can perform last operations on a file. The file will
not be opened for writing after this.
``index`` is the index of the file that completed.
On windows the default storage implementation clears the sparse file flag
on the specified file.
magnet links
============

View File

@ -93,6 +93,7 @@ namespace libtorrent
, abort_torrent
, update_settings
, read_and_hash
, finalize_file
};
action_t action;

View File

@ -210,6 +210,10 @@ namespace libtorrent
void close();
bool set_size(size_type size, error_code& ec);
// called when we're done writing to the file.
// On windows this will clear the sparse bit
void finalize();
int open_mode() const { return m_open_mode; }
// when opened in unbuffered mode, this is the

View File

@ -158,6 +158,8 @@ namespace libtorrent
// non-zero return value indicates an error
virtual bool delete_files() = 0;
virtual void finalize_file(int file) {}
disk_buffer_pool* disk_pool() { return m_disk_pool; }
session_settings const& settings() const { return *m_settings; }
@ -204,6 +206,8 @@ namespace libtorrent
boost::intrusive_ptr<torrent_info const> info() const { return m_info; }
void write_resume_data(entry& rd) const;
void async_finalize_file(int file);
void async_check_fastresume(lazy_entry const* resume_data
, boost::function<void(int, disk_io_job const&)> const& handler);
@ -325,6 +329,8 @@ namespace libtorrent
size_type physical_offset(int piece_index, int offset);
void finalize_file(int index);
// returns the number of pieces left in the
// file currently being checked
int skip_file() const;

View File

@ -1341,6 +1341,7 @@ namespace libtorrent
, fence_operation // abort_torrent
, 0 // update_settings
, read_operation // read_and_hash
, 0 // finalize_file
};
bool is_fence_operation(disk_io_job const& j)
@ -1672,6 +1673,14 @@ namespace libtorrent
#endif
break;
}
case disk_io_job::finalize_file:
{
#ifdef TORRENT_DISK_STATS
m_log << log_time() << " finalize_file " << j.piece << std::endl;
#endif
j.storage->finalize_file(j.piece);
break;
}
case disk_io_job::read:
{
if (test_error(j))

View File

@ -732,7 +732,8 @@ namespace libtorrent
}
// try to make the file sparse if supported
if (mode & file::sparse)
// only set this flag if the file is opened for writing
if ((mode & file::sparse) && (mode & rw_mask) != read_only)
{
DWORD temp;
::DeviceIoControl(m_file_handle, FSCTL_SET_SPARSE, 0, 0
@ -1451,6 +1452,19 @@ namespace libtorrent
return true;
}
void file::finalize()
{
#ifdef TORRENT_WINDOWS
// according to MSDN, clearing the sparse flag of a file only
// works on windows vista and later
DWORD temp;
FILE_SET_SPARSE_BUFFER b;
b.SetSparse = FALSE;
::DeviceIoControl(m_file_handle, FSCTL_SET_SPARSE, &b, sizeof(b)
, 0, 0, &temp, 0);
#endif
}
size_type file::get_size(error_code& ec) const
{
#ifdef TORRENT_WINDOWS

View File

@ -349,6 +349,7 @@ namespace libtorrent
m_save_path = complete(path);
}
void finalize_file(int file);
bool has_any_file();
bool rename_file(int index, std::string const& new_filename);
bool release_files();
@ -398,6 +399,9 @@ namespace libtorrent
boost::scoped_ptr<file_storage> m_mapped_files;
file_storage const& m_files;
// helper function to open a file in the file pool with the right mode
boost::shared_ptr<file> open_file(file_entry const& fe, int mode, error_code& ec) const;
std::vector<boost::uint8_t> m_file_priority;
std::string m_save_path;
// the file pool is typically stored in
@ -540,20 +544,13 @@ namespace libtorrent
if (ec || s.file_size > file_iter->size || file_iter->size == 0)
{
ec.clear();
int mode = file::read_write;
if (m_settings
&& (settings().disk_io_read_mode == session_settings::disable_os_cache
|| (settings().disk_io_read_mode == session_settings::disable_os_cache_for_aligned_files
&& ((file_iter->offset + file_iter->file_base) & (m_page_size-1)) == 0)))
mode |= file::no_buffer;
if (!m_allocate_files) mode |= file::sparse;
boost::shared_ptr<file> f = m_pool.open_file(this
, combine_path(m_save_path, file_iter->path), mode, ec);
if (ec) set_error(combine_path(m_save_path, file_iter->path), ec);
boost::shared_ptr<file> f = open_file(*file_iter, file::read_write, ec);
std::string path = combine_path(m_save_path, file_iter->path);
if (ec) set_error(path, ec);
else if (f)
{
f->set_size(file_iter->size, ec);
if (ec) set_error(combine_path(m_save_path, file_iter->path), ec);
if (ec) set_error(path, ec);
}
}
@ -566,6 +563,18 @@ namespace libtorrent
return false;
}
void storage::finalize_file(int index)
{
TORRENT_ASSERT(index >= 0 && index < m_files.num_files());
if (index < 0 || index >= m_files.num_files()) return;
error_code ec;
boost::shared_ptr<file> f = open_file(files().at(index), file::read_write, ec);
if (ec || !f) return;
f->finalize();
}
bool storage::has_any_file()
{
file_storage::iterator i = files().begin();
@ -696,19 +705,8 @@ namespace libtorrent
TORRENT_ASSERT(file_iter != files().end());
}
std::string path = combine_path(m_save_path, file_iter->path);
error_code ec;
int mode = file::read_only;
boost::shared_ptr<file> file_handle;
int cache_setting = m_settings ? settings().disk_io_write_mode : 0;
if (cache_setting == session_settings::disable_os_cache
|| (cache_setting == session_settings::disable_os_cache_for_aligned_files
&& ((file_iter->offset + file_iter->file_base) & (m_page_size-1)) == 0))
mode |= file::no_buffer;
if (!m_allocate_files) mode |= file::sparse;
file_handle = m_pool.open_file(const_cast<storage*>(this), path, mode, ec);
boost::shared_ptr<file> file_handle = open_file(*file_iter, file::read_only, ec);
if (!file_handle || ec) return slot;
size_type data_start = file_handle->sparse_end(file_offset);
@ -1044,13 +1042,10 @@ ret:
size_type file_offset = tor_off - file_iter->offset;
TORRENT_ASSERT(file_offset >= 0);
std::string p = combine_path(m_save_path, file_iter->path);
error_code ec;
// open the file read only to avoid re-opening
// it in case it's already opened in read-only mode
boost::shared_ptr<file> f = m_pool.open_file(
this, p, file::read_only, ec);
error_code ec;
boost::shared_ptr<file> f = open_file(*file_iter, file::read_only, ec);
size_type ret = 0;
if (f && !ec) ret = f->phys_offset(file_offset);
@ -1191,20 +1186,11 @@ ret:
continue;
}
std::string path = combine_path(m_save_path, file_iter->path);
error_code ec;
int mode = op.mode;
if (op.cache_setting == session_settings::disable_os_cache
|| (op.cache_setting == session_settings::disable_os_cache_for_aligned_files
&& ((file_iter->offset + file_iter->file_base) & (m_page_size-1)) == 0))
mode |= file::no_buffer;
if (!m_allocate_files) mode |= file::sparse;
file_handle = m_pool.open_file(this, path, mode, ec);
file_handle = open_file(*file_iter, op.mode, ec);
if (!file_handle || ec)
{
std::string path = combine_path(m_save_path, file_iter->path);
TORRENT_ASSERT(ec);
set_error(path, ec);
return -1;
@ -1310,6 +1296,18 @@ ret:
return readv(&b, slot, offset, 1);
}
boost::shared_ptr<file> storage::open_file(file_entry const& fe, int mode, error_code& ec) const
{
int cache_setting = m_settings ? settings().disk_io_write_mode : 0;
if (cache_setting == session_settings::disable_os_cache
|| (cache_setting == session_settings::disable_os_cache_for_aligned_files
&& ((fe.offset + fe.file_base) & (m_page_size-1)) == 0))
mode |= file::no_buffer;
if (!m_allocate_files) mode |= file::sparse;
return m_pool.open_file(const_cast<storage*>(this), combine_path(m_save_path, fe.path), mode, ec);
}
storage_interface* default_storage_constructor(file_storage const& fs
, file_storage const* mapped, std::string const& path, file_pool& fp)
{
@ -1426,10 +1424,23 @@ ret:
m_storage->m_disk_pool = &m_io_thread;
}
void piece_manager::finalize_file(int index)
{ m_storage->finalize_file(index); }
piece_manager::~piece_manager()
{
}
void piece_manager::async_finalize_file(int file)
{
disk_io_job j;
j.storage = this;
j.action = disk_io_job::finalize_file;
j.piece = file;
boost::function<void(int, disk_io_job const&)> empty;
m_io_thread.add_job(j, empty);
}
void piece_manager::async_save_resume_data(
boost::function<void(int, disk_io_job const&)> const& handler)
{

View File

@ -2003,6 +2003,7 @@ namespace libtorrent
if (m_file_progress[file_index] >= m_torrent_file->files().at(file_index).size)
{
filesystem().async_finalize_file(file_index);
if (m_ses.m_alerts.should_post<piece_finished_alert>())
{
// this file just completed, post alert