view src/objstore/include/nomad/objstore_backend.h @ 555:0e7e00acfe88

objstore: maintain a tree of head object versions We must keep track of which versions are heads in order to properly determine which version to use when handling unqualified opens. Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
date Thu, 15 Nov 2018 17:24:12 -0500
parents 4b1b3fffdf7b
children 62cb9de73005
line wrap: on
line source

/*
 * Copyright (c) 2015-2018 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef __NOMAD_OBJSTORE_BACKEND_H
#define __NOMAD_OBJSTORE_BACKEND_H

#include <jeffpc/rbtree.h>

#include <nomad/objstore.h>

enum obj_state {
	OBJ_STATE_NEW = 0,	/* newly allocated */
	OBJ_STATE_LIVE,		/* fully initialized */
	OBJ_STATE_DEAD,		/* initialization failed */
};

struct obj {
	/* key */
	struct noid oid;

	/* value */
	struct rb_tree versions;/* cached versions */
	struct rb_tree heads;	/* head versions */
	uint64_t nversions;	/* number of versions */
	uint32_t nlink;		/* file link count */
	void *private;

	/* misc */
	enum obj_state state;
	refcnt_t refcnt;
	struct lock lock;
	struct rb_node node;

	/* constant for the lifetime of the object */
	struct objstore *vol;
	const struct obj_ops *ops;
};

struct objver {
	/* key */
	struct nvclock *clock;

	/* value */
	/*
	 * Everything in the attrs structure is used for attribute storage
	 * except for:
	 *   - nlink: use nlink field in struct obj
	 */
	struct nattr attrs;
	void *private;
	/*
	 * Keep track of opens - both qualified and unqualified.
	 *
	 * ->open[0 aka. false] = unqualified
	 * ->open[1 aka. true]  = qualified
	 */
	struct objstore_open_obj_info *open[2];

	/* misc */
	struct obj *obj;
	struct rb_node all_node;	/* all versions */
	struct rb_node head_node;	/* head versions */
};

struct objstore_open_obj_info {
	/* constant for the lifetime of this struct */
	struct obj *obj;

	/* protected by the obj lock */
	struct objver *ver;
	uint32_t open_count;
};

struct obj_ops {
	/*
	 * Determine if a specified version of an object exists.
	 *
	 * This is meant as a lightweight check to avoid allocating an
	 * objver only to have to free it on error.
	 *
	 * If not implemented, the normal getattr call is used all the time.
	 */
	int (*checkversion)(struct obj *obj, const struct nvclock *clock);

	/* open objects must be closed */
	int (*open)(struct objver *ver);
	int (*close)(struct objver *ver);

	/* cloned objects must be committed/aborted */
	int (*clone)();		/*
				 * create a new temp obj as a copy of
				 * existing obj
				 */
	int (*commit)();	/* make temp object live */
	int (*abort)();		/* delete temp object */

	int (*getattr)(struct objver *ver, struct nattr *attr);
	int (*setattr)(struct objver *ver, struct nattr *attr,
		       const unsigned valid);
	ssize_t (*read)(struct objver *ver, void *buf, size_t len,
			uint64_t offset);
	ssize_t (*write)(struct objver *ver, const void *buf, size_t len,
			 uint64_t offset);

	int (*lookup_one)(struct objver *dirver, const char *name,
			  const struct noid *desired, struct noid *child,
			  uint8_t *type);
	int (*create)(struct objver *dirver, const char *name,
		      uint16_t mode, struct noid *child);
	int (*unlink)(struct objver *dirver, const char *name,
		      struct obj *child);

	int (*getdent)(struct objver *dirver, const uint64_t offset,
		       struct ndirent *child);

	/*
	 * Called just before the generic object is freed.
	 */
	void (*free)(struct obj *obj);
};

struct vol_ops {
	int (*getroot)(struct objstore *vol, struct noid *root);
	/*
	 * Initialize an object.
	 *
	 * At a minimum, the backend must:
	 *  - set obj->nversions
	 *  - set obj->ops
	 *  - add head versions to obj->versions
	 *
	 * Typically, the backend also:
	 *  - sets obj->private
	 */
	int (*initobj)(struct obj *obj);
};

struct objstore_vdev_def {
	const char *name;

	int (*create_vdev)(struct objstore_vdev *vdev);
	int (*create_vol)(struct objstore *vol);
	int (*import_vdev)(struct objstore_vdev *vdev);
};

extern struct objver *obj_add_version(struct obj *obj,
				      const struct nvclock *clock);

#endif