Skip to content

Commit

Permalink
WIP: C API for views
Browse files Browse the repository at this point in the history
* Added C4Key, a wrapper around Collatable
* No more map & emit callbacks in C view API. Instead the client uses
  a doc enumerator and tells the indexer what's emitted. (No tests yet)
* Added options structs for enumeration APIs.
  • Loading branch information
snej committed Sep 17, 2015
1 parent 67d5cb9 commit f033035
Show file tree
Hide file tree
Showing 10 changed files with 620 additions and 109 deletions.
34 changes: 34 additions & 0 deletions C/c4.exp
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,37 @@ _c4doc_insertRevision
_c4doc_insertRevisionWithHistory
_c4doc_setType
_c4doc_save

_kC4DefaultAllDocsOptions
_kC4DefaultChangesOptions
_kC4DefaultQueryOptions

_c4key_new
_c4key_free
_c4Key_addNull
_c4key_addBool
_c4key_addNumber
_c4key_addString
_c4key_addMapKey
_c4key_beginArray
_c4key_endArray
_c4key_beginMap
_c4key_endMap

_c4view_open
_c4view_close
_c4view_eraseIndex
_c4view_delete
_c4view_getTotalRows
_c4view_getLastSequenceIndexed
_c4view_getLastSequenceChangedAt

_c4indexer_begin
_c4indexer_enumerateDocuments
_c4indexer_emit
_c4indexer_end

#_c4view_query
#_c4queryenum_next
#_c4queryenum_free
#_c4queryrow_free
80 changes: 41 additions & 39 deletions C/c4Database.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,8 @@
// Copyright © 2015 Couchbase. All rights reserved.
//

#include "slice.hh"
typedef forestdb::slice C4Slice;
typedef struct {
const void *buf;
size_t size;
} C4SliceResult;

#define kC4SliceNull forestdb::slice::null

#define C4_IMPL
#include "c4Impl.hh"
#include "c4Database.h"
#undef C4_IMPL

#include "Database.hh"
#include "Document.hh"
Expand All @@ -30,44 +20,36 @@ using namespace forestdb;


// Size of ForestDB buffer cache allocated for a database
#define kDBBufferCacheSize (8*1024*1024)
static const size_t kDBBufferCacheSize = (8*1024*1024);

// ForestDB Write-Ahead Log size (# of records)
#define kDBWALThreshold 1024
static const size_t kDBWALThreshold = 1024;

// How often ForestDB should check whether databases need auto-compaction
#define kAutoCompactInterval (5*60.0)
static const uint64_t kAutoCompactInterval = (5*60);


