Kouhei Sutou
null+****@clear*****
Mon Oct 24 00:05:05 JST 2016
Kouhei Sutou 2016-10-24 00:05:05 +0900 (Mon, 24 Oct 2016) New Revision: 8dfc54b4c4a8275b43f7b1084c88acbdccb91164 https://github.com/pgroonga/pgroonga/commit/8dfc54b4c4a8275b43f7b1084c88acbdccb91164 Message: Support writing XLog for insert data It's a experimental feature. TODO: * Support writing XLog for index creation. * Support applying XLog. Added files: src/pgrn_xlog.c src/pgrn_xlog.h Modified files: Makefile sources.am src/pgrn_compatible.h src/pgrn_jsonb.c src/pgrn_jsonb.h src/pgrn_variables.c src/pgroonga.c Modified: Makefile (+10 -3) =================================================================== --- Makefile 2016-10-23 00:44:10 +0900 (fba31b6) +++ Makefile 2016-10-24 00:05:05 +0900 (41b2738) @@ -1,5 +1,9 @@ REQUIRED_GROONGA_VERSION = 5.1.2 GROONGA_PKG = "groonga >= $(REQUIRED_GROONGA_VERSION)" +PACKAGES = $(GROONGA_PKG) +ifdef HAVE_MSGPACK +PACKAGES += msgpack +endif MODULE_big = pgroonga include sources.am @@ -17,15 +21,18 @@ DATA = \ $(shell echo pgroonga--*--*.sql) endif -PG_CPPFLAGS = $(shell pkg-config --cflags $(GROONGA_PKG)) -SHLIB_LINK = $(shell pkg-config --libs $(GROONGA_PKG)) -lm +PG_CPPFLAGS = $(shell pkg-config --cflags $(PACKAGES)) +SHLIB_LINK = $(shell pkg-config --libs $(PACKAGES)) -lm REGRESS = $(shell find sql -name '*.sql' | sed -e 's,\(^sql/\|\.sql$$\),,g') REGRESS_OPTS = --load-extension=pgroonga COPT += -Ivendor/xxHash +ifdef HAVE_MSGPACK +COPT += -DPGRN_HAVE_MSGPACK +endif ifdef DEBUG COPT += -O0 -g3 -DPGROONGA_DEBUG=1 -SHLIB_LINK += -Wl,--rpath=$(shell pkg-config --libs-only-L $(GROONGA_PKG) | sed -e 's/^-L//') +SHLIB_LINK += -Wl,--rpath=$(shell pkg-config --libs-only-L $(PACKAGES) | sed -e 's/^-L//') endif PG_CONFIG = pg_config Modified: sources.am (+1 -0) =================================================================== --- sources.am 2016-10-23 00:44:10 +0900 (820c22b) +++ sources.am 2016-10-24 00:05:05 +0900 (2105f3b) @@ -16,4 +16,5 @@ SRCS = \ src/pgrn_snippet_html.c \ src/pgrn_value.c \ src/pgrn_variables.c \ + src/pgrn_xlog.c \ vendor/xxHash/xxhash.c Modified: src/pgrn_compatible.h (+1 -1) =================================================================== --- src/pgrn_compatible.h 2016-10-23 00:44:10 +0900 (f806415) +++ src/pgrn_compatible.h 2016-10-24 00:05:05 +0900 (a89531a) @@ -20,7 +20,7 @@ # define PGRN_SUPPORT_CREATE_ACCESS_METHOD #endif -#if PG_VERSION_NUM >= 90600 +#if PG_VERSION_NUM >= 90600 && defined(PGRN_HAVE_MSGPACK) # define PGRN_SUPPORT_XLOG #endif Modified: src/pgrn_jsonb.c (+11 -1) =================================================================== --- src/pgrn_jsonb.c 2016-10-23 00:44:10 +0900 (ee32aa5) +++ src/pgrn_jsonb.c 2016-10-24 00:05:05 +0900 (51ad7d5) @@ -7,6 +7,7 @@ #include "pgrn_jsonb.h" #include "pgrn_options.h" #include "pgrn_value.h" +#include "pgrn_xlog.h" #include <catalog/pg_type.h> #include <utils/builtins.h> @@ -42,6 +43,7 @@ typedef struct PGrnJSONBInsertData grn_obj *sizeColumn; grn_obj *typeColumn; grn_obj *valueIDs; + PGrnXLogData *xlogData; grn_obj key; grn_obj components; grn_obj path; @@ -490,10 +492,14 @@ PGrnJSONBInsertValueSet(PGrnJSONBInsertData *data, GRN_BULK_REWIND(&(data->path)); PGrnJSONGenerateCompletePath(&(data->components), &(data->path)); if (GRN_TEXT_LEN(&(data->path)) < GRN_TABLE_MAX_KEY_SIZE) + { + /* TODO: XLog */ grn_obj_set_value(ctx, data->pathColumn, valueID, &(data->path), GRN_OBJ_SET); + } PGrnJSONBInsertGeneratePaths(data); + /* TODO: XLog */ grn_obj_set_value(ctx, data->pathsColumn, valueID, &(data->pathIDs), GRN_OBJ_SET); @@ -501,6 +507,7 @@ PGrnJSONBInsertValueSet(PGrnJSONBInsertData *data, grn_obj_set_value(ctx, column, valueID, &(data->value), GRN_OBJ_SET); GRN_TEXT_SETS(ctx, &(data->type), typeName); + /* TODO: XLog */ grn_obj_set_value(ctx, data->typeColumn, valueID, &(data->type), GRN_OBJ_SET); } @@ -942,6 +949,7 @@ pgroonga_match_jsonb(PG_FUNCTION_ARGS) data.valuesTable = tmpValuesTable; GRN_PTR_INIT(&valueIDs, GRN_OBJ_VECTOR, grn_obj_id(ctx, data.valuesTable)); data.valueIDs = &valueIDs; + data.xlogData = NULL; PGrnJSONBInsertDataInit(&data); iter = JsonbIteratorInit(&(jsonb->root)); PGrnJSONBInsertContainer(&iter, &data); @@ -992,7 +1000,8 @@ void PGrnJSONBInsert(Relation index, Datum *values, unsigned int nthValue, - grn_obj *valueIDs) + grn_obj *valueIDs, + PGrnXLogData *xlogData) { #ifdef PGRN_SUPPORT_JSONB PGrnJSONBInsertData data; @@ -1002,6 +1011,7 @@ PGrnJSONBInsert(Relation index, data.pathsTable = PGrnJSONBLookupPathsTable(index, nthValue, ERROR); data.valuesTable = PGrnJSONBLookupValuesTable(index, nthValue, ERROR); data.valueIDs = valueIDs; + data.xlogData = xlogData; grn_obj_reinit(ctx, data.valueIDs, grn_obj_id(ctx, data.valuesTable), GRN_OBJ_VECTOR); Modified: src/pgrn_jsonb.h (+3 -1) =================================================================== --- src/pgrn_jsonb.h 2016-10-23 00:44:10 +0900 (23956d0) +++ src/pgrn_jsonb.h 2016-10-24 00:05:05 +0900 (8cf3c68) @@ -5,6 +5,7 @@ #include "pgrn_create.h" #include "pgrn_search.h" +#include "pgrn_xlog.h" void PGrnInitializeJSONB(void); void PGrnFinalizeJSONB(void); @@ -43,7 +44,8 @@ grn_obj *PGrnJSONBSetSource(Relation index, unsigned int i); void PGrnJSONBInsert(Relation index, Datum *values, unsigned int nthValue, - grn_obj *valueIDs); + grn_obj *valueIDs, + PGrnXLogData *xlogData); bool PGrnJSONBBuildSearchCondition(PGrnSearchData *data, ScanKey key, Modified: src/pgrn_variables.c (+29 -2) =================================================================== --- src/pgrn_variables.c 2016-10-23 00:44:10 +0900 (07ef83d) +++ src/pgrn_variables.c 2016-10-24 00:05:05 +0900 (2ad98eb) @@ -4,6 +4,7 @@ #include "pgrn_global.h" #include "pgrn_value.h" #include "pgrn_variables.h" +#include "pgrn_xlog.h" #include <utils/guc.h> @@ -46,6 +47,7 @@ static struct config_enum_entry PGrnLogLevelEntries[] = { #endif static int PGrnLockTimeout; +static bool PGrnEnableWAL; #ifdef PGRN_SUPPORT_ENUM_VARIABLE static void @@ -157,6 +159,19 @@ PGrnLockTimeoutAssign(int new_value, void *extra) } #endif +static void +PGrnEnableWALAssign(bool new_value, void *extra) +{ + if (new_value) + { + PGrnXLogEnable(); + } + else + { + PGrnXLogDisable(); + } +} + void PGrnInitializeVariables(void) { @@ -210,9 +225,9 @@ PGrnInitializeVariables(void) "Try pgroonga.lock_timeout times " "at 1 msec intervals to " "get write lock in PGroonga.", - "The default is 10000000. " + "The default is 900000. " "It means that PGroonga tries to get write lock " - "between about 2.7 hours.", + "between about 15 minutes.", &PGrnLockTimeout, grn_get_lock_timeout(), 0, @@ -223,5 +238,17 @@ PGrnInitializeVariables(void) PGrnLockTimeoutAssign, NULL); + DefineCustomBoolVariable("pgroonga.enable_wal", + "Enable WAL. (experimental)", + "It requires PostgreSQL 9.6 or later. " + "It's an experimental feature.", + &PGrnEnableWAL, + PGrnXLogGetEnabled(), + PGC_USERSET, + 0, + NULL, + PGrnEnableWALAssign, + NULL); + EmitWarningsOnPlaceholders("pgroonga"); } Added: src/pgrn_xlog.c (+425 -0) 100644 =================================================================== --- /dev/null +++ src/pgrn_xlog.c 2016-10-24 00:05:05 +0900 (dda9ed9) @@ -0,0 +1,425 @@ +#include "pgroonga.h" + +#include "pgrn_compatible.h" + +#include "pgrn_global.h" +#include "pgrn_xlog.h" + +#include <storage/bufmgr.h> +#include <storage/bufpage.h> +#include <storage/lmgr.h> +#include <storage/lockdefs.h> + +static bool PGrnXLogEnabled = false; + +bool +PGrnXLogGetEnabled(void) +{ + return PGrnXLogEnabled; +} + +void +PGrnXLogEnable(void) +{ + PGrnXLogEnabled = true; +} + +void +PGrnXLogDisable(void) +{ + PGrnXLogEnabled = false; +} + +#ifdef PGRN_SUPPORT_XLOG +# include <access/generic_xlog.h> +# include <msgpack.h> +#endif + +#ifdef PGRN_SUPPORT_XLOG +static grn_ctx *ctx = &PGrnContext; +#endif + +#ifdef PGRN_SUPPORT_XLOG +typedef struct { + BlockNumber start; + BlockNumber current; + BlockNumber end; +} PGrnMetaPageSpecial; + +#define PGRN_PAGE_DATA_SIZE BLCKSZ - SizeOfPageHeaderData - sizeof(OffsetNumber) +typedef struct { + OffsetNumber current; + uint8_t data[PGRN_PAGE_DATA_SIZE]; +} PGrnPageSpecial; + +typedef struct { + GenericXLogState *state; + PGrnMetaPageSpecial *metaPageSpecial; + Buffer buffer; + Page page; + PGrnPageSpecial *special; +} PGrnPageWriteData; +#endif + +struct PGrnXLogData_ +{ + Relation index; +#ifdef PGRN_SUPPORT_XLOG + GenericXLogState *state; + struct + { + Buffer buffer; + Page page; + PGrnMetaPageSpecial *pageSpecial; + } meta; + struct + { + Buffer buffer; + Page page; + PGrnPageSpecial *pageSpecial; + } current; + msgpack_packer packer; +#endif +}; + +#define PGRN_XLOG_META_PAGE_BLOCK_NUMBER 0 + +#ifdef PGRN_SUPPORT_XLOG +static void +PGrnXLogDataInitMeta(PGrnXLogData *data) +{ + if (RelationGetNumberOfBlocks(data->index) == 0) + { + LockRelationForExtension(data->index, ExclusiveLock); + data->meta.buffer = ReadBuffer(data->index, P_NEW); + LockBuffer(data->meta.buffer, BUFFER_LOCK_EXCLUSIVE); + UnlockRelationForExtension(data->index, ExclusiveLock); + } + else + { + data->meta.buffer = ReadBuffer(data->index, + PGRN_XLOG_META_PAGE_BLOCK_NUMBER); + LockBuffer(data->meta.buffer, BUFFER_LOCK_EXCLUSIVE); + } + + data->meta.page = GenericXLogRegisterBuffer(data->state, + data->meta.buffer, + GENERIC_XLOG_FULL_IMAGE); + if (PageIsNew(data->meta.page)) + { + PageInit(data->meta.page, BLCKSZ, sizeof(PGrnMetaPageSpecial)); + data->meta.pageSpecial = + (PGrnMetaPageSpecial *)PageGetSpecialPointer(data->meta.page); + data->meta.pageSpecial->start = PGRN_XLOG_META_PAGE_BLOCK_NUMBER + 1; + data->meta.pageSpecial->current = data->meta.pageSpecial->start; + data->meta.pageSpecial->end = data->meta.pageSpecial->start; + } + else + { + data->meta.pageSpecial = + (PGrnMetaPageSpecial *)PageGetSpecialPointer(data->meta.page); + } +} + +static void +PGrnXLogDataInitCurrent(PGrnXLogData *data) +{ + data->current.buffer = InvalidBuffer; + data->current.page = NULL; + data->current.pageSpecial = NULL; +} + +static int +PGrnXLogPageWriter(void *userData, + const char *buffer, + size_t length) +{ + PGrnXLogData *data = userData; + int written = 0; + + while (written < length) + { + if (BufferIsInvalid(data->current.buffer)) + { + if (RelationGetNumberOfBlocks(data->index) <= + data->meta.pageSpecial->current) + { + LockRelationForExtension(data->index, ExclusiveLock); + data->current.buffer = ReadBuffer(data->index, P_NEW); + LockBuffer(data->current.buffer, BUFFER_LOCK_EXCLUSIVE); + UnlockRelationForExtension(data->index, ExclusiveLock); + + data->meta.pageSpecial->current = + BufferGetBlockNumber(data->current.buffer); + data->meta.pageSpecial->end = data->meta.pageSpecial->current; + } + else + { + data->current.buffer = + ReadBuffer(data->index, data->meta.pageSpecial->current); + LockBuffer(data->current.buffer, BUFFER_LOCK_EXCLUSIVE); + } + } + + if (!PageIsValid(data->current.page)) + { + data->current.page = + GenericXLogRegisterBuffer(data->state, + data->current.buffer, + GENERIC_XLOG_FULL_IMAGE); + if (PageIsNew(data->current.page)) + { + PageInit(data->current.page, BLCKSZ, sizeof(PGrnPageSpecial)); + data->current.pageSpecial = + (PGrnPageSpecial *)PageGetSpecialPointer(data->current.page); + data->current.pageSpecial->current = 0; + } + else + { + data->current.pageSpecial = + (PGrnPageSpecial *)PageGetSpecialPointer(data->current.page); + } + } + + if (data->current.pageSpecial->current + length <= PGRN_PAGE_DATA_SIZE) + { + memcpy(data->current.pageSpecial->data + + SizeOfPageHeaderData + + data->current.pageSpecial->current, + buffer, + length); + data->current.pageSpecial->current += length; + written += length; + } + else + { + size_t writableSize; + + writableSize = + PGRN_PAGE_DATA_SIZE - data->current.pageSpecial->current; + memcpy(data->current.pageSpecial->data + + SizeOfPageHeaderData + + data->current.pageSpecial->current, + buffer, + writableSize); + data->current.pageSpecial->current += writableSize; + written += writableSize; + length -= writableSize; + buffer += writableSize; + + data->current.page = NULL; + UnlockReleaseBuffer(data->current.buffer); + data->current.buffer = InvalidBuffer; + data->meta.pageSpecial->current++; + } + } + + return written; +} + +static void +PGrnXLogDataInitMessagePack(PGrnXLogData *data) +{ + msgpack_packer_init(&(data->packer), data, PGrnXLogPageWriter); +} +#endif + +PGrnXLogData * +PGrnXLogStart(Relation index) +{ +#ifdef PGRN_SUPPORT_XLOG + PGrnXLogData *data; + + if (!PGrnXLogEnabled) + return NULL; + + data = palloc(sizeof(PGrnXLogData)); + + data->index = index; + data->state = GenericXLogStart(data->index); + + PGrnXLogDataInitMeta(data); + PGrnXLogDataInitCurrent(data); + PGrnXLogDataInitMessagePack(data); + + return data; +#else + return NULL; +#endif +} + +void +PGrnXLogFinish(PGrnXLogData *data) +{ +#ifdef PGRN_SUPPORT_XLOG + if (!PGrnXLogEnabled) + return; + + GenericXLogFinish(data->state); + + if (data->current.buffer) + { + UnlockReleaseBuffer(data->current.buffer); + } + UnlockReleaseBuffer(data->meta.buffer); + + pfree(data); +#endif +} + +void +PGrnXLogAbort(PGrnXLogData *data) +{ +#ifdef PGRN_SUPPORT_XLOG + if (!PGrnXLogEnabled) + return; + + GenericXLogAbort(data->state); + + if (data->current.buffer) + { + UnlockReleaseBuffer(data->current.buffer); + } + UnlockReleaseBuffer(data->meta.buffer); + + pfree(data); +#endif +} + +void +PGrnXLogInsertStart(PGrnXLogData *data, + size_t nColumns) +{ +#ifdef PGRN_SUPPORT_XLOG + msgpack_packer *packer; + + if (!PGrnXLogEnabled) + return; + + packer = &(data->packer); + msgpack_pack_map(packer, nColumns); +#endif +} + +void +PGrnXLogInsertFinish(PGrnXLogData *data) +{ +} + +void +PGrnXLogInsertColumnStart(PGrnXLogData *data, + const char *name) +{ +#ifdef PGRN_SUPPORT_XLOG + msgpack_packer *packer; + size_t nameSize; + + if (!PGrnXLogEnabled) + return; + + packer = &(data->packer); + + nameSize = strlen(name); + msgpack_pack_str(packer, nameSize); + msgpack_pack_str_body(packer, name, nameSize); +#endif +} + +void +PGrnXLogInsertColumnFinish(PGrnXLogData *data) +{ +} + +void +PGrnXLogInsertColumn(PGrnXLogData *data, + const char *name, + grn_obj *value) +{ +#ifdef PGRN_SUPPORT_XLOG + msgpack_packer *packer; + + if (!PGrnXLogEnabled) + return; + + packer = &(data->packer); + + PGrnXLogInsertColumnStart(data, name); + + if (value->header.type != GRN_BULK) { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("pgroonga: XLog: array value isn't supported yet: <%s>", + grn_obj_type_to_string(value->header.type)))); + } + + switch (value->header.domain) + { + case GRN_DB_BOOL: + if (GRN_BOOL_VALUE(value)) + { + msgpack_pack_true(packer); + } + else + { + msgpack_pack_false(packer); + } + break; + case GRN_DB_INT8: + msgpack_pack_int8(packer, GRN_INT8_VALUE(value)); + break; + case GRN_DB_UINT8: + msgpack_pack_uint8(packer, GRN_UINT8_VALUE(value)); + break; + case GRN_DB_INT16: + msgpack_pack_int16(packer, GRN_INT16_VALUE(value)); + break; + case GRN_DB_UINT16: + msgpack_pack_uint16(packer, GRN_UINT16_VALUE(value)); + break; + case GRN_DB_INT32: + msgpack_pack_int32(packer, GRN_INT32_VALUE(value)); + break; + case GRN_DB_UINT32: + msgpack_pack_uint32(packer, GRN_UINT32_VALUE(value)); + break; + case GRN_DB_INT64: + msgpack_pack_int64(packer, GRN_INT64_VALUE(value)); + break; + case GRN_DB_UINT64: + msgpack_pack_uint64(packer, GRN_UINT64_VALUE(value)); + break; + case GRN_DB_FLOAT: + msgpack_pack_double(packer, GRN_FLOAT_VALUE(value)); + break; + case GRN_DB_TIME: + msgpack_pack_int64(packer, GRN_TIME_VALUE(value)); + break; + case GRN_DB_SHORT_TEXT: + case GRN_DB_TEXT: + case GRN_DB_LONG_TEXT: + msgpack_pack_str(packer, GRN_TEXT_LEN(value)); + msgpack_pack_str_body(packer, + GRN_TEXT_VALUE(value), + GRN_TEXT_LEN(value)); + break; + default: + { + char name[GRN_TABLE_MAX_KEY_SIZE]; + int nameSize; + + nameSize = grn_table_get_key(ctx, + grn_ctx_db(ctx), + value->header.domain, + name, + GRN_TABLE_MAX_KEY_SIZE); + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("pgroonga: XLog: unsupported type: <%.*s>", + nameSize, name))); + } + break; + } + + PGrnXLogInsertColumnFinish(data); +#endif +} Added: src/pgrn_xlog.h (+24 -0) 100644 =================================================================== --- /dev/null +++ src/pgrn_xlog.h 2016-10-24 00:05:05 +0900 (8f185c3) @@ -0,0 +1,24 @@ +#pragma once + +#include <postgres.h> +#include <utils/relcache.h> + +#include <groonga.h> + +typedef struct PGrnXLogData_ PGrnXLogData; + +bool PGrnXLogGetEnabled(void); +void PGrnXLogEnable(void); +void PGrnXLogDisable(void); + +PGrnXLogData *PGrnXLogStart(Relation index); +void PGrnXLogFinish(PGrnXLogData *data); +void PGrnXLogAbort(PGrnXLogData *data); + +void PGrnXLogInsertStart(PGrnXLogData *data, size_t nColumns); +void PGrnXLogInsertFinish(PGrnXLogData *data); +void PGrnXLogInsertColumnStart(PGrnXLogData *data, const char *name); +void PGrnXLogInsertColumnFinish(PGrnXLogData *data); +void PGrnXLogInsertColumn(PGrnXLogData *data, + const char *name, + grn_obj *value); Modified: src/pgroonga.c (+20 -6) =================================================================== --- src/pgroonga.c 2016-10-23 00:44:10 +0900 (4e35010) +++ src/pgroonga.c 2016-10-24 00:05:05 +0900 (d4a58d9) @@ -16,13 +16,11 @@ #include "pgrn_search.h" #include "pgrn_value.h" #include "pgrn_variables.h" +#include "pgrn_xlog.h" #ifdef PGRN_SUPPORT_CREATE_ACCESS_METHOD # include <access/amapi.h> #endif -#ifdef PGRN_SUPPORT_XLOG -# include <access/generic_xlog.h> -#endif #ifdef PGRN_SUPPORT_OPTIONS # include <access/reloptions.h> #endif @@ -1932,11 +1930,17 @@ PGrnInsert(Relation index, { TupleDesc desc = RelationGetDescr(index); grn_id id; + PGrnXLogData *xlogData; unsigned int i; id = grn_table_add(ctx, sourcesTable, NULL, 0, NULL); + + xlogData = PGrnXLogStart(index); + PGrnXLogInsertStart(xlogData, desc->natts + 1); + GRN_UINT64_SET(ctx, &(buffers->ctid), CtidToUInt64(ht_ctid)); grn_obj_set_value(ctx, sourcesCtidColumn, id, &(buffers->ctid), GRN_OBJ_SET); + PGrnXLogInsertColumn(xlogData, "ctid", &(buffers->ctid)); for (i = 0; i < desc->natts; i++) { @@ -1945,6 +1949,7 @@ PGrnInsert(Relation index, NameData *name; grn_id domain; unsigned char flags; + grn_obj *buffer; name = &(attribute->attname); if (isnull[i]) @@ -1952,22 +1957,31 @@ PGrnInsert(Relation index, dataColumn = PGrnLookupColumn(sourcesTable, name->data, ERROR); + buffer = &(buffers->general); if (PGrnAttributeIsJSONB(attribute->atttypid)) { - PGrnJSONBInsert(index, values, i, &(buffers->general)); + /* PGrnXLogInsertColumnStart(xlogData, name->data); */ + PGrnJSONBInsert(index, values, i, buffer, xlogData); + grn_obj_set_value(ctx, dataColumn, id, buffer, GRN_OBJ_SET); + /* PGrnXLogInsertColumnFinish(xlogData); */ + PGrnXLogInsertColumn(xlogData, name->data, buffer); } else { domain = PGrnGetType(index, i, &flags); grn_obj_reinit(ctx, &(buffers->general), domain, flags); - PGrnConvertFromData(values[i], attribute->atttypid, &(buffers->general)); + PGrnConvertFromData(values[i], attribute->atttypid, buffer); + grn_obj_set_value(ctx, dataColumn, id, buffer, GRN_OBJ_SET); + PGrnXLogInsertColumn(xlogData, name->data, buffer); } - grn_obj_set_value(ctx, dataColumn, id, &(buffers->general), GRN_OBJ_SET); grn_obj_unlink(ctx, dataColumn); if (!PGrnCheck("pgroonga: failed to set column value")) { continue; } } + + PGrnXLogInsertFinish(xlogData); + PGrnXLogFinish(xlogData); } static bool -------------- next part -------------- HTML����������������������������... Download