Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext
async_extents

Asynchronous extent enumeration after a preceding operation.

Description

In a sparsely allocated file, it can be useful to know which extents contain non-zero data. Note that this call is racy (i.e. the extents are enumerated one by one on some platforms, this means they may be out of date with respect to one another) when other threads or processes are concurrently calling zero() or write() - this is a host OS API limitation.

Synopsis
future<std::vector<std::pair<off_t, off_t> > > async_extents(future<> _precondition)
Parameters

Type

Concept

Name

Description

future<>

_precondition

The precondition to use.

Returns

A future<std::vector<std::pair<off_t, off_t>>>

Header

#include <boost/afio/v2/afio.hpp>

Race Guarantees

Operating system Race guarantees under a changing file system
FreeBSD, Linux, OS X Very racy, even individual extent offset and length can race. The following filters are applied before returning results: (i) Any extent whose end appears before its start is retried (ii) Sequences of contiguous extents are merged into single extents.
Windows Race free.

Complexity

Amortised O(1) to dispatch. Amortised O(M) to complete where M is the average number of extents in each file.

Exception Model

Propagates the exception of any input precondition with an errored state at the point of dispatch, and throws a std::invalid_argument if any inputs have values which could not possibly be correct. Note that error code returning functions may still throw exceptions e.g. failure to allocate memory.

Example
// Create a dispatcher
auto dispatcher = make_dispatcher().get();
// Schedule opening the log file for hole punching
auto logfilez(dispatcher->file(path_req("testdir/log", file_flags::create | file_flags::read_write)));
// Schedule opening the log file for atomic appending of log entries
auto logfilea(dispatcher->file(path_req("testdir/log", file_flags::create | file_flags::write | file_flags::append)));
// Retrieve any errors which occurred
logfilez.get();
logfilea.get();
// Initialise a random number generator
ranctx ctx;
raninit(&ctx, (u4) n);
while(!done)
{
  // Each log entry is 32 bytes in length
  union
  {
    char bytes[32];
    struct
    {
      uint64 id;      // The id of the writer
      uint64 r;       // A random number
      uint64 h1, h2;  // A hash of the previous two items
    };
  } buffer;
  buffer.id = n;
  buffer.r = ranval(&ctx);
  buffer.h1 = buffer.h2 = 1;
  SpookyHash::Hash128(buffer.bytes, 16, &buffer.h1, &buffer.h2);
  // Atomically append the log entry to the log file and wait for it
  // to complete, then fetch the new size of the log file.
  stat_t s = dispatcher->write(make_io_req(logfilea, buffer.bytes, 32, 0))->lstat();
  if(s.st_allocated > 8192 || s.st_size > 8192)
  {
    // Allocated space exceeds 8Kb. The actual file size reported may be
    // many times larger if the filing system supports hole punching.

    // Get the list of allocated extents
    std::vector<std::pair<off_t, off_t>> extents = dispatcher->extents(logfilez).get();
    // Filing system may not yet have allocated any storage ...
    if(!extents.empty())
    {
      if(extents.back().second > 1024)
        extents.back().second -= 1024;
      else
        extents.resize(extents.size() - 1);
      if(!extents.empty())
      {
        dispatcher->zero(logfilez, extents).get();
      }
    }
    else
      std::cout << "NOTE: extents() returns empty despite " << s.st_allocated << " bytes allocated (possibly delayed allocation)" << std::endl;
  }
}


PrevUpHomeNext