static void recordError(C4ErrorDomain domain, int code, C4Error* outError) {
void recordError(C4ErrorDomain domain, int code, C4Error* outError) {
if (outError) {
outError->domain = domain;
outError->code = code;
}
}

static void recordHTTPError(int httpStatus, C4Error* outError) {
void recordHTTPError(int httpStatus, C4Error* outError) {
recordError(HTTPDomain, httpStatus, outError);
}

static void recordError(error e, C4Error* outError) {
void recordError(error e, C4Error* outError) {
recordError(ForestDBDomain, e.status, outError);
}

static void recordUnknownException(C4Error* outError) {
void recordUnknownException(C4Error* outError) {
Warn("Unexpected C++ exception thrown from CBForest");
recordError(C4Domain, kC4ErrorInternalException, outError);
}


#define catchError(OUTERR) \
catch (error err) { \
recordError(err, OUTERR); \
} catch (...) { \
recordUnknownException(OUTERR); \
}


void c4slice_free(C4Slice slice) {
slice.free();
}
Expand Down Expand Up @@ -127,6 +109,11 @@ struct c4Database {
};


forestdb::Database* internal(C4Database *db) {
return db->_db;
}


C4Database* c4db_open(C4Slice path,
bool readOnly,
C4Error *outError)
Expand All @@ -138,7 +125,7 @@ C4Database* c4db_open(C4Slice path,
config.wal_flush_before_commit = true;
config.seqtree_opt = true;
config.compress_document_body = true;
config.compactor_sleep_duration = (uint64_t)kAutoCompactInterval;
config.compactor_sleep_duration = kAutoCompactInterval;

auto c4db = new c4Database;
try {
Expand Down Expand Up @@ -321,7 +308,7 @@ struct C4DocumentInternal : public C4Document {
} else {
// Doc body (rev tree) isn't available, but we know most things about the current rev:
selectedRev.revID = revID;
selectedRev.sequence = _versionedDoc.sequence();
selectedRev.sequence = sequence;
int revFlags = 0;
if (flags & kExists) {
revFlags |= kRevLeaf;
Expand All @@ -337,6 +324,7 @@ struct C4DocumentInternal : public C4Document {
void initRevID() {
_revIDBuf = _versionedDoc.revID().expanded();
revID = _revIDBuf;
sequence = _versionedDoc.sequence();
}

bool selectRevision(const Revision *rev, C4Error *outError =NULL) {
Expand Down Expand Up @@ -599,6 +587,17 @@ bool c4doc_save(C4Document *doc,
#pragma mark - DOC ENUMERATION:


const C4AllDocsOptions kC4DefaultAllDocsOptions = {
.inclusiveStart = true,
.inclusiveEnd = true,
.includeBodies = true
};

const C4ChangesOptions kC4DefaultChangesOptions = {
.includeBodies = true
};


struct C4DocEnumerator {
C4Database *_database;
DocEnumerator _e;
Expand Down Expand Up @@ -628,14 +627,16 @@ void c4enum_free(C4DocEnumerator *e) {

C4DocEnumerator* c4db_enumerateChanges(C4Database *database,
C4SequenceNumber since,
bool withBodies,
const C4ChangesOptions *c4options,
C4Error *outError)
{
try {
if (!c4options)
c4options = &kC4DefaultChangesOptions;
auto options = DocEnumerator::Options::kDefault;
options.inclusiveEnd = true;
options.includeDeleted = false;
if (!withBodies)
options.includeDeleted = c4options->includeDeleted;
if (!c4options->includeBodies)
options.contentOptions = KeyStore::kMetaOnly;
return new C4DocEnumerator(database, since+1, UINT64_MAX, options);
} catchError(outError);
Expand All @@ -646,18 +647,19 @@ C4DocEnumerator* c4db_enumerateChanges(C4Database *database,
C4DocEnumerator* c4db_enumerateAllDocs(C4Database *database,
C4Slice startDocID,
C4Slice endDocID,
bool descending,
bool inclusiveEnd,
unsigned skip,
bool withBodies,
const C4AllDocsOptions *c4options,
C4Error *outError)
{
try {
if (!c4options)
c4options = &kC4DefaultAllDocsOptions;
auto options = DocEnumerator::Options::kDefault;
options.skip = skip;
options.descending = descending;
options.inclusiveEnd = inclusiveEnd;
if (!withBodies)
options.skip = c4options->skip;
options.descending = c4options->descending;
options.inclusiveStart = c4options->inclusiveStart;
options.inclusiveEnd = c4options->inclusiveEnd;
options.includeDeleted = c4options->includeDeleted;
if (!c4options->includeBodies)
options.contentOptions = KeyStore::kMetaOnly;
return new C4DocEnumerator(database, startDocID, endDocID, options);
} catchError(outError);
Expand Down
57 changes: 37 additions & 20 deletions C/c4Database.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,10 @@ extern "C" {

/** Describes a version-controlled document. */
typedef struct {
C4DocumentFlags flags;
C4Slice docID;
C4Slice revID;
C4DocumentFlags flags; /**< Document flags */
C4Slice docID; /**< Document ID */
C4Slice revID; /**< RevID of current revision */
C4SequenceNumber sequence; /**< Sequence at which doc was last updated */

struct {
C4Slice revID;
Expand Down Expand Up @@ -171,7 +172,36 @@ extern "C" {

//////// DOCUMENT ENUMERATORS:


/** Options for enumerating over all documents. */
typedef struct {
bool descending; /**< If true, iteration goes by descending document IDs. */
bool inclusiveStart; /**< If false, iteration starts just _after_ the startDocID. */
bool inclusiveEnd; /**< If false, iteration stops just _before_ the endDocID. */
unsigned skip; /**< The number of initial results to skip. */
bool includeDeleted; /**< If true, include deleted documents. */
bool includeBodies; /**< If false, document bodies will not be preloaded, just the
metadata (docID, revID, sequence, flags.) This is faster if you
don't need to access the revision tree or revision bodies. You
can still access all the data of the document, but it will
trigger loading the document body from the database. */
} C4AllDocsOptions;

/** Default all-docs enumeration options. */
extern const C4AllDocsOptions kC4DefaultAllDocsOptions;


/** Options for enumerating over database changes. */
typedef struct {
bool includeDeleted; /**< If true, include deleted documents. */
bool includeBodies; /**< If false, document bodies will not be preloaded. See
C4AllDocsOptions.includeBodies for more details. */
} C4ChangesOptions;

/** Default change-enumeration options. */
extern const C4ChangesOptions kC4DefaultChangesOptions;


/** Opaque handle to a document enumerator. */
typedef struct C4DocEnumerator C4DocEnumerator;

Expand All @@ -182,15 +212,12 @@ extern "C" {
Caller is responsible for freeing the enumerator when finished with it.
@param database The database.
@param since The sequence number to start _after_. Pass 0 to start from the beginning.
@param withBodies If false, document bodies will not be preloaded, just the metadata
(docID, revID, sequence, flags.) This is faster if you don't need to access the
revision tree or revision bodies. You can still access all the data of the document,
but it will trigger loading the document body from the database.
@param options Enumeration options (NULL for defaults).
@param outError Error will be stored here on failure.
@return A new enumerator, or NULL on failure. */
C4DocEnumerator* c4db_enumerateChanges(C4Database *database,
C4SequenceNumber since,
bool withBodies,
const C4ChangesOptions *options,
C4Error *outError);

/** Creates an enumerator ordered by docID.
Expand All @@ -200,23 +227,13 @@ extern "C" {
@param database The database.
@param startDocID The document ID to begin at.
@param endDocID The document ID to end at.
@param descending If true, iteration goes by descending document ID. The startDocID must
be higher than the endDocID.
@param inclusiveEnd If false, iteration stops just _before_ the endDocID.
@param skip The number of initial results to skip.
@param withBodies If false, document bodies will not be preloaded, just the metadata
(docID, revID, sequence, flags.) This is faster if you don't need to access the
revision tree or revision bodies. You can still access all the data of the document,
but it will trigger loading the document body from the database.
@param options Enumeration options (NULL for defaults).
@param outError Error will be stored here on failure.
@return A new enumerator, or NULL on failure. */
C4DocEnumerator* c4db_enumerateAllDocs(C4Database *database,
C4Slice startDocID,
C4Slice endDocID,
bool descending,
bool inclusiveEnd,
unsigned skip,
bool withBodies,
const C4AllDocsOptions *options,
C4Error *outError);

/** Returns the next document from an enumerator, or NULL if there are no more.
Expand Down
49 changes: 49 additions & 0 deletions C/c4Impl.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// c4Impl.h
// CBForest
//
// Created by Jens Alfke on 9/15/15.
// Copyright © 2015 Couchbase. All rights reserved.
//

#ifndef c4Impl_h
#define c4Impl_h

#include "slice.hh"

typedef forestdb::slice C4Slice;

typedef struct {
const void *buf;
size_t size;
} C4SliceResult;

#define kC4SliceNull forestdb::slice::null


#define C4_IMPL
#include "c4Database.h"


#include "Error.hh"
#include "Database.hh"

using namespace forestdb;

Database* internal(C4Database*);


void recordError(C4ErrorDomain domain, int code, C4Error* outError);
void recordHTTPError(int httpStatus, C4Error* outError);
void recordError(error e, C4Error* outError);
void recordUnknownException(C4Error* outError);

#define catchError(OUTERR) \
catch (error err) { \
recordError(err, OUTERR); \
} catch (...) { \
recordUnknownException(OUTERR); \
}


#endif /* c4Impl_h */
Loading

0 comments on commit f033035

Please sign in to comment.