1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2016 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18#ifndef LIBCOUCHSTORE_FILE_OPS_H
19#define LIBCOUCHSTORE_FILE_OPS_H
20
21#include <stdint.h>
22#include <sys/types.h>
23
24#include <platform/platform.h>
25
26#include "couch_common.h"
27
28    /**
29     * Abstract file handle. Implementations can use it for anything
30     * they want, whether a pointer to an allocated data structure, or
31     * an integer such as a Unix file descriptor.
32     */
33    typedef struct couch_file_handle_opaque* couch_file_handle;
34
35    typedef struct {
36#ifdef WIN32
37        DWORD error;
38#else
39        int error;
40#endif
41    } couchstore_error_info_t;
42
43
44
45#ifdef __cplusplus
46/**
47 * An abstract base class that defines the interface of the file
48 * I/O primitives used by CouchStore. Passed to couchstore_open_db_ex().
49 */
50class LIBCOUCHSTORE_API
51FileOpsInterface {
52public:
53    /**
54     * An interface to query statistical information about a specific file
55     * handle.
56     */
57    class FHStats {
58    public:
59        virtual ~FHStats() = default;
60
61        /**
62         * Return the number of read() calls performed on this file handle
63         * since it was created.
64         */
65        virtual size_t getReadCount() = 0;
66
67        /**
68         * Return the number of write() calls performed on this file handle
69         * since it was created.
70         */
71        virtual size_t getWriteCount() = 0;
72    };
73
74    /**
75     * Virtual destructor used for optional cleanup
76     */
77    virtual ~FileOpsInterface() {}
78
79    /**
80     * Initialize state (e.g. allocate memory) for a file handle
81     * before opening a file.  This method is optional and
82     * doesn't need to do anything at all; it can just return NULL
83     * if there isn't anything to do.
84     *
85     * Note: No error checking is done on the result of this call
86     * so any failure should be handled accordingly (e.g. error
87     * when calling the `open` method).
88     */
89    virtual couch_file_handle constructor(couchstore_error_info_t* errinfo) = 0;
90
91    /**
92     * Open a file.
93     *
94     * @param on input, a pointer to the file handle that was
95     *        returned by the constructor function. The function
96     *        can change this value if it wants to; the value
97     *        stored here on return is the one that will be passed
98     *        to the other functions.
99     * @param path the name of the file
100     * @param flags flags as specified by UNIX open(2) system call
101     * @return COUCHSTORE_SUCCESS upon success.
102     */
103    virtual couchstore_error_t open(couchstore_error_info_t* errinfo,
104                                    couch_file_handle* handle, const char* path,
105                                    int oflag) = 0;
106
107    /**
108     * Close file associated with this handle.
109     *
110     * @param handle file handle to close
111     * @return COUCHSTORE_SUCCESS upon success, COUCHSTORE_ERROR_FILE_CLOSE if
112     *         there was an error.
113     */
114    virtual couchstore_error_t close(couchstore_error_info_t* errinfo,
115                                     couch_file_handle handle) = 0;
116
117    /**
118     * Specify that sync() should automatically be called after every N bytes
119     * of data written.
120     * Optional - defaults to COUCHSTORE_ERROR_NOT_SUPPORTED.
121     *
122     * @param handle file handle to set periodic sync for.
123     * @param period_bytes Perform a sync() call after the specified number of
124     *        bytes have been written. Specify 0 to disabled automatic sync().
125     * @return COUCHSTORE_SUCCESS upon success, or
126     *         COUCHSTORE_ERROR_NOT_SUPPORTED if automatic syncing not supported.
127     */
128    virtual couchstore_error_t set_periodic_sync(
129            couch_file_handle handle,
130            uint64_t period_bytes) {
131        return COUCHSTORE_ERROR_NOT_SUPPORTED;
132    }
133
134    /**
135     * Read a chunk of data from a given offset in the file.
136     *
137     * @param handle file handle to read from
138     * @param buf where to store data
139     * @param nbyte number of bytes to read
140     * @param offset where to read from
141     * @return number of bytes read (which may be less than nbytes),
142     *         or a value <= 0 if an error occurred
143     */
144    virtual ssize_t pread(couchstore_error_info_t* errinfo,
145                          couch_file_handle handle, void* buf, size_t nbytes,
146                          cs_off_t offset) = 0;
147
148    /**
149     * Write a chunk of data to a given offset in the file.
150     *
151     * @param handle file handle to write to
152     * @param buf where to read data
153     * @param nbyte number of bytes to write
154     * @param offset where to write to
155     * @return number of bytes written (which may be less than nbytes),
156     *         or a value <= 0 if an error occurred
157     */
158    virtual ssize_t pwrite(couchstore_error_info_t* errinfo,
159                           couch_file_handle handle, const void* buf,
160                           size_t nbytes, cs_off_t offset) = 0;
161
162    /**
163     * Find the end of the file.
164     *
165     * @param handle file handle to find the offset for
166     * @return the offset (from beginning of the file), or -1 if
167     *         the operation failed
168     */
169    virtual cs_off_t goto_eof(couchstore_error_info_t* errinfo,
170                              couch_file_handle handle) = 0;
171
172    /**
173     * Flush the buffers to disk
174     *
175     * @param handle file handle to flush
176     * @return COUCHSTORE_SUCCESS upon success
177     */
178    virtual couchstore_error_t sync(couchstore_error_info_t* errinfo,
179                                    couch_file_handle handle) = 0;
180
181    /**
182     * Give filesystem caching advice.
183     * @param handle file handle to give advice on
184     * @param offset offset to start at
185     * @param len length of range to advise on
186     * @param advice the advice type, see couchstore_file_advice_t
187     *        in couch_common.h
188     */
189    virtual couchstore_error_t advise(couchstore_error_info_t* errinfo,
190                                      couch_file_handle handle, cs_off_t offset,
191                                      cs_off_t len,
192                                      couchstore_file_advice_t advice) = 0;
193
194    /**
195     * Inform the file handlers the type of subsequent accesses.
196     */
197    virtual void tag(couch_file_handle handle, FileTag tag) {
198    }
199
200    /**
201     * Request stats associated with this file handle.
202     * Optional; subclasses may not support per-fileHandle stats; in which case
203     * nullptr is returned.
204     */
205    virtual FHStats* get_stats(couch_file_handle handle) {
206        return nullptr;
207    }
208
209    /**
210     * Called as part of shutting down the db instance this instance was
211     * passed to. A hook to for releasing allocated resources
212     *
213     * @param handle file handle to be released
214     */
215    virtual void destructor(couch_file_handle handle) = 0;
216};
217
218class ScopedFileTag {
219public:
220    ScopedFileTag(FileOpsInterface* ops, couch_file_handle handle, FileTag tag)
221        : ops(ops), handle(handle) {
222        ops->tag(handle, tag);
223    }
224
225    ~ScopedFileTag() {
226        ops->tag(handle, FileTag::Unknown);
227    }
228
229private:
230    FileOpsInterface* ops;
231    couch_file_handle handle;
232};
233
234#else
235    /**
236     * Opaque reference to a FileOpsInterface instance
237     */
238    typedef struct couch_file_ops_opaque* FileOpsInterface;
239
240#endif
241
242#endif
243