/* -*- c-basic-offset: 2 -*- */
/*
Copyright ( C ) 2009 - 2017 Brazil
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License version 2 . 1 as published by the Free Software Foundation .
This library is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1335 USA
*/
#include "grn.h"
#include "grn_str.h"
#include "grn_store.h"
#include "grn_ctx_impl.h"
#include "grn_output.h"
#include <string.h>
/* rectangular arrays */
#define GRN_RA_W_SEGMENT 22
#define GRN_RA_SEGMENT_SIZE (1 << GRN_RA_W_SEGMENT)
static grn_ra *
_grn_ra_create(grn_ctx *ctx, grn_ra *ra, const char *path, unsigned int element_size)
{
grn_io *io;
int max_segments, n_elm, w_elm;
struct grn_ra_header *header;
unsigned int actual_size;
if (element_size > GRN_RA_SEGMENT_SIZE) {
GRN_LOG(ctx, GRN_LOG_ERROR, "element_size too large (%d)" , element_size);
return NULL;
}
for (actual_size = 1 ; actual_size < element_size; actual_size *= 2 ) ;
max_segments = ((GRN_ID_MAX + 1 ) / GRN_RA_SEGMENT_SIZE) * actual_size;
io = grn_io_create(ctx, path, sizeof (struct grn_ra_header),
GRN_RA_SEGMENT_SIZE, max_segments, grn_io_auto,
GRN_IO_EXPIRE_SEGMENT);
if (!io) { return NULL; }
header = grn_io_header(io);
grn_io_set_type(io, GRN_COLUMN_FIX_SIZE);
header->element_size = actual_size;
n_elm = GRN_RA_SEGMENT_SIZE / header->element_size;
for (w_elm = GRN_RA_W_SEGMENT; (1 << w_elm) > n_elm; w_elm--);
ra->io = io;
ra->header = header;
ra->element_mask = n_elm - 1 ;
ra->element_width = w_elm;
return ra;
}
grn_ra *
grn_ra_create(grn_ctx *ctx, const char *path, unsigned int element_size)
{
grn_ra *ra = (grn_ra *)GRN_CALLOC(sizeof (grn_ra));
if (!ra) {
return NULL;
}
GRN_DB_OBJ_SET_TYPE(ra, GRN_COLUMN_FIX_SIZE);
if (!_grn_ra_create(ctx, ra, path, element_size)) {
GRN_FREE(ra);
return NULL;
}
return ra;
}
grn_ra *
grn_ra_open(grn_ctx *ctx, const char *path)
{
grn_io *io;
int n_elm, w_elm;
grn_ra *ra = NULL;
struct grn_ra_header *header;
uint32_t io_type;
io = grn_io_open(ctx, path, grn_io_auto);
if (!io) { return NULL; }
header = grn_io_header(io);
io_type = grn_io_get_type(io);
if (io_type != GRN_COLUMN_FIX_SIZE) {
ERR(GRN_INVALID_FORMAT,
"[column][fix-size] file type must be %#04x: <%#04x>" ,
GRN_COLUMN_FIX_SIZE, io_type);
grn_io_close(ctx, io);
return NULL;
}
ra = GRN_MALLOCN(grn_ra, 1 );
if (!ra) {
grn_io_close(ctx, io);
return NULL;
}
n_elm = GRN_RA_SEGMENT_SIZE / header->element_size;
for (w_elm = GRN_RA_W_SEGMENT; (1 << w_elm) > n_elm; w_elm--);
GRN_DB_OBJ_SET_TYPE(ra, GRN_COLUMN_FIX_SIZE);
ra->io = io;
ra->header = header;
ra->element_mask = n_elm - 1 ;
ra->element_width = w_elm;
return ra;
}
grn_rc
grn_ra_info(grn_ctx *ctx, grn_ra *ra, unsigned int *element_size)
{
if (!ra) { return GRN_INVALID_ARGUMENT; }
if (element_size) { *element_size = ra->header->element_size; }
return GRN_SUCCESS;
}
grn_rc
grn_ra_close(grn_ctx *ctx, grn_ra *ra)
{
grn_rc rc;
if (!ra) { return GRN_INVALID_ARGUMENT; }
rc = grn_io_close(ctx, ra->io);
GRN_FREE(ra);
return rc;
}
grn_rc
grn_ra_remove(grn_ctx *ctx, const char *path)
{
if (!path) { return GRN_INVALID_ARGUMENT; }
return grn_io_remove(ctx, path);
}
grn_rc
grn_ra_truncate(grn_ctx *ctx, grn_ra *ra)
{
grn_rc rc;
const char *io_path;
char *path;
unsigned int element_size;
if ((io_path = grn_io_path(ra->io)) && *io_path != '\0' ) {
if (!(path = GRN_STRDUP(io_path))) {
ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>" , io_path);
return GRN_NO_MEMORY_AVAILABLE;
}
} else {
path = NULL;
}
element_size = ra->header->element_size;
if ((rc = grn_io_close(ctx, ra->io))) { goto exit ; }
ra->io = NULL;
if (path && (rc = grn_io_remove(ctx, path))) { goto exit ; }
if (!_grn_ra_create(ctx, ra, path, element_size)) {
rc = GRN_UNKNOWN_ERROR;
}
exit :
if (path) { GRN_FREE(path); }
return rc;
}
void *
grn_ra_ref(grn_ctx *ctx, grn_ra *ra, grn_id id)
{
void *p = NULL;
uint16_t seg;
if (id > GRN_ID_MAX) { return NULL; }
seg = id >> ra->element_width;
GRN_IO_SEG_REF(ra->io, seg, p);
if (!p) { return NULL; }
return (void *)(((byte *)p) + ((id & ra->element_mask) * ra->header->element_size));
}
grn_rc
grn_ra_unref(grn_ctx *ctx, grn_ra *ra, grn_id id)
{
uint16_t seg;
if (id > GRN_ID_MAX) { return GRN_INVALID_ARGUMENT; }
seg = id >> ra->element_width;
GRN_IO_SEG_UNREF(ra->io, seg);
return GRN_SUCCESS;
}
void *
grn_ra_ref_cache(grn_ctx *ctx, grn_ra *ra, grn_id id, grn_ra_cache *cache)
{
void *p = NULL;
uint16_t seg;
if (id > GRN_ID_MAX) { return NULL; }
seg = id >> ra->element_width;
if (seg == cache->seg) {
p = cache->p;
} else {
if (cache->seg != -1 ) { GRN_IO_SEG_UNREF(ra->io, cache->seg); }
GRN_IO_SEG_REF(ra->io, seg, p);
cache->seg = seg;
cache->p = p;
}
if (!p) { return NULL; }
return (void *)(((byte *)p) + ((id & ra->element_mask) * ra->header->element_size));
}
grn_rc
grn_ra_cache_fin(grn_ctx *ctx, grn_ra *ra, grn_id id)
{
uint16_t seg;
if (id > GRN_ID_MAX) { return GRN_INVALID_ARGUMENT; }
seg = id >> ra->element_width;
GRN_IO_SEG_UNREF(ra->io, seg);
return GRN_SUCCESS;
}
/**** jagged arrays ****/
#define GRN_JA_W_SEGREGATE_THRESH_V1 7
#define GRN_JA_W_SEGREGATE_THRESH_V2 16
#define GRN_JA_W_CAPACITY 38
#define GRN_JA_W_SEGMENT 22
#define JA_ESEG_VOID (0 xffffffffU)
#define JA_SEGMENT_SIZE (1 U << GRN_JA_W_SEGMENT)
#define JA_W_EINFO 3
#define JA_W_SEGMENTS_MAX (GRN_JA_W_CAPACITY - GRN_JA_W_SEGMENT)
#define JA_W_EINFO_IN_A_SEGMENT (GRN_JA_W_SEGMENT - JA_W_EINFO)
#define JA_N_EINFO_IN_A_SEGMENT (1 U << JA_W_EINFO_IN_A_SEGMENT)
#define JA_M_EINFO_IN_A_SEGMENT (JA_N_EINFO_IN_A_SEGMENT - 1 )
#define JA_N_GARBAGES_IN_A_SEGMENT ((1 U << (GRN_JA_W_SEGMENT - 3 )) - 2 )
#define JA_N_ELEMENT_VARIATION_V1 (GRN_JA_W_SEGREGATE_THRESH_V1 - JA_W_EINFO + 1 )
#define JA_N_ELEMENT_VARIATION_V2 (GRN_JA_W_SEGREGATE_THRESH_V2 - JA_W_EINFO + 1 )
#define JA_N_DSEGMENTS (1 U << JA_W_SEGMENTS_MAX)
#define JA_N_ESEGMENTS (1 U << (GRN_ID_WIDTH - JA_W_EINFO_IN_A_SEGMENT))
typedef struct _grn_ja_einfo grn_ja_einfo;
struct _grn_ja_einfo {
union {
struct {
uint16_t seg;
uint16_t pos;
uint16_t size;
uint8_t c1;
uint8_t c2;
} n;
struct {
uint32_t size;
uint16_t seg;
uint8_t c1;
uint8_t c2;
} h;
uint8_t c[8 ];
} u;
};
#define ETINY (0 x80)
#define EHUGE (0 x40)
#define ETINY_P(e) ((e)->u.c[7 ] & ETINY)
#define ETINY_ENC(e,_size) ((e)->u.c[7 ] = (_size) + ETINY)
#define ETINY_DEC(e,_size) ((_size) = (e)->u.c[7 ] & ~(ETINY|EHUGE))
#define EHUGE_P(e) ((e)->u.c[7 ] & EHUGE)
#define EHUGE_ENC(e,_seg,_size) do {\
(e)->u.h.c1 = 0 ;\
(e)->u.h.c2 = EHUGE;\
(e)->u.h.seg = (_seg);\
(e)->u.h.size = (_size);\
} while (0 )
#define EHUGE_DEC_SIZE(e, _size) do {\
(_size) = (e)->u.h.size;\
} while (0 )
#define EHUGE_DEC(e,_seg,_size) do {\
(_seg) = (e)->u.h.seg;\
EHUGE_DEC_SIZE((e), (_size));\
} while (0 )
#define EINFO_ENC(e,_seg,_pos,_size) do {\
(e)->u.n.c1 = (_pos) >> 16 ;\
(e)->u.n.c2 = ((_size) >> 16 );\
(e)->u.n.seg = (_seg);\
(e)->u.n.pos = (_pos);\
(e)->u.n.size = (_size);\
} while (0 )
#define EINFO_DEC_POS_SIZE(e, _pos, _size) do {\
(_pos) = ((e)->u.n.c1 << 16 ) + (e)->u.n.pos;\
(_size) = ((e)->u.n.c2 << 16 ) + (e)->u.n.size;\
} while (0 )
#define EINFO_DEC(e,_seg,_pos,_size) do {\
(_seg) = (e)->u.n.seg;\
EINFO_DEC_POS_SIZE((e), (_pos), (_size));\
} while (0 )
typedef struct {
uint32_t seg;
uint32_t pos;
} ja_pos;
typedef struct {
uint32_t head;
uint32_t tail;
uint32_t nrecs;
uint32_t next;
ja_pos recs[JA_N_GARBAGES_IN_A_SEGMENT];
} grn_ja_ginfo;
struct grn_ja_header_v1 {
uint32_t flags;
uint32_t curr_seg;
uint32_t curr_pos;
uint32_t max_element_size;
ja_pos free_elements[JA_N_ELEMENT_VARIATION_V1];
uint32_t garbages[JA_N_ELEMENT_VARIATION_V1];
uint32_t ngarbages[JA_N_ELEMENT_VARIATION_V1];
uint32_t dsegs[JA_N_DSEGMENTS];
uint32_t esegs[JA_N_ESEGMENTS];
};
struct grn_ja_header_v2 {
uint32_t flags;
uint32_t curr_seg;
uint32_t curr_pos;
uint32_t max_element_size;
ja_pos free_elements[JA_N_ELEMENT_VARIATION_V2];
uint32_t garbages[JA_N_ELEMENT_VARIATION_V2];
uint32_t ngarbages[JA_N_ELEMENT_VARIATION_V2];
uint32_t dsegs[JA_N_DSEGMENTS];
uint32_t esegs[JA_N_ESEGMENTS];
uint8_t segregate_threshold;
uint8_t n_element_variation;
};
struct grn_ja_header {
uint32_t flags;
uint32_t *curr_seg;
uint32_t *curr_pos;
uint32_t max_element_size;
ja_pos *free_elements;
uint32_t *garbages;
uint32_t *ngarbages;
uint32_t *dsegs;
uint32_t *esegs;
uint8_t segregate_threshold;
uint8_t n_element_variation;
};
#define SEG_SEQ (0 x10000000U)
#define SEG_HUGE (0 x20000000U)
#define SEG_EINFO (0 x30000000U)
#define SEG_GINFO (0 x40000000U)
#define SEG_MASK (0 xf0000000U)
#define SEGMENTS_AT(ja,seg) ((ja)->header->dsegs[seg])
#define SEGMENTS_SEGRE_ON(ja,seg,width) (SEGMENTS_AT(ja,seg) = width)
#define SEGMENTS_SEQ_ON(ja,seg) (SEGMENTS_AT(ja,seg) = SEG_SEQ)
#define SEGMENTS_HUGE_ON(ja,seg) (SEGMENTS_AT(ja,seg) = SEG_HUGE)
#define SEGMENTS_EINFO_ON(ja,seg,lseg) (SEGMENTS_AT(ja,seg) = SEG_EINFO|(lseg))
#define SEGMENTS_GINFO_ON(ja,seg,width) (SEGMENTS_AT(ja,seg) = SEG_GINFO|(width))
#define SEGMENTS_OFF(ja,seg) (SEGMENTS_AT(ja,seg) = 0 )
static grn_ja *
_grn_ja_create(grn_ctx *ctx, grn_ja *ja, const char *path,
unsigned int max_element_size, uint32_t flags)
{
unsigned int i;
grn_io *io;
struct grn_ja_header *header;
struct grn_ja_header_v2 *header_v2;
io = grn_io_create(ctx, path, sizeof (struct grn_ja_header_v2),
JA_SEGMENT_SIZE, JA_N_DSEGMENTS, grn_io_auto,
GRN_IO_EXPIRE_SEGMENT);
if (!io) { return NULL; }
grn_io_set_type(io, GRN_COLUMN_VAR_SIZE);
header_v2 = grn_io_header(io);
header_v2->flags = flags;
header_v2->curr_seg = 0 ;
header_v2->curr_pos = JA_SEGMENT_SIZE;
header_v2->max_element_size = max_element_size;
for (i = 0 ; i < JA_N_ESEGMENTS; i++) { header_v2->esegs[i] = JA_ESEG_VOID; }
header_v2->segregate_threshold = GRN_JA_W_SEGREGATE_THRESH_V2;
header_v2->n_element_variation = JA_N_ELEMENT_VARIATION_V2;
header = GRN_MALLOCN(struct grn_ja_header, 1 );
if (!header) {
grn_io_close(ctx, io);
return NULL;
}
header->flags = header_v2->flags;
header->curr_seg = &(header_v2->curr_seg);
header->curr_pos = &(header_v2->curr_pos);
header->max_element_size = header_v2->max_element_size;
header->free_elements = header_v2->free_elements;
header->garbages = header_v2->garbages;
header->ngarbages = header_v2->ngarbages;
header->dsegs = header_v2->dsegs;
header->esegs = header_v2->esegs;
header->segregate_threshold = header_v2->segregate_threshold;
header->n_element_variation = header_v2->n_element_variation;
ja->io = io;
ja->header = header;
SEGMENTS_EINFO_ON(ja, 0 , 0 );
header->esegs[0 ] = 0 ;
return ja;
}
grn_ja *
grn_ja_create(grn_ctx *ctx, const char *path, unsigned int max_element_size, uint32_t flags)
{
grn_ja *ja = NULL;
ja = (grn_ja *)GRN_CALLOC(sizeof (grn_ja));
if (!ja) {
return NULL;
}
GRN_DB_OBJ_SET_TYPE(ja, GRN_COLUMN_VAR_SIZE);
if (!_grn_ja_create(ctx, ja, path, max_element_size, flags)) {
GRN_FREE(ja);
return NULL;
}
return ja;
}
grn_ja *
grn_ja_open(grn_ctx *ctx, const char *path)
{
grn_io *io;
grn_ja *ja = NULL;
struct grn_ja_header *header;
struct grn_ja_header_v2 *header_v2;
uint32_t io_type;
io = grn_io_open(ctx, path, grn_io_auto);
if (!io) { return NULL; }
header_v2 = grn_io_header(io);
io_type = grn_io_get_type(io);
if (io_type != GRN_COLUMN_VAR_SIZE) {
ERR(GRN_INVALID_FORMAT,
"[column][var-size] file type must be %#04x: <%#04x>" ,
GRN_COLUMN_VAR_SIZE, io_type);
grn_io_close(ctx, io);
return NULL;
}
if (header_v2->segregate_threshold == 0 ) {
header_v2->segregate_threshold = GRN_JA_W_SEGREGATE_THRESH_V1;
}
if (header_v2->n_element_variation == 0 ) {
header_v2->n_element_variation = JA_N_ELEMENT_VARIATION_V1;
}
ja = GRN_MALLOCN(grn_ja, 1 );
if (!ja) {
grn_io_close(ctx, io);
return NULL;
}
GRN_DB_OBJ_SET_TYPE(ja, GRN_COLUMN_VAR_SIZE);
header = GRN_MALLOCN(struct grn_ja_header, 1 );
if (!header) {
grn_io_close(ctx, io);
GRN_FREE(ja);
return NULL;
}
header->flags = header_v2->flags;
header->curr_seg = &(header_v2->curr_seg);
header->curr_pos = &(header_v2->curr_pos);
header->max_element_size = header_v2->max_element_size;
header->segregate_threshold = header_v2->segregate_threshold;
header->n_element_variation = header_v2->n_element_variation;
if (header->segregate_threshold == GRN_JA_W_SEGREGATE_THRESH_V1) {
struct grn_ja_header_v1 *header_v1 = (struct grn_ja_header_v1 *)header_v2;
header->free_elements = header_v1->free_elements;
header->garbages = header_v1->garbages;
header->ngarbages = header_v1->ngarbages;
header->dsegs = header_v1->dsegs;
header->esegs = header_v1->esegs;
} else {
header->free_elements = header_v2->free_elements;
header->garbages = header_v2->garbages;
header->ngarbages = header_v2->ngarbages;
header->dsegs = header_v2->dsegs;
header->esegs = header_v2->esegs;
}
ja->io = io;
ja->header = header;
return ja;
}
grn_rc
grn_ja_info(grn_ctx *ctx, grn_ja *ja, unsigned int *max_element_size)
{
if (!ja) { return GRN_INVALID_ARGUMENT; }
if (max_element_size) { *max_element_size = ja->header->max_element_size; }
return GRN_SUCCESS;
}
grn_column_flags
grn_ja_get_flags(grn_ctx *ctx, grn_ja *ja)
{
if (!ja) {
return 0 ;
}
return ja->header->flags;
}
grn_rc
grn_ja_close(grn_ctx *ctx, grn_ja *ja)
{
grn_rc rc;
if (!ja) { return GRN_INVALID_ARGUMENT; }
rc = grn_io_close(ctx, ja->io);
GRN_FREE(ja->header);
GRN_FREE(ja);
return rc;
}
grn_rc
grn_ja_remove(grn_ctx *ctx, const char *path)
{
if (!path) { return GRN_INVALID_ARGUMENT; }
return grn_io_remove(ctx, path);
}
grn_rc
grn_ja_truncate(grn_ctx *ctx, grn_ja *ja)
{
grn_rc rc;
const char *io_path;
char *path;
unsigned int max_element_size;
uint32_t flags;
if ((io_path = grn_io_path(ja->io)) && *io_path != '\0' ) {
if (!(path = GRN_STRDUP(io_path))) {
ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>" , io_path);
return GRN_NO_MEMORY_AVAILABLE;
}
} else {
path = NULL;
}
max_element_size = ja->header->max_element_size;
flags = ja->header->flags;
if ((rc = grn_io_close(ctx, ja->io))) { goto exit ; }
ja->io = NULL;
if (path && (rc = grn_io_remove(ctx, path))) { goto exit ; }
GRN_FREE(ja->header);
if (!_grn_ja_create(ctx, ja, path, max_element_size, flags)) {
rc = GRN_UNKNOWN_ERROR;
}
exit :
if (path) { GRN_FREE(path); }
return rc;
}
static void *
grn_ja_ref_raw(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
{
uint32_t pseg = ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
iw->size = 0 ;
iw->addr = NULL;
iw->pseg = pseg;
iw->uncompressed_value = NULL;
if (pseg != JA_ESEG_VOID) {
grn_ja_einfo *einfo = NULL;
GRN_IO_SEG_REF(ja->io, pseg, einfo);
if (einfo) {
grn_ja_einfo *ei = &einfo[id & JA_M_EINFO_IN_A_SEGMENT];
if (ETINY_P(ei)) {
iw->tiny_p = 1 ;
ETINY_DEC(ei, iw->size);
iw->io = ja->io;
iw->ctx = ctx;
iw->addr = (void *)ei;
} else {
uint32_t jag, vpos, vsize;
iw->tiny_p = 0 ;
if (EHUGE_P(ei)) {
EHUGE_DEC(ei, jag, vsize);
vpos = 0 ;
} else {
EINFO_DEC(ei, jag, vpos, vsize);
}
grn_io_win_map(ja->io, ctx, iw, jag, vpos, vsize, grn_io_rdonly);
}
if (!iw->addr) { GRN_IO_SEG_UNREF(ja->io, pseg); }
}
}
*value_len = iw->size;
return iw->addr;
}
grn_rc
grn_ja_unref(grn_ctx *ctx, grn_io_win *iw)
{
if (iw->uncompressed_value) {
GRN_FREE(iw->uncompressed_value);
iw->uncompressed_value = NULL;
}
if (!iw->addr) { return GRN_INVALID_ARGUMENT; }
GRN_IO_SEG_UNREF(iw->io, iw->pseg);
if (!iw->tiny_p) { grn_io_win_unmap(iw); }
return GRN_SUCCESS;
}
#define DELETED 0 x80000000
static grn_rc
grn_ja_free(grn_ctx *ctx, grn_ja *ja, grn_ja_einfo *einfo)
{
grn_ja_ginfo *ginfo = NULL;
uint32_t seg, pos, element_size, aligned_size, m, *gseg;
if (ETINY_P(einfo)) { return GRN_SUCCESS; }
if (EHUGE_P(einfo)) {
uint32_t n;
EHUGE_DEC(einfo, seg, element_size);
n = ((element_size + JA_SEGMENT_SIZE - 1 ) >> GRN_JA_W_SEGMENT);
for (; n--; seg++) { SEGMENTS_OFF(ja, seg); }
return GRN_SUCCESS;
}
EINFO_DEC(einfo, seg, pos, element_size);
if (!element_size) { return GRN_SUCCESS; }
{
int es = element_size - 1 ;
GRN_BIT_SCAN_REV(es, m);
m++;
}
if (m > ja->header->segregate_threshold) {
byte *addr = NULL;
GRN_IO_SEG_REF(ja->io, seg, addr);
if (!addr) { return GRN_NO_MEMORY_AVAILABLE; }
aligned_size = (element_size + sizeof (grn_id) - 1 ) & ~(sizeof (grn_id) - 1 );
*(uint32_t *)(addr + pos - sizeof (grn_id)) = DELETED|aligned_size;
if (SEGMENTS_AT(ja, seg) < (aligned_size + sizeof (grn_id)) + SEG_SEQ) {
GRN_LOG(ctx, GRN_WARN, "inconsistent ja entry detected (%d > %d)" ,
element_size, SEGMENTS_AT(ja, seg) - SEG_SEQ);
}
SEGMENTS_AT(ja, seg) -= (aligned_size + sizeof (grn_id));
if (SEGMENTS_AT(ja, seg) == SEG_SEQ) {
/* reuse the segment */
SEGMENTS_OFF(ja, seg);
if (seg == *(ja->header->curr_seg)) {
*(ja->header->curr_pos) = JA_SEGMENT_SIZE;
}
}
GRN_IO_SEG_UNREF(ja->io, seg);
} else {
uint32_t lseg = 0 , lseg_;
gseg = &ja->header->garbages[m - JA_W_EINFO];
while ((lseg_ = *gseg)) {
if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
GRN_IO_SEG_REF(ja->io, lseg_, ginfo);
if (!ginfo) {
return GRN_NO_MEMORY_AVAILABLE;
}
lseg = lseg_;
if (ginfo->nrecs < JA_N_GARBAGES_IN_A_SEGMENT) { break ; }
gseg = &ginfo->next;
}
if (!lseg_) {
uint32_t i = 0 ;
while (SEGMENTS_AT(ja, i)) {
if (++i >= JA_N_DSEGMENTS) {
if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
return GRN_NO_MEMORY_AVAILABLE;
}
}
SEGMENTS_GINFO_ON(ja, i, m - JA_W_EINFO);
*gseg = i;
lseg_ = *gseg;
if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
GRN_IO_SEG_REF(ja->io, lseg_, ginfo);
lseg = lseg_;
if (!ginfo) {
return GRN_NO_MEMORY_AVAILABLE;
}
ginfo->head = 0 ;
ginfo->tail = 0 ;
ginfo->nrecs = 0 ;
ginfo->next = 0 ;
}
ginfo->recs[ginfo->head].seg = seg;
ginfo->recs[ginfo->head].pos = pos;
if (++ginfo->head == JA_N_GARBAGES_IN_A_SEGMENT) { ginfo->head = 0 ; }
ginfo->nrecs++;
ja->header->ngarbages[m - JA_W_EINFO]++;
if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
}
return GRN_SUCCESS;
}
grn_rc
grn_ja_replace(grn_ctx *ctx, grn_ja *ja, grn_id id,
grn_ja_einfo *ei, uint64_t *cas)
{
grn_rc rc = GRN_SUCCESS;
uint32_t lseg, *pseg, pos;
grn_ja_einfo *einfo = NULL, eback;
lseg = id >> JA_W_EINFO_IN_A_SEGMENT;
pos = id & JA_M_EINFO_IN_A_SEGMENT;
pseg = &ja->header->esegs[lseg];
if (grn_io_lock(ctx, ja->io, grn_lock_timeout)) {
return ctx->rc;
}
if (*pseg == JA_ESEG_VOID) {
unsigned int i = 0 ;
while (SEGMENTS_AT(ja, i)) {
if (++i >= JA_N_DSEGMENTS) {
ERR(GRN_NOT_ENOUGH_SPACE, "grn_ja file (%s) is full" , ja->io->path);
rc = GRN_NOT_ENOUGH_SPACE;
goto exit ;
}
}
SEGMENTS_EINFO_ON(ja, i, lseg);
GRN_IO_SEG_REF(ja->io, i, einfo);
if (einfo) {
*pseg = i;
memset(einfo, 0 , JA_SEGMENT_SIZE);
}
} else {
GRN_IO_SEG_REF(ja->io, *pseg, einfo);
}
if (!einfo) {
rc = GRN_NO_MEMORY_AVAILABLE;
goto exit ;
}
eback = einfo[pos];
if (cas && *cas != *((uint64_t *)&eback)) {
ERR(GRN_CAS_ERROR, "cas failed (%d)" , id);
GRN_IO_SEG_UNREF(ja->io, *pseg);
rc = GRN_CAS_ERROR;
goto exit ;
}
// smb_wmb();
{
uint64_t *location = (uint64_t *)(einfo + pos);
uint64_t value = *((uint64_t *)ei);
GRN_SET_64BIT(location, value);
}
GRN_IO_SEG_UNREF(ja->io, *pseg);
grn_ja_free(ctx, ja, &eback);
exit :
grn_io_unlock(ja->io);
return rc;
}
#define JA_N_GARBAGES_TH 10
// todo : grn_io_win_map cause verbose copy when nseg > 1, it should be copied directly.
static grn_rc
grn_ja_alloc(grn_ctx *ctx, grn_ja *ja, grn_id id,
uint32_t element_size, grn_ja_einfo *einfo, grn_io_win *iw)
{
byte *addr = NULL;
iw->io = ja->io;
iw->ctx = ctx;
iw->cached = 1 ;
if (element_size < 8 ) {
ETINY_ENC(einfo, element_size);
iw->tiny_p = 1 ;
iw->addr = (void *)einfo;
return GRN_SUCCESS;
}
iw->tiny_p = 0 ;
if (grn_io_lock(ctx, ja->io, grn_lock_timeout)) { return ctx->rc; }
if (element_size + sizeof (grn_id) > JA_SEGMENT_SIZE) {
uint i;
int j, n = (element_size + JA_SEGMENT_SIZE - 1 ) >> GRN_JA_W_SEGMENT;
for (i = 0 , j = -1 ; i < JA_N_DSEGMENTS; i++) {
if (SEGMENTS_AT(ja, i)) {
j = i;
} else {
if (i == (uint) (j + n)) {
j++;
addr = grn_io_win_map(ja->io, ctx, iw, j, 0 , element_size, grn_io_wronly);
if (!addr) {
grn_io_unlock(ja->io);
return GRN_NO_MEMORY_AVAILABLE;
}
EHUGE_ENC(einfo, j, element_size);
for (; j <= (int ) i; j++) { SEGMENTS_HUGE_ON(ja, j); }
grn_io_unlock(ja->io);
return GRN_SUCCESS;
}
}
}
GRN_LOG(ctx, GRN_LOG_CRIT, "ja full. requested element_size=%d." , element_size);
grn_io_unlock(ja->io);
return GRN_NO_MEMORY_AVAILABLE;
} else {
ja_pos *vp;
int m, aligned_size, es = element_size - 1 ;
GRN_BIT_SCAN_REV(es, m);
m++;
if (m > ja->header->segregate_threshold) {
uint32_t seg = *(ja->header->curr_seg);
uint32_t pos = *(ja->header->curr_pos);
if (pos + element_size + sizeof (grn_id) > JA_SEGMENT_SIZE) {
seg = 0 ;
while (SEGMENTS_AT(ja, seg)) {
if (++seg >= JA_N_DSEGMENTS) {
grn_io_unlock(ja->io);
GRN_LOG(ctx, GRN_LOG_CRIT, "ja full. seg=%d." , seg);
return GRN_NOT_ENOUGH_SPACE;
}
}
SEGMENTS_SEQ_ON(ja, seg);
*(ja->header->curr_seg) = seg;
pos = 0 ;
}
GRN_IO_SEG_REF(ja->io, seg, addr);
if (!addr) {
grn_io_unlock(ja->io);
return GRN_NO_MEMORY_AVAILABLE;
}
*(grn_id *)(addr + pos) = id;
aligned_size = (element_size + sizeof (grn_id) - 1 ) & ~(sizeof (grn_id) - 1 );
if (pos + aligned_size < JA_SEGMENT_SIZE) {
*(grn_id *)(addr + pos + aligned_size) = GRN_ID_NIL;
}
SEGMENTS_AT(ja, seg) += aligned_size + sizeof (grn_id);
pos += sizeof (grn_id);
EINFO_ENC(einfo, seg, pos, element_size);
iw->segment = seg;
iw->addr = addr + pos;
*(ja->header->curr_pos) = pos + aligned_size;
grn_io_unlock(ja->io);
return GRN_SUCCESS;
} else {
uint32_t lseg = 0 , lseg_;
aligned_size = 1 << m;
if (ja->header->ngarbages[m - JA_W_EINFO] > JA_N_GARBAGES_TH) {
grn_ja_ginfo *ginfo = NULL;
uint32_t seg, pos, *gseg;
gseg = &ja->header->garbages[m - JA_W_EINFO];
while ((lseg_ = *gseg)) {
GRN_IO_SEG_REF(ja->io, lseg_, ginfo);
if (!ginfo) {
if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
grn_io_unlock(ja->io);
return GRN_NO_MEMORY_AVAILABLE;
}
if (ginfo->next || ginfo->nrecs > JA_N_GARBAGES_TH) {
seg = ginfo->recs[ginfo->tail].seg;
pos = ginfo->recs[ginfo->tail].pos;
GRN_IO_SEG_REF(ja->io, seg, addr);
if (!addr) {
if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
GRN_IO_SEG_UNREF(ja->io, lseg_);
grn_io_unlock(ja->io);
return GRN_NO_MEMORY_AVAILABLE;
}
EINFO_ENC(einfo, seg, pos, element_size);
iw->segment = seg;
iw->addr = addr + pos;
if (++ginfo->tail == JA_N_GARBAGES_IN_A_SEGMENT) { ginfo->tail = 0 ; }
ginfo->nrecs--;
ja->header->ngarbages[m - JA_W_EINFO]--;
if (!ginfo->nrecs) {
SEGMENTS_OFF(ja, *gseg);
*gseg = ginfo->next;
}
if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
GRN_IO_SEG_UNREF(ja->io, lseg_);
grn_io_unlock(ja->io);
return GRN_SUCCESS;
}
if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
if (!ginfo->next) {
GRN_IO_SEG_UNREF(ja->io, lseg_);
break ;
}
lseg = lseg_;
gseg = &ginfo->next;
}
}
vp = &ja->header->free_elements[m - JA_W_EINFO];
if (!vp->seg) {
uint i = 0 ;
while (SEGMENTS_AT(ja, i)) {
if (++i >= JA_N_DSEGMENTS) {
grn_io_unlock(ja->io);
return GRN_NO_MEMORY_AVAILABLE;
}
}
SEGMENTS_SEGRE_ON(ja, i, m);
vp->seg = i;
vp->pos = 0 ;
}
}
EINFO_ENC(einfo, vp->seg, vp->pos, element_size);
GRN_IO_SEG_REF(ja->io, vp->seg, addr);
if (!addr) {
grn_io_unlock(ja->io);
return GRN_NO_MEMORY_AVAILABLE;
}
iw->segment = vp->seg;
iw->addr = addr + vp->pos;
if ((vp->pos += aligned_size) == JA_SEGMENT_SIZE) {
vp->seg = 0 ;
vp->pos = 0 ;
}
iw->uncompressed_value = NULL;
grn_io_unlock(ja->io);
return GRN_SUCCESS;
}
}
static grn_rc
set_value(grn_ctx *ctx, grn_ja *ja, grn_id id, void *value, uint32_t value_len,
grn_ja_einfo *einfo)
{
grn_rc rc = GRN_SUCCESS;
grn_io_win iw;
if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
value_len >= ja->header->max_element_size) {
if ((rc = grn_ja_alloc(ctx, ja, id, value_len + sizeof (uint32_t), einfo, &iw))) {
return rc;
}
grn_memcpy(iw.addr, value, value_len);
memset((byte *)iw.addr + value_len, 0 , sizeof (uint32_t));
grn_io_win_unmap(&iw);
} else {
if ((rc = grn_ja_alloc(ctx, ja, id, value_len, einfo, &iw))) { return rc; }
grn_memcpy(iw.addr, value, value_len);
grn_io_win_unmap(&iw);
}
return rc;
}
static grn_rc
grn_ja_put_raw(grn_ctx *ctx, grn_ja *ja, grn_id id,
void *value, uint32_t value_len, int flags, uint64_t *cas)
{
int rc;
int64_t buf;
grn_io_win iw;
grn_ja_einfo einfo;
if ((flags & GRN_OBJ_SET_MASK) == GRN_OBJ_SET &&
value_len > 0 ) {
grn_io_win jw;
uint32_t old_len;
void *old_value;
grn_bool same_value = GRN_FALSE;
old_value = grn_ja_ref(ctx, ja, id, &jw, &old_len);
if (value_len == old_len && memcmp(value, old_value, value_len) == 0 ) {
same_value = GRN_TRUE;
}
grn_ja_unref(ctx, &jw);
if (same_value) {
return GRN_SUCCESS;
}
}
switch (flags & GRN_OBJ_SET_MASK) {
case GRN_OBJ_APPEND :
if (value_len) {
grn_io_win jw;
uint32_t old_len;
void *oldvalue = grn_ja_ref(ctx, ja, id, &jw, &old_len);
if (oldvalue) {
if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
old_len + value_len >= ja->header->max_element_size) {
if (old_len >= ja->header->max_element_size) {
byte *b = oldvalue;
uint32_t el = old_len - sizeof (uint32_t);
uint32_t pos = *((uint32_t *)(b + el));
GRN_ASSERT(pos < el);
if (el <= pos + value_len) {
uint32_t rest = el - pos;
grn_memcpy(b + pos, value, rest);
grn_memcpy(b, (byte *)value + rest, value_len - rest);
*((uint32_t *)(b + el)) = value_len - rest;
} else {
grn_memcpy(b + pos, value, value_len);
*((uint32_t *)(b + el)) = pos + value_len;
}
return GRN_SUCCESS;
} else {
if ((rc = grn_ja_alloc(ctx, ja, id,
value_len + old_len + sizeof (uint32_t),
&einfo, &iw))) {
grn_ja_unref(ctx, &jw);
return rc;
}
grn_memcpy(iw.addr, oldvalue, old_len);
grn_memcpy((byte *)iw.addr + old_len, value, value_len);
memset((byte *)iw.addr + old_len + value_len, 0 , sizeof (uint32_t));
grn_io_win_unmap(&iw);
}
} else {
if ((rc = grn_ja_alloc(ctx, ja, id, value_len + old_len, &einfo, &iw))) {
grn_ja_unref(ctx, &jw);
return rc;
}
grn_memcpy(iw.addr, oldvalue, old_len);
grn_memcpy((byte *)iw.addr + old_len, value, value_len);
grn_io_win_unmap(&iw);
}
grn_ja_unref(ctx, &jw);
} else {
set_value(ctx, ja, id, value, value_len, &einfo);
}
}
break ;
case GRN_OBJ_PREPEND :
if (value_len) {
grn_io_win jw;
uint32_t old_len;
void *oldvalue = grn_ja_ref(ctx, ja, id, &jw, &old_len);
if (oldvalue) {
if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
old_len + value_len >= ja->header->max_element_size) {
if (old_len >= ja->header->max_element_size) {
byte *b = oldvalue;
uint32_t el = old_len - sizeof (uint32_t);
uint32_t pos = *((uint32_t *)(b + el));
GRN_ASSERT(pos < el);
if (pos < value_len) {
uint32_t rest = value_len - pos;
grn_memcpy(b, (byte *)value + rest, pos);
grn_memcpy(b + el - rest, value, rest);
*((uint32_t *)(b + el)) = el - rest;
} else {
grn_memcpy(b + pos - value_len, value, value_len);
*((uint32_t *)(b + el)) = pos - value_len;
}
return GRN_SUCCESS;
} else {
if ((rc = grn_ja_alloc(ctx, ja, id,
value_len + old_len + sizeof (uint32_t),
&einfo, &iw))) {
grn_ja_unref(ctx, &jw);
return rc;
}
grn_memcpy(iw.addr, value, value_len);
grn_memcpy((byte *)iw.addr + value_len, oldvalue, old_len);
memset((byte *)iw.addr + value_len + old_len, 0 , sizeof (uint32_t));
grn_io_win_unmap(&iw);
}
} else {
if ((rc = grn_ja_alloc(ctx, ja, id, value_len + old_len, &einfo, &iw))) {
grn_ja_unref(ctx, &jw);
return rc;
}
grn_memcpy(iw.addr, value, value_len);
grn_memcpy((byte *)iw.addr + value_len, oldvalue, old_len);
grn_io_win_unmap(&iw);
}
grn_ja_unref(ctx, &jw);
} else {
set_value(ctx, ja, id, value, value_len, &einfo);
}
}
break ;
case GRN_OBJ_DECR :
if (value_len == sizeof (int64_t)) {
int64_t *v = (int64_t *)&buf;
*v = -(*(int64_t *)value);
value = v;
} else if (value_len == sizeof (int32_t)) {
int32_t *v = (int32_t *)&buf;
*v = -(*(int32_t *)value);
value = v;
} else {
return GRN_INVALID_ARGUMENT;
}
/* fallthru */
case GRN_OBJ_INCR :
{
grn_io_win jw;
uint32_t old_len;
void *oldvalue = grn_ja_ref(ctx, ja, id, &jw, &old_len);
if (oldvalue && old_len) {
grn_rc rc = GRN_INVALID_ARGUMENT;
if (old_len == sizeof (int64_t) && value_len == sizeof (int64_t)) {
(*(int64_t *)oldvalue) += (*(int64_t *)value);
rc = GRN_SUCCESS;
} else if (old_len == sizeof (int32_t) && value_len == sizeof (int32_t)) {
(*(int32_t *)oldvalue) += (*(int32_t *)value);
rc = GRN_SUCCESS;
}
grn_ja_unref(ctx, &jw);
return rc;
}
}
/* fallthru */
case GRN_OBJ_SET :
if (value_len) {
set_value(ctx, ja, id, value, value_len, &einfo);
} else {
memset(&einfo, 0 , sizeof (grn_ja_einfo));
}
break ;
default :
ERR(GRN_INVALID_ARGUMENT, "grn_ja_put_raw called with illegal flags value" );
return GRN_INVALID_ARGUMENT;
}
if ((rc = grn_ja_replace(ctx, ja, id, &einfo, cas))) {
if (!grn_io_lock(ctx, ja->io, grn_lock_timeout)) {
grn_ja_free(ctx, ja, &einfo);
grn_io_unlock(ja->io);
}
}
return rc;
}
grn_rc
grn_ja_putv(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_obj *vector, int flags)
{
grn_obj header, footer;
grn_rc rc = GRN_SUCCESS;
grn_section *vp;
int i, f = 0 , n = grn_vector_size(ctx, vector);
GRN_TEXT_INIT(&header, 0 );
GRN_TEXT_INIT(&footer, 0 );
grn_text_benc(ctx, &header, n);
for (i = 0 , vp = vector->u.v.sections; i < n; i++, vp++) {
grn_text_benc(ctx, &header, vp->length);
if (vp->weight || vp->domain) { f = 1 ; }
}
if (f) {
for (i = 0 , vp = vector->u.v.sections; i < n; i++, vp++) {
grn_text_benc(ctx, &footer, vp->weight);
grn_text_benc(ctx, &footer, vp->domain);
}
}
{
grn_io_win iw;
grn_ja_einfo einfo;
grn_obj *body = vector->u.v.body;
size_t sizeh = GRN_BULK_VSIZE(&header);
size_t sizev = body ? GRN_BULK_VSIZE(body) : 0 ;
size_t sizef = GRN_BULK_VSIZE(&footer);
if ((rc = grn_ja_alloc(ctx, ja, id, sizeh + sizev + sizef, &einfo, &iw))) { goto exit ; }
grn_memcpy(iw.addr, GRN_BULK_HEAD(&header), sizeh);
if (body) {
grn_memcpy((char *)iw.addr + sizeh, GRN_BULK_HEAD(body), sizev);
}
if (f) {
grn_memcpy((char *)iw.addr + sizeh + sizev, GRN_BULK_HEAD(&footer), sizef);
}
grn_io_win_unmap(&iw);
rc = grn_ja_replace(ctx, ja, id, &einfo, NULL);
}
exit :
GRN_OBJ_FIN(ctx, &footer);
GRN_OBJ_FIN(ctx, &header);
return rc;
}
uint32_t
grn_ja_size(grn_ctx *ctx, grn_ja *ja, grn_id id)
{
grn_ja_einfo *einfo = NULL, *ei;
uint32_t lseg, *pseg, pos, size;
lseg = id >> JA_W_EINFO_IN_A_SEGMENT;
pos = id & JA_M_EINFO_IN_A_SEGMENT;
pseg = &ja->header->esegs[lseg];
if (*pseg == JA_ESEG_VOID) {
ctx->rc = GRN_INVALID_ARGUMENT;
return 0 ;
}
GRN_IO_SEG_REF(ja->io, *pseg, einfo);
if (!einfo) {
ctx->rc = GRN_NO_MEMORY_AVAILABLE;
return 0 ;
}
ei = &einfo[pos];
if (ETINY_P(ei)) {
ETINY_DEC(ei, size);
} else {
if (EHUGE_P(ei)) {
size = ei->u.h.size;
} else {
size = (ei->u.n.c2 << 16 ) + ei->u.n.size;
}
}
GRN_IO_SEG_UNREF(ja->io, *pseg);
return size;
}
grn_rc
grn_ja_element_info(grn_ctx *ctx, grn_ja *ja, grn_id id,
uint64_t *cas, uint32_t *pos, uint32_t *size)
{
uint32_t pseg = ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
if (pseg == JA_ESEG_VOID) {
return GRN_INVALID_ARGUMENT;
} else {
grn_ja_einfo *einfo = NULL;
GRN_IO_SEG_REF(ja->io, pseg, einfo);
if (einfo) {
grn_ja_einfo *ei;
*cas = *((uint64_t *)&einfo[id & JA_M_EINFO_IN_A_SEGMENT]);
ei = (grn_ja_einfo *)cas;
if (ETINY_P(ei)) {
ETINY_DEC(ei, *size);
*pos = 0 ;
} else {
if (EHUGE_P(ei)) {
EHUGE_DEC_SIZE(ei, *size);
*pos = 0 ;
} else {
EINFO_DEC_POS_SIZE(ei, *pos, *size);
}
}
GRN_IO_SEG_UNREF(ja->io, pseg);
} else {
return GRN_INVALID_ARGUMENT;
}
}
return GRN_SUCCESS;
}
#define COMPRESSED_VALUE_META_FLAG(meta) ((meta) & 0 xf000000000000000)
#define COMPRESSED_VALUE_META_FLAG_RAW 0 x1000000000000000
#define COMPRESSED_VALUE_META_UNCOMPRESSED_LEN(meta) \
((meta) & 0 x0fffffffffffffff)
#define COMPRESS_THRESHOLD_BYTE 256
#define COMPRESS_PACKED_VALUE_SIZE_MAX 257
/* COMPRESS_THRESHOLD_BYTE - 1 + sizeof(uint64_t) = 257 */
#if defined (GRN_WITH_ZLIB) || defined (GRN_WITH_LZ4) || defined (GRN_WITH_ZSTD)
# define GRN_WITH_COMPRESSED
#endif
#ifdef GRN_WITH_COMPRESSED
static void *
grn_ja_ref_packed(grn_ctx *ctx,
grn_io_win *iw,
uint32_t *value_len,
void *raw_value,
uint32_t raw_value_len,
void **compressed_value,
uint32_t *compressed_value_len,
uint32_t *uncompressed_value_len)
{
uint64_t compressed_value_meta;
compressed_value_meta = *((uint64_t *)raw_value);
*compressed_value = (void *)(((uint64_t *)raw_value) + 1 );
*compressed_value_len = raw_value_len - sizeof (uint64_t);
*uncompressed_value_len =
COMPRESSED_VALUE_META_UNCOMPRESSED_LEN(compressed_value_meta);
switch (COMPRESSED_VALUE_META_FLAG(compressed_value_meta)) {
case COMPRESSED_VALUE_META_FLAG_RAW :
iw->uncompressed_value = NULL;
*value_len = *uncompressed_value_len;
return *compressed_value;
default :
return NULL;
}
}
static grn_rc
grn_ja_put_packed(grn_ctx *ctx,
grn_ja *ja,
grn_id id,
void *value,
uint32_t value_len,
int flags,
uint64_t *cas)
{
char *packed_value[COMPRESS_PACKED_VALUE_SIZE_MAX];
uint32_t packed_value_len;
uint64_t packed_value_meta;
packed_value_len = value_len + sizeof (uint64_t);
packed_value_meta = value_len | COMPRESSED_VALUE_META_FLAG_RAW;
*((uint64_t *)packed_value) = packed_value_meta;
memcpy(((uint64_t *)packed_value) + 1 ,
value,
value_len);
return grn_ja_put_raw(ctx,
ja,
id,
packed_value,
packed_value_len,
flags,
cas);
}
static void
grn_ja_compress_error(grn_ctx *ctx,
grn_ja *ja,
grn_id id,
grn_rc rc,
const char *message,
const char *detail)
{
char name[GRN_TABLE_MAX_KEY_SIZE];
int name_len;
if (ja->obj.id == GRN_ID_NIL) {
name[0 ] = '\0' ;
name_len = 0 ;
} else {
name_len = grn_obj_name(ctx, (grn_obj *)ja, name, GRN_TABLE_MAX_KEY_SIZE);
}
ERR(GRN_ZSTD_ERROR,
"[ja]%s: %s%.*s%s<%u>%s%s%s" ,
message,
name_len == 0 ? "" : "<" ,
name_len,
name,
name_len == 0 ? "" : ">: " ,
id,
detail ? " :<" : "" ,
detail ? detail : "" ,
detail ? ">" : "" );
}
#endif /* GRN_WITH_COMPRESSED */
#ifdef GRN_WITH_ZLIB
#include <zlib.h>
static const char *
grn_zrc_to_string(int zrc)
{
switch (zrc) {
case Z_OK :
return "OK" ;
case Z_STREAM_END :
return "Stream is end" ;
case Z_NEED_DICT :
return "Need dictionary" ;
case Z_ERRNO :
return "See errno" ;
case Z_STREAM_ERROR :
return "Stream error" ;
case Z_DATA_ERROR :
return "Data error" ;
case Z_MEM_ERROR :
return "Memory error" ;
case Z_BUF_ERROR :
return "Buffer error" ;
case Z_VERSION_ERROR :
return "Version error" ;
default :
return "Unknown" ;
}
}
static void *
grn_ja_ref_zlib(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
{
z_stream zstream;
void *raw_value;
uint32_t raw_value_len;
void *zvalue;
uint32_t zvalue_len;
void *unpacked_value;
uint32_t uncompressed_value_len;
int zrc;
if (!(raw_value = grn_ja_ref_raw(ctx, ja, id, iw, &raw_value_len))) {
iw->uncompressed_value = NULL;
*value_len = 0 ;
return NULL;
}
unpacked_value = grn_ja_ref_packed(ctx,
iw, value_len,
raw_value, raw_value_len,
&zvalue, &zvalue_len,
&uncompressed_value_len);
if (unpacked_value) {
return unpacked_value;
}
zstream.next_in = (Bytef *)zvalue;
zstream.avail_in = zvalue_len;
zstream.zalloc = Z_NULL;
zstream.zfree = Z_NULL;
zrc = inflateInit2(&zstream, 15 /* windowBits */);
if (zrc != Z_OK) {
iw->uncompressed_value = NULL;
*value_len = 0 ;
grn_ja_compress_error(ctx,
ja,
id,
GRN_ZLIB_ERROR,
"[zlib] failed to decompress: initialize" ,
grn_zrc_to_string(zrc));
return NULL;
}
if (!(iw->uncompressed_value = GRN_MALLOC(uncompressed_value_len))) {
inflateEnd(&zstream);
iw->uncompressed_value = NULL;
*value_len = 0 ;
grn_ja_compress_error(ctx,
ja,
id,
GRN_ZLIB_ERROR,
"[zlib] failed to decompress: allocate buffer" ,
NULL);
return NULL;
}
zstream.next_out = (Bytef *)iw->uncompressed_value;
zstream.avail_out = uncompressed_value_len;
zrc = inflate(&zstream, Z_FINISH);
if (zrc != Z_STREAM_END) {
inflateEnd(&zstream);
GRN_FREE(iw->uncompressed_value);
iw->uncompressed_value = NULL;
*value_len = 0 ;
grn_ja_compress_error(ctx,
ja,
id,
GRN_ZLIB_ERROR,
"[zlib] failed to decompress: finish" ,
grn_zrc_to_string(zrc));
return NULL;
}
*value_len = zstream.total_out;
zrc = inflateEnd(&zstream);
if (zrc != Z_OK) {
GRN_FREE(iw->uncompressed_value);
iw->uncompressed_value = NULL;
*value_len = 0 ;
grn_ja_compress_error(ctx,
ja,
id,
GRN_ZLIB_ERROR,
"[zlib] failed to decompress: end" ,
grn_zrc_to_string(zrc));
return NULL;
}
return iw->uncompressed_value;
}
#endif /* GRN_WITH_ZLIB */
#ifdef GRN_WITH_LZ4
#include <lz4.h>
# if (LZ4_VERSION_MAJOR == 1 && LZ4_VERSION_MINOR < 6 )
# define LZ4_compress_default(source, dest, source_size, max_dest_size) \
LZ4_compress((source), (dest), (source_size))
# endif
static void *
grn_ja_ref_lz4(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
{
void *raw_value;
uint32_t raw_value_len;
void *lz4_value;
uint32_t lz4_value_len;
void *unpacked_value;
uint32_t uncompressed_value_len;
if (!(raw_value = grn_ja_ref_raw(ctx, ja, id, iw, &raw_value_len))) {
iw->uncompressed_value = NULL;
*value_len = 0 ;
return NULL;
}
unpacked_value = grn_ja_ref_packed(ctx,
iw, value_len,
raw_value, raw_value_len,
&lz4_value, &lz4_value_len,
&uncompressed_value_len);
if (unpacked_value) {
return unpacked_value;
}
if (!(iw->uncompressed_value = GRN_MALLOC(uncompressed_value_len))) {
iw->uncompressed_value = NULL;
*value_len = 0 ;
return NULL;
}
if (LZ4_decompress_safe((const char *)(lz4_value),
(char *)(iw->uncompressed_value),
lz4_value_len,
uncompressed_value_len) < 0 ) {
GRN_FREE(iw->uncompressed_value);
iw->uncompressed_value = NULL;
*value_len = 0 ;
grn_ja_compress_error(ctx,
ja,
id,
GRN_LZ4_ERROR,
"[lz4] failed to decompress" ,
NULL);
return NULL;
}
*value_len = uncompressed_value_len;
return iw->uncompressed_value;
}
#endif /* GRN_WITH_LZ4 */
#ifdef GRN_WITH_ZSTD
#include <zstd.h>
static void *
grn_ja_ref_zstd(grn_ctx *ctx,
grn_ja *ja,
grn_id id,
grn_io_win *iw,
uint32_t *value_len)
{
void *raw_value;
uint32_t raw_value_len;
void *zstd_value;
uint32_t zstd_value_len;
void *unpacked_value;
uint32_t uncompressed_value_len;
size_t written_len;
if (!(raw_value = grn_ja_ref_raw(ctx, ja, id, iw, &raw_value_len))) {
iw->uncompressed_value = NULL;
*value_len = 0 ;
return NULL;
}
unpacked_value = grn_ja_ref_packed(ctx,
iw, value_len,
raw_value, raw_value_len,
&zstd_value, &zstd_value_len,
&uncompressed_value_len);
if (unpacked_value) {
return unpacked_value;
}
if (!(iw->uncompressed_value = GRN_MALLOC(uncompressed_value_len))) {
iw->uncompressed_value = NULL;
*value_len = 0 ;
return NULL;
}
written_len = ZSTD_decompress((char *)(iw->uncompressed_value),
uncompressed_value_len,
zstd_value,
zstd_value_len);
if (ZSTD_isError(written_len)) {
GRN_FREE(iw->uncompressed_value);
iw->uncompressed_value = NULL;
*value_len = 0 ;
grn_ja_compress_error(ctx,
ja,
id,
GRN_ZSTD_ERROR,
"[zstd] failed to decompress" ,
ZSTD_getErrorName(written_len));
return NULL;
}
*value_len = uncompressed_value_len;
return iw->uncompressed_value;
}
#endif /* GRN_WITH_ZSTD */
void *
grn_ja_ref(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
{
switch (ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
#ifdef GRN_WITH_ZLIB
case GRN_OBJ_COMPRESS_ZLIB :
return grn_ja_ref_zlib(ctx, ja, id, iw, value_len);
#endif /* GRN_WITH_ZLIB */
#ifdef GRN_WITH_LZ4
case GRN_OBJ_COMPRESS_LZ4 :
return grn_ja_ref_lz4(ctx, ja, id, iw, value_len);
#endif /* GRN_WITH_LZ4 */
#ifdef GRN_WITH_ZSTD
case GRN_OBJ_COMPRESS_ZSTD :
return grn_ja_ref_zstd(ctx, ja, id, iw, value_len);
#endif /* GRN_WITH_ZSTD */
default :
return grn_ja_ref_raw(ctx, ja, id, iw, value_len);
}
}
grn_obj *
grn_ja_get_value(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_obj *value)
{
void *v;
uint32_t len;
grn_io_win iw;
if (!value) {
if (!(value = grn_obj_open(ctx, GRN_BULK, 0 , 0 ))) {
ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed" );
goto exit ;
}
}
if ((v = grn_ja_ref(ctx, ja, id, &iw, &len))) {
if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
len > ja->header->max_element_size) {
byte *b = v;
uint32_t el = len - sizeof (uint32_t);
uint32_t pos = *((uint32_t *)(b + el));
GRN_ASSERT(pos < el);
grn_bulk_write(ctx, value, (char *)(b + pos), el - pos);
grn_bulk_write(ctx, value, (char *)(b), pos);
} else {
grn_bulk_write(ctx, value, v, len);
}
grn_ja_unref(ctx, &iw);
}
exit :
return value;
}
#ifdef GRN_WITH_ZLIB
inline static grn_rc
grn_ja_put_zlib(grn_ctx *ctx, grn_ja *ja, grn_id id,
void *value, uint32_t value_len, int flags, uint64_t *cas)
{
grn_rc rc;
z_stream zstream;
void *zvalue;
int zvalue_len;
int zrc;
if (value_len == 0 ) {
return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
}
if (value_len < COMPRESS_THRESHOLD_BYTE) {
return grn_ja_put_packed(ctx, ja, id, value, value_len, flags, cas);
}
zstream.next_in = value;
zstream.avail_in = value_len;
zstream.zalloc = Z_NULL;
zstream.zfree = Z_NULL;
zrc = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
15 /* windowBits */,
8 /* memLevel */,
Z_DEFAULT_STRATEGY);
if (zrc != Z_OK) {
grn_ja_compress_error(ctx,
ja,
id,
GRN_ZLIB_ERROR,
"[zlib] failed to compress: initialize" ,
grn_zrc_to_string(zrc));
return ctx->rc;
}
zvalue_len = deflateBound(&zstream, value_len);
if (!(zvalue = GRN_MALLOC(zvalue_len + sizeof (uint64_t)))) {
deflateEnd(&zstream);
grn_ja_compress_error(ctx,
ja,
id,
GRN_ZLIB_ERROR,
"[zlib] failed to allocate compress buffer" ,
NULL);
return ctx->rc;
}
zstream.next_out = (Bytef *)(((uint64_t *)zvalue) + 1 );
zstream.avail_out = zvalue_len;
zrc = deflate(&zstream, Z_FINISH);
if (zrc != Z_STREAM_END) {
deflateEnd(&zstream);
GRN_FREE(zvalue);
grn_ja_compress_error(ctx,
ja,
id,
GRN_ZLIB_ERROR,
"[zlib] failed to compress: finish" ,
grn_zrc_to_string(zrc));
return ctx->rc;
}
zvalue_len = zstream.total_out;
zrc = deflateEnd(&zstream);
if (zrc != Z_OK) {
GRN_FREE(zvalue);
grn_ja_compress_error(ctx,
ja,
id,
GRN_ZLIB_ERROR,
"[zlib] failed to compress: end" ,
grn_zrc_to_string(zrc));
return ctx->rc;
}
*(uint64_t *)zvalue = value_len;
rc = grn_ja_put_raw(ctx, ja, id, zvalue, zvalue_len + sizeof (uint64_t), flags, cas);
GRN_FREE(zvalue);
return rc;
}
#endif /* GRN_WITH_ZLIB */
#ifdef GRN_WITH_LZ4
inline static grn_rc
grn_ja_put_lz4(grn_ctx *ctx, grn_ja *ja, grn_id id,
void *value, uint32_t value_len, int flags, uint64_t *cas)
{
grn_rc rc;
void *packed_value;
int packed_value_len_max;
int packed_value_len_real;
char *lz4_value;
int lz4_value_len_max;
int lz4_value_len_real;
if (value_len == 0 ) {
return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
}
if (value_len < COMPRESS_THRESHOLD_BYTE) {
return grn_ja_put_packed(ctx, ja, id, value, value_len, flags, cas);
}
if (value_len > (uint32_t)LZ4_MAX_INPUT_SIZE) {
uint64_t packed_value_meta;
packed_value_len_real = value_len + sizeof (uint64_t);
packed_value = GRN_MALLOC(packed_value_len_real);
if (!packed_value) {
grn_ja_compress_error(ctx,
ja,
id,
GRN_LZ4_ERROR,
"[lz4] failed to allocate packed buffer" ,
NULL);
return ctx->rc;
}
packed_value_meta = value_len | COMPRESSED_VALUE_META_FLAG_RAW;
*((uint64_t *)packed_value) = packed_value_meta;
memcpy(((uint64_t *)packed_value) + 1 ,
value,
value_len);
rc = grn_ja_put_raw(ctx,
ja,
id,
packed_value,
packed_value_len_real,
flags,
cas);
GRN_FREE(packed_value);
return rc;
}
lz4_value_len_max = LZ4_compressBound(value_len);
packed_value_len_max = lz4_value_len_max + sizeof (uint64_t);
if (!(packed_value = GRN_MALLOC(packed_value_len_max))) {
grn_ja_compress_error(ctx,
ja,
id,
GRN_LZ4_ERROR,
"[lz4] failed to allocate compress buffer" ,
NULL);
return ctx->rc;
}
lz4_value = (char *)((uint64_t *)packed_value + 1 );
lz4_value_len_real = LZ4_compress_default((const char *)value,
lz4_value,
value_len,
lz4_value_len_max);
if (lz4_value_len_real <= 0 ) {
GRN_FREE(packed_value);
grn_ja_compress_error(ctx,
ja,
id,
GRN_LZ4_ERROR,
"[lz4] failed to compress" ,
NULL);
return ctx->rc;
}
*(uint64_t *)packed_value = value_len;
packed_value_len_real = lz4_value_len_real + sizeof (uint64_t);
rc = grn_ja_put_raw(ctx,
ja,
id,
packed_value,
packed_value_len_real,
flags,
cas);
GRN_FREE(packed_value);
return rc;
}
#endif /* GRN_WITH_LZ4 */
#ifdef GRN_WITH_ZSTD
inline static grn_rc
grn_ja_put_zstd(grn_ctx *ctx,
grn_ja *ja,
grn_id id,
void *value,
uint32_t value_len,
int flags,
uint64_t *cas)
{
grn_rc rc;
void *packed_value;
int packed_value_len_max;
int packed_value_len_real;
void *zstd_value;
int zstd_value_len_max;
int zstd_value_len_real;
int zstd_compression_level = 3 ;
if (value_len == 0 ) {
return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
}
if (value_len < COMPRESS_THRESHOLD_BYTE) {
return grn_ja_put_packed(ctx, ja, id, value, value_len, flags, cas);
}
zstd_value_len_max = ZSTD_compressBound(value_len);
packed_value_len_max = zstd_value_len_max + sizeof (uint64_t);
if (!(packed_value = GRN_MALLOC(packed_value_len_max))) {
grn_ja_compress_error(ctx,
ja,
id,
GRN_ZSTD_ERROR,
"[zstd] failed to allocate compress buffer" ,
NULL);
return ctx->rc;
}
zstd_value = ((uint64_t *)packed_value) + 1 ;
zstd_value_len_real = ZSTD_compress(zstd_value, zstd_value_len_max,
value, value_len,
zstd_compression_level);
if (ZSTD_isError(zstd_value_len_real)) {
grn_ja_compress_error(ctx,
ja,
id,
GRN_ZSTD_ERROR,
"[zstd] failed to compress" ,
ZSTD_getErrorName(zstd_value_len_real));
return ctx->rc;
}
*(uint64_t *)packed_value = value_len;
packed_value_len_real = zstd_value_len_real + sizeof (uint64_t);
rc = grn_ja_put_raw(ctx,
ja,
id,
packed_value,
packed_value_len_real,
flags,
cas);
GRN_FREE(packed_value);
return rc;
}
#endif /* GRN_WITH_ZSTD */
grn_rc
grn_ja_put(grn_ctx *ctx, grn_ja *ja, grn_id id, void *value, uint32_t value_len,
int flags, uint64_t *cas)
{
switch (ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
#ifdef GRN_WITH_ZLIB
case GRN_OBJ_COMPRESS_ZLIB :
return grn_ja_put_zlib(ctx, ja, id, value, value_len, flags, cas);
#endif /* GRN_WITH_ZLIB */
#ifdef GRN_WITH_LZ4
case GRN_OBJ_COMPRESS_LZ4 :
return grn_ja_put_lz4(ctx, ja, id, value, value_len, flags, cas);
#endif /* GRN_WITH_LZ4 */
#ifdef GRN_WITH_ZSTD
case GRN_OBJ_COMPRESS_ZSTD :
return grn_ja_put_zstd(ctx, ja, id, value, value_len, flags, cas);
#endif /* GRN_WITH_ZSTD */
default :
return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
}
}
static grn_rc
grn_ja_defrag_seg(grn_ctx *ctx, grn_ja *ja, uint32_t seg)
{
byte *v = NULL, *ve;
uint32_t element_size, cum = 0 , *seginfo = &SEGMENTS_AT(ja,seg), sum;
sum = (*seginfo & ~SEG_MASK);
GRN_IO_SEG_REF(ja->io, seg, v);
if (!v) { return GRN_NO_MEMORY_AVAILABLE; }
ve = v + JA_SEGMENT_SIZE;
while (v < ve && cum < sum) {
grn_id id = *((grn_id *)v);
if (!id) { break ; }
if (id & DELETED) {
element_size = (id & ~DELETED);
} else {
uint64_t cas;
uint32_t pos;
if (grn_ja_element_info(ctx, ja, id, &cas, &pos, &element_size)) { break ; }
if (v + sizeof (uint32_t) != ve - JA_SEGMENT_SIZE + pos) {
GRN_LOG(ctx, GRN_LOG_WARNING,
"dseges[%d] = pos unmatch (%d != %" GRN_FMT_LLD ")" ,
seg, pos, (long long int )(v + sizeof (uint32_t) + JA_SEGMENT_SIZE - ve));
break ;
}
if (grn_ja_put(ctx, ja, id, v + sizeof (uint32_t), element_size, GRN_OBJ_SET, &cas)) {
GRN_LOG(ctx, GRN_LOG_WARNING,
"dseges[%d] = put failed (%d)" , seg, id);
break ;
}
element_size = (element_size + sizeof (grn_id) - 1 ) & ~(sizeof (grn_id) - 1 );
cum += sizeof (uint32_t) + element_size;
}
v += sizeof (uint32_t) + element_size;
}
if (*seginfo) {
GRN_LOG(ctx, GRN_LOG_WARNING, "dseges[%d] = %d after defrag" , seg, (*seginfo & ~SEG_MASK));
}
GRN_IO_SEG_UNREF(ja->io, seg);
return GRN_SUCCESS;
}
int
grn_ja_defrag(grn_ctx *ctx, grn_ja *ja, int threshold)
{
int nsegs = 0 ;
uint32_t seg, ts = 1 U << (GRN_JA_W_SEGMENT - threshold);
for (seg = 0 ; seg < JA_N_DSEGMENTS; seg++) {
if (seg == *(ja->header->curr_seg)) { continue ; }
if (((SEGMENTS_AT(ja, seg) & SEG_MASK) == SEG_SEQ) &&
((SEGMENTS_AT(ja, seg) & ~SEG_MASK) < ts)) {
if (!grn_ja_defrag_seg(ctx, ja, seg)) { nsegs++; }
}
}
return nsegs;
}
void
grn_ja_check(grn_ctx *ctx, grn_ja *ja)
{
char buf[8 ];
uint32_t seg;
struct grn_ja_header *h = ja->header;
GRN_OUTPUT_ARRAY_OPEN("RESULT" , 8 );
GRN_OUTPUT_MAP_OPEN("SUMMARY" , 8 );
GRN_OUTPUT_CSTR("flags" );
grn_itoh(h->flags, buf, 8 );
GRN_OUTPUT_STR(buf, 8 );
GRN_OUTPUT_CSTR("curr seg" );
GRN_OUTPUT_INT64(*(h->curr_seg));
GRN_OUTPUT_CSTR("curr pos" );
GRN_OUTPUT_INT64(*(h->curr_pos));
GRN_OUTPUT_CSTR("max_element_size" );
GRN_OUTPUT_INT64(h->max_element_size);
GRN_OUTPUT_CSTR("segregate_threshold" );
GRN_OUTPUT_INT64(h->segregate_threshold);
GRN_OUTPUT_CSTR("n_element_variation" );
GRN_OUTPUT_INT64(h->n_element_variation);
GRN_OUTPUT_MAP_CLOSE();
GRN_OUTPUT_ARRAY_OPEN("DETAIL" , -1 );
for (seg = 0 ; seg < JA_N_DSEGMENTS; seg++) {
int dseg = SEGMENTS_AT(ja, seg);
if (dseg) {
GRN_OUTPUT_MAP_OPEN("SEG" , -1 );
GRN_OUTPUT_CSTR("seg id" );
GRN_OUTPUT_INT64(seg);
GRN_OUTPUT_CSTR("seg type" );
GRN_OUTPUT_INT64((dseg & SEG_MASK)>>28 );
GRN_OUTPUT_CSTR("seg value" );
GRN_OUTPUT_INT64(dseg & ~SEG_MASK);
if ((dseg & SEG_MASK) == SEG_SEQ) {
byte *v = NULL, *ve;
uint32_t element_size, cum = 0 , sum = dseg & ~SEG_MASK;
uint32_t n_del_elements = 0 , n_elements = 0 , s_del_elements = 0 , s_elements = 0 ;
GRN_IO_SEG_REF(ja->io, seg, v);
if (v) {
/*
GRN_OUTPUT_CSTR ( " seg seq " ) ;
GRN_OUTPUT_ARRAY_OPEN ( " SEQ " , - 1 ) ;
*/
ve = v + JA_SEGMENT_SIZE;
while (v < ve && cum < sum) {
grn_id id = *((grn_id *)v);
/*
GRN_OUTPUT_MAP_OPEN ( " ENTRY " , - 1 ) ;
GRN_OUTPUT_CSTR ( " id " ) ;
GRN_OUTPUT_INT64 ( id ) ;
*/
if (!id) { break ; }
if (id & DELETED) {
element_size = (id & ~DELETED);
n_del_elements++;
s_del_elements += element_size;
} else {
element_size = grn_ja_size(ctx, ja, id);
element_size = (element_size + sizeof (grn_id) - 1 ) & ~(sizeof (grn_id) - 1 );
cum += sizeof (uint32_t) + element_size;
n_elements++;
s_elements += sizeof (uint32_t) + element_size;
}
v += sizeof (uint32_t) + element_size;
/*
GRN_OUTPUT_CSTR ( " size " ) ;
GRN_OUTPUT_INT64 ( element_size ) ;
GRN_OUTPUT_CSTR ( " cum " ) ;
GRN_OUTPUT_INT64 ( cum ) ;
GRN_OUTPUT_MAP_CLOSE ( ) ;
*/
}
GRN_IO_SEG_UNREF(ja->io, seg);
/*
GRN_OUTPUT_ARRAY_CLOSE ( ) ;
*/
GRN_OUTPUT_CSTR("n_elements" );
GRN_OUTPUT_INT64(n_elements);
GRN_OUTPUT_CSTR("s_elements" );
GRN_OUTPUT_INT64(s_elements);
GRN_OUTPUT_CSTR("n_del_elements" );
GRN_OUTPUT_INT64(n_del_elements);
GRN_OUTPUT_CSTR("s_del_elements" );
GRN_OUTPUT_INT64(s_del_elements);
if (cum != sum) {
GRN_OUTPUT_CSTR("cum gap" );
GRN_OUTPUT_INT64(cum - sum);
}
}
}
GRN_OUTPUT_MAP_CLOSE();
}
}
GRN_OUTPUT_ARRAY_CLOSE();
GRN_OUTPUT_ARRAY_CLOSE();
}
/* grn_ja_reader */
grn_rc
grn_ja_reader_init(grn_ctx *ctx, grn_ja_reader *reader, grn_ja *ja)
{
reader->ja = ja;
reader->einfo_seg_id = JA_ESEG_VOID;
reader->ref_avail = GRN_FALSE;
reader->ref_seg_id = JA_ESEG_VOID;
reader->ref_seg_ids = NULL;
reader->nref_seg_ids = 0 ;
reader->ref_seg_ids_size = 0 ;
reader->body_seg_id = JA_ESEG_VOID;
reader->body_seg_addr = NULL;
reader->packed_buf = NULL;
reader->packed_buf_size = 0 ;
#ifdef GRN_WITH_ZLIB
if (reader->ja->header->flags & GRN_OBJ_COMPRESS_ZLIB) {
z_stream *new_stream = GRN_MALLOCN(z_stream, 1 );
if (!new_stream) {
return GRN_NO_MEMORY_AVAILABLE;
}
new_stream->zalloc = NULL;
new_stream->zfree = NULL;
new_stream->opaque = NULL;
if (inflateInit2(new_stream, 15 ) != Z_OK) {
GRN_FREE(new_stream);
return GRN_ZLIB_ERROR;
}
reader->stream = new_stream;
}
#endif /* GRN_WITH_ZLIB */
return GRN_SUCCESS;
}
grn_rc
grn_ja_reader_fin(grn_ctx *ctx, grn_ja_reader *reader)
{
grn_rc rc = GRN_SUCCESS;
if (reader->einfo_seg_id != JA_ESEG_VOID) {
GRN_IO_SEG_UNREF(reader->ja->io, reader->einfo_seg_id);
}
if (reader->ref_seg_ids) {
grn_ja_reader_unref(ctx, reader);
GRN_FREE(reader->ref_seg_ids);
}
if (reader->body_seg_addr) {
GRN_IO_SEG_UNREF(reader->ja->io, reader->body_seg_id);
}
if (reader->packed_buf) {
GRN_FREE(reader->packed_buf);
}
#ifdef GRN_WITH_ZLIB
if (reader->ja->header->flags & GRN_OBJ_COMPRESS_ZLIB) {
if (reader->stream) {
if (inflateEnd((z_stream *)reader->stream) != Z_OK) {
rc = GRN_UNKNOWN_ERROR;
}
GRN_FREE(reader->stream);
}
}
#endif /* GRN_WITH_ZLIB */
return rc;
}
grn_rc
grn_ja_reader_open(grn_ctx *ctx, grn_ja *ja, grn_ja_reader **reader)
{
grn_rc rc;
grn_ja_reader *new_reader = GRN_MALLOCN(grn_ja_reader, 1 );
if (!new_reader) {
return GRN_NO_MEMORY_AVAILABLE;
}
rc = grn_ja_reader_init(ctx, new_reader, ja);
if (rc != GRN_SUCCESS) {
GRN_FREE(new_reader);
return rc;
}
*reader = new_reader;
return GRN_SUCCESS;
}
grn_rc
grn_ja_reader_close(grn_ctx *ctx, grn_ja_reader *reader)
{
grn_rc rc = grn_ja_reader_fin(ctx, reader);
GRN_FREE(reader);
return rc;
}
#ifdef GRN_WITH_COMPRESSED
/* grn_ja_reader_seek_compressed() prepares to access a compressed value. */
static grn_rc
grn_ja_reader_seek_compressed(grn_ctx *ctx, grn_ja_reader *reader, grn_id id)
{
grn_ja_einfo *einfo;
void *seg_addr;
uint32_t seg_id = reader->ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
if (seg_id == JA_ESEG_VOID) {
return GRN_INVALID_ARGUMENT;
}
if (seg_id != reader->einfo_seg_id) {
GRN_IO_SEG_REF(reader->ja->io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
if (reader->einfo_seg_id != JA_ESEG_VOID) {
GRN_IO_SEG_UNREF(reader->ja->io, reader->einfo_seg_id);
}
reader->einfo_seg_id = seg_id;
reader->einfo_seg_addr = seg_addr;
}
einfo = (grn_ja_einfo *)reader->einfo_seg_addr;
einfo += id & JA_M_EINFO_IN_A_SEGMENT;
reader->einfo = einfo;
/* ETINY_P(einfo) is always false because the original size needs 8 bytes. */
if (EHUGE_P(einfo)) {
EHUGE_DEC(einfo, seg_id, reader->packed_size);
reader->body_seg_offset = 0 ;
} else {
EINFO_DEC(einfo, seg_id, reader->body_seg_offset, reader->packed_size);
}
if (seg_id != reader->body_seg_id) {
GRN_IO_SEG_REF(reader->ja->io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
if (reader->body_seg_addr) {
GRN_IO_SEG_UNREF(reader->ja->io, reader->body_seg_id);
}
reader->body_seg_id = seg_id;
reader->body_seg_addr = seg_addr;
}
seg_addr = (char *)reader->body_seg_addr + reader->body_seg_offset;
reader->value_size = (uint32_t)*(uint64_t *)seg_addr;
return GRN_SUCCESS;
}
#endif /* GRN_WITH_COMPRESSED */
/* grn_ja_reader_seek_raw() prepares to access a value. */
static grn_rc
grn_ja_reader_seek_raw(grn_ctx *ctx, grn_ja_reader *reader, grn_id id)
{
grn_ja_einfo *einfo;
void *seg_addr;
uint32_t seg_id = reader->ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
if (seg_id == JA_ESEG_VOID) {
return GRN_INVALID_ARGUMENT;
}
if (seg_id != reader->einfo_seg_id) {
GRN_IO_SEG_REF(reader->ja->io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
if (reader->einfo_seg_id != JA_ESEG_VOID) {
GRN_IO_SEG_UNREF(reader->ja->io, reader->einfo_seg_id);
}
reader->einfo_seg_id = seg_id;
reader->einfo_seg_addr = seg_addr;
}
einfo = (grn_ja_einfo *)reader->einfo_seg_addr;
einfo += id & JA_M_EINFO_IN_A_SEGMENT;
reader->einfo = einfo;
if (ETINY_P(einfo)) {
ETINY_DEC(einfo, reader->value_size);
reader->ref_avail = GRN_FALSE;
} else {
if (EHUGE_P(einfo)) {
EHUGE_DEC(einfo, seg_id, reader->value_size);
reader->ref_avail = GRN_FALSE;
} else {
EINFO_DEC(einfo, seg_id, reader->body_seg_offset, reader->value_size);
reader->ref_avail = GRN_TRUE;
}
if (reader->body_seg_addr) {
if (seg_id != reader->body_seg_id) {
GRN_IO_SEG_UNREF(reader->ja->io, reader->body_seg_id);
reader->body_seg_addr = NULL;
}
}
reader->body_seg_id = seg_id;
}
return GRN_SUCCESS;
}
grn_rc
grn_ja_reader_seek(grn_ctx *ctx, grn_ja_reader *reader, grn_id id)
{
switch (reader->ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
#ifdef GRN_WITH_ZLIB
case GRN_OBJ_COMPRESS_ZLIB :
return grn_ja_reader_seek_compressed(ctx, reader, id);
#endif /* GRN_WITH_ZLIB */
#ifdef GRN_WITH_LZ4
case GRN_OBJ_COMPRESS_LZ4 :
return grn_ja_reader_seek_compressed(ctx, reader, id);
#endif /* GRN_WITH_LZ4 */
#ifdef GRN_WITH_ZSTD
case GRN_OBJ_COMPRESS_ZSTD :
return grn_ja_reader_seek_compressed(ctx, reader, id);
#endif /* GRN_WITH_ZSTD */
default :
return grn_ja_reader_seek_raw(ctx, reader, id);
}
}
grn_rc
grn_ja_reader_ref(grn_ctx *ctx, grn_ja_reader *reader, void **addr)
{
if (!reader->ref_avail) {
return GRN_INVALID_ARGUMENT;
}
if (reader->body_seg_id != reader->ref_seg_id) {
void *seg_addr;
if (reader->nref_seg_ids == reader->ref_seg_ids_size) {
size_t n_bytes;
uint32_t new_size, *new_seg_ids;
if (reader->ref_seg_ids_size == 0 ) {
new_size = GRN_JA_READER_INITIAL_REF_SEG_IDS_SIZE;
} else {
new_size = reader->ref_seg_ids_size * 2 ;
}
n_bytes = sizeof (uint32_t) * new_size;
new_seg_ids = (uint32_t *)GRN_REALLOC(reader->ref_seg_ids, n_bytes);
if (!new_seg_ids) {
return GRN_NO_MEMORY_AVAILABLE;
}
reader->ref_seg_ids = new_seg_ids;
reader->ref_seg_ids_size = new_size;
}
GRN_IO_SEG_REF(reader->ja->io, reader->body_seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
reader->ref_seg_id = reader->body_seg_id;
reader->ref_seg_addr = seg_addr;
reader->ref_seg_ids[reader->nref_seg_ids++] = reader->body_seg_id;
}
*addr = (char *)reader->ref_seg_addr + reader->body_seg_offset;
return GRN_SUCCESS;
}
grn_rc
grn_ja_reader_unref(grn_ctx *ctx, grn_ja_reader *reader)
{
uint32_t i;
for (i = 0 ; i < reader->nref_seg_ids; i++) {
GRN_IO_SEG_UNREF(reader->ja->io, reader->ref_seg_ids[i]);
}
reader->ref_seg_id = JA_ESEG_VOID;
reader->nref_seg_ids = 0 ;
return GRN_FUNCTION_NOT_IMPLEMENTED;
}
#ifdef GRN_WITH_ZLIB
/* grn_ja_reader_read_zlib() reads a value compressed with zlib. */
static grn_rc
grn_ja_reader_read_zlib(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
{
uLong dest_size = reader->value_size;
z_stream *stream = (z_stream *)reader->stream;
grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
if (EHUGE_P(einfo)) {
/* TODO: Use z_stream to avoid copy. */
grn_io *io = reader->ja->io;
void *seg_addr;
char *packed_ptr;
uint32_t size, seg_id;
if (reader->packed_size > reader->packed_buf_size) {
void *new_buf = GRN_REALLOC(reader->packed_buf, reader->packed_size);
if (!new_buf) {
return GRN_NO_MEMORY_AVAILABLE;
}
reader->packed_buf = new_buf;
reader->packed_buf_size = reader->packed_size;
}
packed_ptr = (char *)reader->packed_buf;
grn_memcpy(packed_ptr, (char *)reader->body_seg_addr + sizeof (uint64_t),
io->header->segment_size - sizeof (uint64_t));
packed_ptr += io->header->segment_size - sizeof (uint64_t);
size = reader->packed_size - (io->header->segment_size - sizeof (uint64_t));
seg_id = reader->body_seg_id + 1 ;
while (size > io->header->segment_size) {
GRN_IO_SEG_REF(io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
grn_memcpy(packed_ptr, seg_addr, io->header->segment_size);
GRN_IO_SEG_UNREF(io, seg_id);
seg_id++;
size -= io->header->segment_size;
packed_ptr += io->header->segment_size;
}
GRN_IO_SEG_REF(io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
grn_memcpy(packed_ptr, seg_addr, size);
GRN_IO_SEG_UNREF(io, seg_id);
seg_id++;
if (uncompress((Bytef *)buf, &dest_size, (Bytef *)reader->packed_buf,
reader->packed_size - sizeof (uint64_t)) != Z_OK) {
return GRN_ZLIB_ERROR;
}
if (dest_size != reader->value_size) {
return GRN_ZLIB_ERROR;
}
} else {
char *packed_addr = (char *)reader->body_seg_addr;
packed_addr += reader->body_seg_offset + sizeof (uint64_t);
if (inflateReset(stream) != Z_OK) {
return GRN_ZLIB_ERROR;
}
stream->next_in = (Bytef *)packed_addr;
stream->avail_in = reader->packed_size - sizeof (uint64_t);
stream->next_out = (Bytef *)buf;
stream->avail_out = dest_size;
if ((inflate(stream, Z_FINISH) != Z_STREAM_END) || stream->avail_out) {
return GRN_ZLIB_ERROR;
}
}
return GRN_SUCCESS;
}
#endif /* GRN_WITH_ZLIB */
#ifdef GRN_WITH_LZ4
/* grn_ja_reader_read_lz4() reads a value compressed with LZ4. */
static grn_rc
grn_ja_reader_read_lz4(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
{
int src_size, dest_size;
grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
if (EHUGE_P(einfo)) {
grn_io *io = reader->ja->io;
void *seg_addr;
char *packed_ptr;
uint32_t size, seg_id;
if (reader->packed_size > reader->packed_buf_size) {
void *new_buf = GRN_REALLOC(reader->packed_buf, reader->packed_size);
if (!new_buf) {
return GRN_NO_MEMORY_AVAILABLE;
}
reader->packed_buf = new_buf;
reader->packed_buf_size = reader->packed_size;
}
packed_ptr = (char *)reader->packed_buf;
grn_memcpy(packed_ptr, (char *)reader->body_seg_addr + sizeof (uint64_t),
io->header->segment_size - sizeof (uint64_t));
packed_ptr += io->header->segment_size - sizeof (uint64_t);
size = reader->packed_size - (io->header->segment_size - sizeof (uint64_t));
seg_id = reader->body_seg_id + 1 ;
while (size > io->header->segment_size) {
GRN_IO_SEG_REF(io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
grn_memcpy(packed_ptr, seg_addr, io->header->segment_size);
GRN_IO_SEG_UNREF(io, seg_id);
seg_id++;
size -= io->header->segment_size;
packed_ptr += io->header->segment_size;
}
GRN_IO_SEG_REF(io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
grn_memcpy(packed_ptr, seg_addr, size);
GRN_IO_SEG_UNREF(io, seg_id);
seg_id++;
src_size = (int )(reader->packed_size - sizeof (uint64_t));
dest_size = LZ4_decompress_safe(reader->packed_buf, buf, src_size,
(int )reader->value_size);
} else {
char *packed_addr = (char *)reader->body_seg_addr;
packed_addr += reader->body_seg_offset + sizeof (uint64_t);
src_size = (int )(reader->packed_size - sizeof (uint64_t));
dest_size = LZ4_decompress_safe(packed_addr, buf, src_size,
(int )reader->value_size);
}
if ((uint32_t)dest_size != reader->value_size) {
return GRN_LZ4_ERROR;
}
return GRN_SUCCESS;
}
#endif /* GRN_WITH_LZ4 */
#ifdef GRN_WITH_ZSTD
/* grn_ja_reader_read_zstd() reads a value compressed with Zstandard. */
static grn_rc
grn_ja_reader_read_zstd(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
{
int src_size, dest_size;
grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
if (EHUGE_P(einfo)) {
grn_io *io = reader->ja->io;
void *seg_addr;
char *packed_ptr;
uint32_t size, seg_id;
if (reader->packed_size > reader->packed_buf_size) {
void *new_buf = GRN_REALLOC(reader->packed_buf, reader->packed_size);
if (!new_buf) {
return GRN_NO_MEMORY_AVAILABLE;
}
reader->packed_buf = new_buf;
reader->packed_buf_size = reader->packed_size;
}
packed_ptr = (char *)reader->packed_buf;
grn_memcpy(packed_ptr, (char *)reader->body_seg_addr + sizeof (uint64_t),
io->header->segment_size - sizeof (uint64_t));
packed_ptr += io->header->segment_size - sizeof (uint64_t);
size = reader->packed_size - (io->header->segment_size - sizeof (uint64_t));
seg_id = reader->body_seg_id + 1 ;
while (size > io->header->segment_size) {
GRN_IO_SEG_REF(io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
grn_memcpy(packed_ptr, seg_addr, io->header->segment_size);
GRN_IO_SEG_UNREF(io, seg_id);
seg_id++;
size -= io->header->segment_size;
packed_ptr += io->header->segment_size;
}
GRN_IO_SEG_REF(io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
grn_memcpy(packed_ptr, seg_addr, size);
GRN_IO_SEG_UNREF(io, seg_id);
seg_id++;
src_size = (int )(reader->packed_size - sizeof (uint64_t));
dest_size = ZSTD_decompress(reader->packed_buf, reader->value_size,
buf, src_size);
} else {
char *packed_addr = (char *)reader->body_seg_addr;
packed_addr += reader->body_seg_offset + sizeof (uint64_t);
src_size = (int )(reader->packed_size - sizeof (uint64_t));
dest_size = ZSTD_decompress(packed_addr, reader->value_size,
buf, src_size);
}
if ((uint32_t)dest_size != reader->value_size) {
return GRN_ZSTD_ERROR;
}
return GRN_SUCCESS;
}
#endif /* GRN_WITH_ZSTD */
/* grn_ja_reader_read_raw() reads a value. */
static grn_rc
grn_ja_reader_read_raw(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
{
grn_io *io = reader->ja->io;
grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
if (ETINY_P(einfo)) {
grn_memcpy(buf, einfo, reader->value_size);
} else if (EHUGE_P(einfo)) {
char *buf_ptr = (char *)buf;
void *seg_addr;
uint32_t seg_id = reader->body_seg_id;
uint32_t size = reader->value_size;
while (size > io->header->segment_size) {
GRN_IO_SEG_REF(io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
grn_memcpy(buf_ptr, seg_addr, io->header->segment_size);
GRN_IO_SEG_UNREF(io, seg_id);
seg_id++;
size -= io->header->segment_size;
buf_ptr += io->header->segment_size;
}
GRN_IO_SEG_REF(io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
grn_memcpy(buf_ptr, seg_addr, size);
GRN_IO_SEG_UNREF(io, seg_id);
seg_id++;
} else {
if (!reader->body_seg_addr) {
GRN_IO_SEG_REF(io, reader->body_seg_id, reader->body_seg_addr);
if (!reader->body_seg_addr) {
return GRN_UNKNOWN_ERROR;
}
}
grn_memcpy(buf, (char *)reader->body_seg_addr + reader->body_seg_offset,
reader->value_size);
}
return GRN_SUCCESS;
}
grn_rc
grn_ja_reader_read(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
{
switch (reader->ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
#ifdef GRN_WITH_ZLIB
case GRN_OBJ_COMPRESS_ZLIB :
return grn_ja_reader_read_zlib(ctx, reader, buf);
#endif /* GRN_WITH_ZLIB */
#ifdef GRN_WITH_LZ4
case GRN_OBJ_COMPRESS_LZ4 :
return grn_ja_reader_read_lz4(ctx, reader, buf);
#endif /* GRN_WITH_LZ4 */
#ifdef GRN_WITH_ZSTD
case GRN_OBJ_COMPRESS_ZSTD :
return grn_ja_reader_read_zstd(ctx, reader, buf);
#endif /* GRN_WITH_ZSTD */
default :
return grn_ja_reader_read_raw(ctx, reader, buf);
}
}
#ifdef GRN_WITH_ZLIB
/* grn_ja_reader_pread_zlib() reads a part of a value compressed with zlib. */
static grn_rc
grn_ja_reader_pread_zlib(grn_ctx *ctx, grn_ja_reader *reader,
size_t offset, size_t size, void *buf)
{
/* TODO: To be supported? */
return GRN_FUNCTION_NOT_IMPLEMENTED;
}
#endif /* GRN_WITH_ZLIB */
#ifdef GRN_WITH_LZ4
/* grn_ja_reader_pread_lz4() reads a part of a value compressed with LZ4. */
static grn_rc
grn_ja_reader_pread_lz4(grn_ctx *ctx, grn_ja_reader *reader,
size_t offset, size_t size, void *buf)
{
/* TODO: To be supported? */
return GRN_FUNCTION_NOT_IMPLEMENTED;
}
#endif /* GRN_WITH_LZ4 */
#ifdef GRN_WITH_ZSTD
/* grn_ja_reader_pread_zstd() reads a part of a value compressed with ZSTD. */
static grn_rc
grn_ja_reader_pread_zstd(grn_ctx *ctx, grn_ja_reader *reader,
size_t offset, size_t size, void *buf)
{
/* TODO: To be supported? */
return GRN_FUNCTION_NOT_IMPLEMENTED;
}
#endif /* GRN_WITH_ZSTD */
/* grn_ja_reader_pread_raw() reads a part of a value. */
static grn_rc
grn_ja_reader_pread_raw(grn_ctx *ctx, grn_ja_reader *reader,
size_t offset, size_t size, void *buf)
{
grn_io *io = reader->ja->io;
grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
if ((offset >= reader->value_size) || !size) {
return GRN_SUCCESS;
}
if (size > (reader->value_size - offset)) {
size = reader->value_size - offset;
}
if (ETINY_P(einfo)) {
grn_memcpy(buf, (char *)einfo + offset, size);
} else if (EHUGE_P(einfo)) {
char *buf_ptr = (char *)buf;
void *seg_addr;
uint32_t seg_id = reader->body_seg_id;
if (offset >= io->header->segment_size) {
seg_id += offset / io->header->segment_size;
offset %= io->header->segment_size;
}
GRN_IO_SEG_REF(io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
grn_memcpy(buf_ptr, (char *)seg_addr + offset,
io->header->segment_size - offset);
GRN_IO_SEG_UNREF(io, seg_id);
seg_id++;
size -= io->header->segment_size - offset;
buf_ptr += io->header->segment_size - offset;
while (size > io->header->segment_size) {
GRN_IO_SEG_REF(io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
grn_memcpy(buf_ptr, (char *)seg_addr, io->header->segment_size);
GRN_IO_SEG_UNREF(io, seg_id);
seg_id++;
size -= io->header->segment_size;
buf_ptr += io->header->segment_size;
}
GRN_IO_SEG_REF(io, seg_id, seg_addr);
if (!seg_addr) {
return GRN_UNKNOWN_ERROR;
}
grn_memcpy(buf_ptr, seg_addr, size);
GRN_IO_SEG_UNREF(io, seg_id);
} else {
if (!reader->body_seg_addr) {
GRN_IO_SEG_REF(io, reader->body_seg_id, reader->body_seg_addr);
if (!reader->body_seg_addr) {
return GRN_UNKNOWN_ERROR;
}
}
offset += reader->body_seg_offset;
grn_memcpy(buf, (char *)reader->body_seg_addr + offset, size);
}
return GRN_SUCCESS;
}
grn_rc
grn_ja_reader_pread(grn_ctx *ctx, grn_ja_reader *reader,
size_t offset, size_t size, void *buf)
{
switch (reader->ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
#ifdef GRN_WITH_ZLIB
case GRN_OBJ_COMPRESS_ZLIB :
return grn_ja_reader_pread_zlib(ctx, reader, offset, size, buf);
#endif /* GRN_WITH_ZLIB */
#ifdef GRN_WITH_LZ4
case GRN_OBJ_COMPRESS_LZ4 :
return grn_ja_reader_pread_lz4(ctx, reader, offset, size, buf);
#endif /* GRN_WITH_LZ4 */
#ifdef GRN_WITH_ZSTD
case GRN_OBJ_COMPRESS_ZSTD :
return grn_ja_reader_pread_zstd(ctx, reader, offset, size, buf);
#endif /* GRN_WITH_ZSTD */
default :
return grn_ja_reader_pread_raw(ctx, reader, offset, size, buf);
}
}
/**** vgram ****/
/*
static int len_sum = 0 ;
static int img_sum = 0 ;
static int simple_sum = 0 ;
static int skip_sum = 0 ;
grn_vgram *
grn_vgram_create ( const char * path )
{
grn_vgram * s ;
if ( ! ( s = GRN_MALLOCN ( grn_vgram , 1 ) ) ) { return NULL ; }
s - > vgram = grn_sym_create ( path , sizeof ( grn_id ) * 2 , 0 , GRN_ENC_NONE ) ;
if ( ! s - > vgram ) {
GRN_FREE ( s ) ;
return NULL ;
}
return s ;
}
grn_vgram *
grn_vgram_open ( const char * path )
{
grn_vgram * s ;
if ( ! ( s = GRN_MALLOCN ( grn_vgram , 1 ) ) ) { return NULL ; }
s - > vgram = grn_sym_open ( path ) ;
if ( ! s - > vgram ) {
GRN_FREE ( s ) ;
return NULL ;
}
return s ;
}
grn_vgram_buf *
grn_vgram_buf_open ( size_t len )
{
grn_vgram_buf * b ;
if ( ! ( b = GRN_MALLOCN ( grn_vgram_buf , 1 ) ) ) { return NULL ; }
b - > len = len ;
b - > tvs = b - > tvp = GRN_MALLOCN ( grn_id , len ) ;
if ( ! b - > tvp ) { GRN_FREE ( b ) ; return NULL ; }
b - > tve = b - > tvs + len ;
b - > vps = b - > vpp = GRN_MALLOCN ( grn_vgram_vnode , len * 2 ) ;
if ( ! b - > vpp ) { GRN_FREE ( b - > tvp ) ; GRN_FREE ( b ) ; return NULL ; }
b - > vpe = b - > vps + len ;
return b ;
}
grn_rc
grn_vgram_buf_add ( grn_vgram_buf * b , grn_id tid )
{
uint8_t dummybuf [ 8 ] , * dummyp ;
if ( b - > tvp < b - > tve ) { * b - > tvp + + = tid ; }
dummyp = dummybuf ;
GRN_B_ENC ( tid , dummyp ) ;
simple_sum + = dummyp - dummybuf ;
return GRN_SUCCESS ;
}
typedef struct {
grn_id vid ;
grn_id tid ;
} vgram_key ;
grn_rc
grn_vgram_update ( grn_vgram * vgram , grn_id rid , grn_vgram_buf * b , grn_hash * terms )
{
grn_inv_updspec * * u ;
if ( b & & b - > tvs < b - > tvp ) {
grn_id * t0 , * tn ;
for ( t0 = b - > tvs ; t0 < b - > tvp - 1 ; t0 + + ) {
grn_vgram_vnode * v , * * vp ;
if ( grn_set_at ( terms , t0 , ( void * * ) & u ) ) {
vp = & ( * u ) - > vnodes ;
for ( tn = t0 + 1 ; tn < b - > tvp ; tn + + ) {
for ( v = * vp ; v & & v - > tid ! = * tn ; v = v - > cdr ) ;
if ( ! v ) {
if ( b - > vpp < b - > vpe ) {
v = b - > vpp + + ;
} else {
// todo;
break ;
}
v - > car = NULL ;
v - > cdr = * vp ;
* vp = v ;
v - > tid = * tn ;
v - > vid = 0 ;
v - > freq = 0 ;
v - > len = tn - t0 ;
}
v - > freq + + ;
if ( v - > vid ) {
vp = & v - > car ;
} else {
break ;
}
}
}
}
{
grn_set * th = grn_set_open ( sizeof ( grn_id ) , sizeof ( int ) , 0 ) ;
if ( ! th ) { return GRN_NO_MEMORY_AVAILABLE ; }
if ( t0 = = b - > tvp ) { GRN_LOG ( ctx , GRN_LOG_DEBUG , " t0 = = tvp " ) ; }
for ( t0 = b - > tvs ; t0 < b - > tvp ; t0 + + ) {
grn_id vid , vid0 = * t0 , vid1 = 0 ;
grn_vgram_vnode * v , * v2 = NULL , * * vp ;
if ( grn_set_at ( terms , t0 , ( void * * ) & u ) ) {
vp = & ( * u ) - > vnodes ;
for ( tn = t0 + 1 ; tn < b - > tvp ; tn + + ) {
for ( v = * vp ; v ; v = v - > cdr ) {
if ( ! v - > vid & & ( v - > freq < 2 | | v - > freq * v - > len < 4 ) ) {
* vp = v - > cdr ;
v - > freq = 0 ;
}
if ( v - > tid = = * tn ) { break ; }
vp = & v - > cdr ;
}
if ( v ) {
if ( v - > freq ) {
v2 = v ;
vid1 = vid0 ;
vid0 = v - > vid ;
}
if ( v - > vid ) {
vp = & v - > car ;
continue ;
}
}
break ;
}
}
if ( v2 ) {
if ( ! v2 - > vid ) {
vgram_key key ;
key . vid = vid1 ;
key . tid = v2 - > tid ;
if ( ! ( v2 - > vid = grn_sym_get ( vgram - > vgram , ( char * ) & key ) ) ) {
grn_set_close ( th ) ;
return GRN_NO_MEMORY_AVAILABLE ;
}
}
vid = * t0 = v2 - > vid * 2 + 1 ;
memset ( t0 + 1 , 0 , sizeof ( grn_id ) * v2 - > len ) ;
t0 + = v2 - > len ;
} else {
vid = * t0 * = 2 ;
}
{
int * tf ;
if ( ! grn_set_get ( th , & vid , ( void * * ) & tf ) ) {
grn_set_close ( th ) ;
return GRN_NO_MEMORY_AVAILABLE ;
}
( * tf ) + + ;
}
}
if ( ! th - > n_entries ) { GRN_LOG ( ctx , GRN_LOG_DEBUG , " th - > n_entries = = 0 " ) ; }
{
int j = 0 ;
int skip = 0 ;
grn_set_eh * ehs , * ehp , * ehe ;
grn_set_sort_optarg arg ;
uint8_t * ps = GRN_MALLOC ( b - > len * 2 ) , * pp , * pe ;
if ( ! ps ) {
grn_set_close ( th ) ;
return GRN_NO_MEMORY_AVAILABLE ;
}
pp = ps ;
pe = ps + b - > len * 2 ;
arg . mode = grn_sort_descending ;
arg . compar = NULL ;
arg . compar_arg = ( void * ) ( intptr_t ) sizeof ( grn_id ) ;
ehs = grn_set_sort ( th , 0 , & arg ) ;
if ( ! ehs ) {
GRN_FREE ( ps ) ;
grn_set_close ( th ) ;
return GRN_NO_MEMORY_AVAILABLE ;
}
GRN_B_ENC ( th - > n_entries , pp ) ;
for ( ehp = ehs , ehe = ehs + th - > n_entries ; ehp < ehe ; ehp + + , j + + ) {
int * id = ( int * ) GRN_SET_INTVAL ( * ehp ) ;
GRN_B_ENC ( * GRN_SET_INTKEY ( * ehp ) , pp ) ;
* id = j ;
}
for ( t0 = b - > tvs ; t0 < b - > tvp ; t0 + + ) {
if ( * t0 ) {
int * id ;
if ( ! grn_set_at ( th , t0 , ( void * * ) & id ) ) {
GRN_LOG ( ctx , GRN_LOG_ERROR , " lookup error ( % d ) " , * t0 ) ;
}
GRN_B_ENC ( * id , pp ) ;
} else {
skip + + ;
}
}
len_sum + = b - > len ;
img_sum + = pp - ps ;
skip_sum + = skip ;
GRN_FREE ( ehs ) ;
GRN_FREE ( ps ) ;
}
grn_set_close ( th ) ;
}
}
return GRN_SUCCESS ;
}
grn_rc
grn_vgram_buf_close ( grn_vgram_buf * b )
{
if ( ! b ) { return GRN_INVALID_ARGUMENT ; }
if ( b - > tvs ) { GRN_FREE ( b - > tvs ) ; }
if ( b - > vps ) { GRN_FREE ( b - > vps ) ; }
GRN_FREE ( b ) ;
return GRN_SUCCESS ;
}
grn_rc
grn_vgram_close ( grn_vgram * vgram )
{
if ( ! vgram ) { return GRN_INVALID_ARGUMENT ; }
GRN_LOG ( ctx , GRN_LOG_DEBUG , " len = % d img = % d skip = % d simple = % d " , len_sum , img_sum , skip_sum , simple_sum ) ;
grn_sym_close ( vgram - > vgram ) ;
GRN_FREE ( vgram ) ;
return GRN_SUCCESS ;
}
*/
Messung V0.5 in Prozent C=98 H=91 G=94
¤ Dauer der Verarbeitung: 0.48 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland