diff options
Diffstat (limited to 'src/blob/blob_stream.c')
-rw-r--r-- | src/blob/blob_stream.c | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/src/blob/blob_stream.c b/src/blob/blob_stream.c new file mode 100644 index 00000000..ab21aa0f --- /dev/null +++ b/src/blob/blob_stream.c @@ -0,0 +1,283 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2013, 2015 Oracle and/or its affiliates. All rights reserved. + */ + +#include "db_config.h" + +#include "db_int.h" +#include "dbinc/db_page.h" +#include "dbinc/db_am.h" +#include "dbinc/fop.h" + +static int __db_stream_close __P((DB_STREAM *, u_int32_t)); +static int __db_stream_read + __P((DB_STREAM *, DBT *, db_off_t, u_int32_t, u_int32_t)); +static int __db_stream_size __P((DB_STREAM *, db_off_t *, u_int32_t)); +static int __db_stream_write __P((DB_STREAM *, DBT *, db_off_t, u_int32_t)); + +/* + * __db_stream_init + * DB_STREAM initializer. + * + * PUBLIC: int __db_stream_init __P((DBC *, DB_STREAM **, u_int32_t)); + */ +int +__db_stream_init(dbc, dbsp, flags) + DBC *dbc; + DB_STREAM **dbsp; + u_int32_t flags; +{ + DB_STREAM *dbs; + DB_THREAD_INFO *ip; + ENV *env; + int ret; + off_t size; + + dbs = NULL; + env = dbc->env; + + if ((ret = __os_malloc(env, sizeof(DB_STREAM), &dbs)) != 0) + return (ret); + memset(dbs, 0, sizeof(DB_STREAM)); + + ENV_ENTER(env, ip); + /* Should the copy be transient? */ + if ((ret = __dbc_idup(dbc, &dbs->dbc, DB_POSITION)) != 0) + goto err; + dbs->flags = flags; + + /* + * Make sure we have a write lock on the db record if writing + * to the blob. + */ + if (F_ISSET(dbs, DB_FOP_WRITE)) + F_SET(dbc, DBC_RMW); + + if ((ret = __dbc_get_blob_id(dbs->dbc, &dbs->blob_id)) != 0) { + if (ret == EINVAL) + __db_errx(env, DB_STR("0211", + "Error, cursor does not point to a blob.")); + goto err; + } + + if ((ret = __dbc_get_blob_size(dbs->dbc, &size)) != 0) + goto err; + dbs->file_size = size; + + if ((ret = __blob_file_open( + dbs->dbc->dbp, &dbs->fhp, dbs->blob_id, flags, 1)) != 0) + goto err; + ENV_LEAVE(env, ip); + + dbs->close = __db_stream_close; + dbs->read = __db_stream_read; + dbs->size = __db_stream_size; + dbs->write = __db_stream_write; + + *dbsp = dbs; + return (0); + +err: if (dbs != NULL && dbs->dbc != NULL) + (void)__dbc_close(dbs->dbc); + ENV_LEAVE(env, ip); + if (dbs != NULL) + __os_free(env, dbs); + return (ret); +} + +/* + * __db_stream_close -- + * + * DB_STREAM->close + */ +static int +__db_stream_close(dbs, flags) + DB_STREAM *dbs; + u_int32_t flags; +{ + DB_THREAD_INFO *ip; + ENV *env; + int ret; + + env = dbs->dbc->env; + + if ((ret = __db_fchk(env, "DB_STREAM->close", flags, 0)) != 0) + return (ret); + + ENV_ENTER(env, ip); + + ret = __db_stream_close_int(dbs); + + ENV_LEAVE(env, ip); + + return (ret); +} + +/* + * __db_stream_close_int -- + * Close a DB_STREAM object. + * + * PUBLIC: int __db_stream_close_int __P ((DB_STREAM *)); + */ +int +__db_stream_close_int(dbs) + DB_STREAM *dbs; +{ + DBC *dbc; + ENV *env; + int ret, t_ret; + + dbc = dbs->dbc; + env = dbc->env; + + ret = __blob_file_close(dbc, dbs->fhp, dbs->flags); + + if ((t_ret = __dbc_close(dbs->dbc)) != 0 && ret == 0) + ret = t_ret; + + __os_free(env, dbs); + + return (ret); +} + +/* + * __db_stream_read -- + * + * DB_STREAM->read + */ +static int +__db_stream_read(dbs, data, offset, size, flags) + DB_STREAM *dbs; + DBT *data; + db_off_t offset; + u_int32_t size; + u_int32_t flags; +{ + DBC *dbc; + ENV *env; + int ret; + u_int32_t needed, start; + + dbc = dbs->dbc; + env = dbc->dbp->env; + ret = 0; + + if ((ret = __db_fchk(env, "DB_STREAM->read", flags, 0)) != 0) + return (ret); + + if (F_ISSET(data, DB_DBT_PARTIAL)) { + ret = EINVAL; + __db_errx(env, DB_STR("0212", + "Error, do not use DB_DBT_PARTIAL with DB_STREAM.")); + goto err; + } + + if (offset > dbs->file_size) { + data->size = 0; + goto err; + } + + if ((ret = __db_alloc_dbt( + env, data, size, &needed, &start, NULL, NULL)) != 0) + goto err; + data->size = needed; + + if (needed == 0) + goto err; + + ret = __blob_file_read(env, dbs->fhp, data, offset, size); + +err: return (ret); +} + +/* + * __db_stream_size -- + * + * DB_STREAM->size + */ +static int +__db_stream_size(dbs, size, flags) + DB_STREAM *dbs; + db_off_t *size; + u_int32_t flags; +{ + int ret; + + if ((ret = __db_fchk(dbs->dbc->env, "DB_STREAM->size", flags, 0)) != 0) + return (ret); + + *size = dbs->file_size; + + return (0); +} + +/* + * __db_stream_write -- + * + * DB_STREAM->write + */ +static int +__db_stream_write(dbs, data, offset, flags) + DB_STREAM *dbs; + DBT *data; + db_off_t offset; + u_int32_t flags; +{ + DB_THREAD_INFO *ip; + ENV *env; + int ret; + off_t file_size; + u_int32_t wflags; + + env = dbs->dbc->env; + + if ((ret = __db_fchk( + env, "DB_STREAM->write", flags, DB_STREAM_SYNC_WRITE)) != 0) + return (ret); + + if (F_ISSET(dbs, DB_FOP_READONLY)) { + ret = EINVAL; + __db_errx(env, DB_STR("0213", "Error, blob is read only.")); + return (ret); + } + if (F_ISSET(data, DB_DBT_PARTIAL)) { + ret = EINVAL; + __db_errx(env, DB_STR("0214", + "Error, do not use DB_DBT_PARTIAL with DB_STREAM.")); + return (ret); + } + if (offset < 0 ) { + ret = EINVAL; + __db_errx(env, DB_STR_A("0215", + "Error, invalid offset value: %lld", "%lld"), + (long long)offset); + return (ret); + } + /* Catch overflow. */ + if (offset + (db_off_t)data->size < offset) { + ret = EINVAL; + __db_errx(env, DB_STR_A("0216", + "Error, this write will exceed the maximum blob size: %lu %lld", + "%lu %lld"), (u_long)data->size, (long long)offset); + return (ret); + } + + ENV_ENTER(env, ip); + wflags = dbs->flags; + if (LF_ISSET(DB_STREAM_SYNC_WRITE)) + wflags |= DB_FOP_SYNC_WRITE; + file_size = dbs->file_size; + if ((ret = __blob_file_write(dbs->dbc, dbs->fhp, + data, offset, dbs->blob_id, &file_size, wflags)) != 0) + goto err; + if (file_size != dbs->file_size) { + dbs->file_size = file_size; + if ((ret = __dbc_set_blob_size(dbs->dbc, dbs->file_size)) != 0) + goto err; + } +err: ENV_LEAVE(env, ip); + + return (ret); +} |