mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-23 07:12:09 +00:00
dm persistent data: add transactional array
Add a transactional array. Signed-off-by: Joe Thornber <ejt@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
This commit is contained in:
parent
025b96853f
commit
6513c29f44
3 changed files with 975 additions and 0 deletions
166
drivers/md/persistent-data/dm-array.h
Normal file
166
drivers/md/persistent-data/dm-array.h
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Red Hat, Inc.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
#ifndef _LINUX_DM_ARRAY_H
|
||||
#define _LINUX_DM_ARRAY_H
|
||||
|
||||
#include "dm-btree.h"
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The dm-array is a persistent version of an array. It packs the data
|
||||
* more efficiently than a btree which will result in less disk space use,
|
||||
* and a performance boost. The element get and set operations are still
|
||||
* O(ln(n)), but with a much smaller constant.
|
||||
*
|
||||
* The value type structure is reused from the btree type to support proper
|
||||
* reference counting of values.
|
||||
*
|
||||
* The arrays implicitly know their length, and bounds are checked for
|
||||
* lookups and updated. It doesn't store this in an accessible place
|
||||
* because it would waste a whole metadata block. Make sure you store the
|
||||
* size along with the array root in your encompassing data.
|
||||
*
|
||||
* Array entries are indexed via an unsigned integer starting from zero.
|
||||
* Arrays are not sparse; if you resize an array to have 'n' entries then
|
||||
* 'n - 1' will be the last valid index.
|
||||
*
|
||||
* Typical use:
|
||||
*
|
||||
* a) initialise a dm_array_info structure. This describes the array
|
||||
* values and ties it into a specific transaction manager. It holds no
|
||||
* instance data; the same info can be used for many similar arrays if
|
||||
* you wish.
|
||||
*
|
||||
* b) Get yourself a root. The root is the index of a block of data on the
|
||||
* disk that holds a particular instance of an array. You may have a
|
||||
* pre existing root in your metadata that you wish to use, or you may
|
||||
* want to create a brand new, empty array with dm_array_empty().
|
||||
*
|
||||
* Like the other data structures in this library, dm_array objects are
|
||||
* immutable between transactions. Update functions will return you the
|
||||
* root for a _new_ array. If you've incremented the old root, via
|
||||
* dm_tm_inc(), before calling the update function you may continue to use
|
||||
* it in parallel with the new root.
|
||||
*
|
||||
* c) resize an array with dm_array_resize().
|
||||
*
|
||||
* d) Get a value from the array with dm_array_get_value().
|
||||
*
|
||||
* e) Set a value in the array with dm_array_set_value().
|
||||
*
|
||||
* f) Walk an array of values in index order with dm_array_walk(). More
|
||||
* efficient than making many calls to dm_array_get_value().
|
||||
*
|
||||
* g) Destroy the array with dm_array_del(). This tells the transaction
|
||||
* manager that you're no longer using this data structure so it can
|
||||
* recycle it's blocks. (dm_array_dec() would be a better name for it,
|
||||
* but del is in keeping with dm_btree_del()).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Describes an array. Don't initialise this structure yourself, use the
|
||||
* init function below.
|
||||
*/
|
||||
struct dm_array_info {
|
||||
struct dm_transaction_manager *tm;
|
||||
struct dm_btree_value_type value_type;
|
||||
struct dm_btree_info btree_info;
|
||||
};
|
||||
|
||||
/*
|
||||
* Sets up a dm_array_info structure. You don't need to do anything with
|
||||
* this structure when you finish using it.
|
||||
*
|
||||
* info - the structure being filled in.
|
||||
* tm - the transaction manager that should supervise this structure.
|
||||
* vt - describes the leaf values.
|
||||
*/
|
||||
void dm_array_info_init(struct dm_array_info *info,
|
||||
struct dm_transaction_manager *tm,
|
||||
struct dm_btree_value_type *vt);
|
||||
|
||||
/*
|
||||
* Create an empty, zero length array.
|
||||
*
|
||||
* info - describes the array
|
||||
* root - on success this will be filled out with the root block
|
||||
*/
|
||||
int dm_array_empty(struct dm_array_info *info, dm_block_t *root);
|
||||
|
||||
/*
|
||||
* Resizes the array.
|
||||
*
|
||||
* info - describes the array
|
||||
* root - the root block of the array on disk
|
||||
* old_size - the caller is responsible for remembering the size of
|
||||
* the array
|
||||
* new_size - can be bigger or smaller than old_size
|
||||
* value - if we're growing the array the new entries will have this value
|
||||
* new_root - on success, points to the new root block
|
||||
*
|
||||
* If growing the inc function for 'value' will be called the appropriate
|
||||
* number of times. So if the caller is holding a reference they may want
|
||||
* to drop it.
|
||||
*/
|
||||
int dm_array_resize(struct dm_array_info *info, dm_block_t root,
|
||||
uint32_t old_size, uint32_t new_size,
|
||||
const void *value, dm_block_t *new_root)
|
||||
__dm_written_to_disk(value);
|
||||
|
||||
/*
|
||||
* Frees a whole array. The value_type's decrement operation will be called
|
||||
* for all values in the array
|
||||
*/
|
||||
int dm_array_del(struct dm_array_info *info, dm_block_t root);
|
||||
|
||||
/*
|
||||
* Lookup a value in the array
|
||||
*
|
||||
* info - describes the array
|
||||
* root - root block of the array
|
||||
* index - array index
|
||||
* value - the value to be read. Will be in on-disk format of course.
|
||||
*
|
||||
* -ENODATA will be returned if the index is out of bounds.
|
||||
*/
|
||||
int dm_array_get_value(struct dm_array_info *info, dm_block_t root,
|
||||
uint32_t index, void *value);
|
||||
|
||||
/*
|
||||
* Set an entry in the array.
|
||||
*
|
||||
* info - describes the array
|
||||
* root - root block of the array
|
||||
* index - array index
|
||||
* value - value to be written to disk. Make sure you confirm the value is
|
||||
* in on-disk format with__dm_bless_for_disk() before calling.
|
||||
* new_root - the new root block
|
||||
*
|
||||
* The old value being overwritten will be decremented, the new value
|
||||
* incremented.
|
||||
*
|
||||
* -ENODATA will be returned if the index is out of bounds.
|
||||
*/
|
||||
int dm_array_set_value(struct dm_array_info *info, dm_block_t root,
|
||||
uint32_t index, const void *value, dm_block_t *new_root)
|
||||
__dm_written_to_disk(value);
|
||||
|
||||
/*
|
||||
* Walk through all the entries in an array.
|
||||
*
|
||||
* info - describes the array
|
||||
* root - root block of the array
|
||||
* fn - called back for every element
|
||||
* context - passed to the callback
|
||||
*/
|
||||
int dm_array_walk(struct dm_array_info *info, dm_block_t root,
|
||||
int (*fn)(void *context, uint64_t key, void *leaf),
|
||||
void *context);
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#endif /* _LINUX_DM_ARRAY_H */
|
Loading…
Add table
Add a link
Reference in a new issue