summaryrefslogtreecommitdiff
path: root/src/blob/blob_stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/blob/blob_stream.c')
-rw-r--r--src/blob/blob_stream.c283
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);
+}