1 /***************************************************************************
2  *  lib/io/fileperblock_file.cpp
3  *
4  *  Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  *  Copyright (C) 2008, 2009 Johannes Singler <singler@ira.uka.de>
7  *  Copyright (C) 2008 Andreas Beckmann <beckmann@cs.uni-frankfurt.de>
8  *
9  *  Distributed under the Boost Software License, Version 1.0.
10  *  (See accompanying file LICENSE_1_0.txt or copy at
11  *  http://www.boost.org/LICENSE_1_0.txt)
12  **************************************************************************/
13 
14 #include <cassert>
15 #include <cstdio>
16 #include <iomanip>
17 #include <sstream>
18 #include <string>
19 
20 #include <stxxl/bits/common/aligned_alloc.h>
21 #include <stxxl/bits/common/counting_ptr.h>
22 #include <stxxl/bits/common/error_handling.h>
23 #include <stxxl/bits/common/exceptions.h>
24 #include <stxxl/bits/config.h>
25 #include <stxxl/bits/io/boostfd_file.h>
26 #include <stxxl/bits/io/completion_handler.h>
27 #include <stxxl/bits/io/disk_queued_file.h>
28 #include <stxxl/bits/io/file.h>
29 #include <stxxl/bits/io/fileperblock_file.h>
30 #include <stxxl/bits/io/mmap_file.h>
31 #include <stxxl/bits/io/boostfd_file.h>
32 #include <stxxl/bits/io/wincall_file.h>
33 #include <stxxl/bits/io/request.h>
34 #include <stxxl/bits/io/serving_request.h>
35 #include <stxxl/bits/io/syscall_file.h>
36 #include <stxxl/bits/io/wincall_file.h>
37 #include <stxxl/bits/namespace.h>
38 #include <stxxl/bits/unused.h>
39 #include <stxxl/bits/verbose.h>
40 #include "ufs_platform.h"
41 
42 STXXL_BEGIN_NAMESPACE
43 
44 template <class base_file_type>
fileperblock_file(const std::string & filename_prefix,int mode,int queue_id,int allocator_id,unsigned int device_id)45 fileperblock_file<base_file_type>::fileperblock_file(
46     const std::string& filename_prefix,
47     int mode,
48     int queue_id,
49     int allocator_id,
50     unsigned int device_id)
51     : file(device_id),
52       disk_queued_file(queue_id, allocator_id),
53       filename_prefix(filename_prefix),
54       mode(mode),
55       current_size(0),
56       lock_file_created(false),
57       lock_file(filename_prefix + "_fpb_lock", mode, queue_id)
58 { }
59 
60 template <class base_file_type>
~fileperblock_file()61 fileperblock_file<base_file_type>::~fileperblock_file()
62 {
63     if (lock_file_created)
64     {
65         if (::remove((filename_prefix + "_fpb_lock").c_str()) != 0)
66             STXXL_ERRMSG("remove() error on path=" << filename_prefix << "_fpb_lock error=" << strerror(errno));
67     }
68 }
69 
70 template <class base_file_type>
filename_for_block(offset_type offset)71 std::string fileperblock_file<base_file_type>::filename_for_block(offset_type offset)
72 {
73     std::ostringstream name;
74     //enough for 1 billion blocks
75     name << filename_prefix << "_fpb_" << std::setw(20) << std::setfill('0') << offset;
76     return name.str();
77 }
78 
79 template <class base_file_type>
serve(void * buffer,offset_type offset,size_type bytes,request::request_type type)80 void fileperblock_file<base_file_type>::serve(void* buffer, offset_type offset,
81                                               size_type bytes, request::request_type type)
82 {
83     base_file_type base_file(filename_for_block(offset), mode, get_queue_id());
84     base_file.set_size(bytes);
85     base_file.serve(buffer, 0, bytes, type);
86 }
87 
88 template <class base_file_type>
lock()89 void fileperblock_file<base_file_type>::lock()
90 {
91     if (!lock_file_created)
92     {
93         //create lock file and fill it with one page, an empty file cannot be locked
94         const int page_size = STXXL_BLOCK_ALIGN;
95         void* one_page = aligned_alloc<STXXL_BLOCK_ALIGN>(page_size);
96 #if STXXL_WITH_VALGRIND
97         memset(one_page, 0, page_size);
98 #endif
99         lock_file.set_size(page_size);
100         request_ptr r = lock_file.awrite(one_page, 0, page_size);
101         r->wait();
102         aligned_dealloc<STXXL_BLOCK_ALIGN>(one_page);
103         lock_file_created = true;
104     }
105     lock_file.lock();
106 }
107 
108 template <class base_file_type>
discard(offset_type offset,offset_type length)109 void fileperblock_file<base_file_type>::discard(offset_type offset, offset_type length)
110 {
111     STXXL_UNUSED(length);
112 #ifdef STXXL_FILEPERBLOCK_NO_DELETE
113     if (::truncate(filename_for_block(offset).c_str(), 0) != 0)
114         STXXL_ERRMSG("truncate() error on path=" << filename_for_block(offset) << " error=" << strerror(errno));
115 #else
116     if (::remove(filename_for_block(offset).c_str()) != 0)
117         STXXL_ERRMSG("remove() error on path=" << filename_for_block(offset) << " error=" << strerror(errno));
118 #endif
119 
120     STXXL_VERBOSE2("discard " << offset << " + " << length);
121 }
122 
123 template <class base_file_type>
export_files(offset_type offset,offset_type length,std::string filename)124 void fileperblock_file<base_file_type>::export_files(offset_type offset, offset_type length, std::string filename)
125 {
126     std::string original(filename_for_block(offset));
127     filename.insert(0, original.substr(0, original.find_last_of("/") + 1));
128     if (::remove(filename.c_str()) != 0)
129         STXXL_ERRMSG("remove() error on path=" << filename << " error=" << strerror(errno));
130 
131     if (::rename(original.c_str(), filename.c_str()) != 0)
132         STXXL_ERRMSG("rename() error on path=" << filename << " to=" << original << " error=" << strerror(errno));
133 
134 #if !STXXL_WINDOWS
135     //TODO: implement on Windows
136     if (::truncate(filename.c_str(), length) != 0) {
137         STXXL_THROW_ERRNO(io_error, "Error doing truncate()");
138     }
139 #else
140     STXXL_UNUSED(length);
141 #endif
142 }
143 
144 template <class base_file_type>
io_type() const145 const char* fileperblock_file<base_file_type>::io_type() const
146 {
147     return "fileperblock";
148 }
149 
150 ////////////////////////////////////////////////////////////////////////////
151 
152 template class fileperblock_file<syscall_file>;
153 
154 #if STXXL_HAVE_MMAP_FILE
155 template class fileperblock_file<mmap_file>;
156 #endif
157 
158 #if STXXL_HAVE_WINCALL_FILE
159 template class fileperblock_file<wincall_file>;
160 #endif
161 
162 #if STXXL_HAVE_BOOSTFD_FILE
163 template class fileperblock_file<boostfd_file>;
164 #endif
165 
166 STXXL_END_NAMESPACE
167