2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $DragonFly: src/sys/vfs/hammer/Attic/hammer_spike.c,v 1.5 2008/01/10 07:41:03 dillon Exp $
40 * Load spike info given a cursor. The cursor must point to the leaf node
41 * that needs to be spiked.
44 hammer_load_spike(hammer_cursor_t cursor
, struct hammer_cursor
**spikep
)
46 hammer_cursor_t spike
;
48 KKASSERT(cursor
->node
->ondisk
->type
== HAMMER_BTREE_TYPE_LEAF
);
49 KKASSERT(*spikep
== NULL
);
50 *spikep
= spike
= kmalloc(sizeof(*spike
), M_HAMMER
, M_WAITOK
|M_ZERO
);
51 ++hammer_count_spikes
;
53 spike
->parent
= cursor
->parent
;
54 spike
->parent_index
= cursor
->parent_index
;
55 spike
->node
= cursor
->node
;
56 spike
->index
= cursor
->index
;
57 spike
->left_bound
= cursor
->left_bound
;
58 spike
->right_bound
= cursor
->right_bound
;
61 hammer_ref_node(spike
->parent
);
62 hammer_lock_ex(&spike
->parent
->lock
);
64 hammer_ref_node(spike
->node
);
65 hammer_lock_ex(&spike
->node
->lock
);
66 kprintf("LOAD SPIKE %p\n", spike
);
70 * Spike code - make room in a cluster by spiking in a new cluster.
72 * The spike structure contains a locked and reference B-Tree leaf node.
73 * The spike at a minimum must replace the node with a cluster reference
74 * and then delete the contents of the node.
76 * Various optimizations are desireable, including merging the spike node
77 * with an adjacent node that has already been spiked, if its cluster is
78 * not full, or promoting the spike node to the parent cluster of the current
79 * cluster when it represents the right hand boundary leaf node in the
80 * cluster (to avoid append chains).
83 hammer_spike(struct hammer_cursor
**spikep
)
85 hammer_cursor_t spike
;
86 struct hammer_cursor ncursor
;
87 hammer_cluster_t ocluster
;
88 hammer_cluster_t ncluster
;
92 kprintf("hammer_spike: ENOSPC in cluster, spiking\n");
93 /*Debugger("ENOSPC");*/
96 * Lock and flush the cluster XXX
99 KKASSERT(spike
!= NULL
);
100 KKASSERT(spike
->parent
&&
101 spike
->parent
->cluster
== spike
->node
->cluster
);
105 ocluster
= onode
->cluster
;
106 hammer_lock_ex(&ocluster
->io
.lock
);
111 * Allocate and lock a new cluster, initialize its bounds.
113 ncluster
= hammer_alloc_cluster(ocluster
->volume
->hmp
, ocluster
,
115 if (ncluster
== NULL
)
117 hammer_init_cluster(ncluster
, spike
->left_bound
, spike
->right_bound
);
120 * Get a cursor for the new cluster. Operations will be limited to
123 error
= hammer_init_cursor_cluster(&ncursor
, ncluster
);
128 * Copy the elements in the leaf node.
130 for (spike
->index
= 0; spike
->index
< onode
->ondisk
->count
;
132 error
= hammer_btree_extract(spike
, HAMMER_CURSOR_GET_RECORD
|
133 HAMMER_CURSOR_GET_DATA
);
136 kprintf("EXTRACT %04x %016llx %016llx\n",
137 spike
->record
->base
.base
.rec_type
,
138 spike
->record
->base
.base
.obj_id
,
139 spike
->record
->base
.base
.key
);
140 error
= hammer_write_record(&ncursor
, spike
->record
,
141 spike
->data
, spike
->flags
);
142 if (error
== ENOSPC
) {
143 kprintf("impossible ENOSPC error on spike\n");
151 * Success! Replace the parent reference to the leaf node with a
152 * parent reference to the new cluster and fixup the new cluster's
153 * parent reference. This completes the spike operation.
156 hammer_node_ondisk_t ondisk
;
157 hammer_btree_elm_t elm
;
159 hammer_modify_node(spike
->parent
);
160 ondisk
= spike
->parent
->ondisk
;
161 elm
= &ondisk
->elms
[spike
->parent_index
];
162 elm
->internal
.subtree_type
= HAMMER_BTREE_TYPE_CLUSTER
;
163 elm
->internal
.rec_offset
= -1; /* XXX */
164 elm
->internal
.subtree_clu_no
= ncluster
->clu_no
;
165 elm
->internal
.subtree_vol_no
= ncluster
->volume
->vol_no
;
166 elm
->internal
.subtree_count
= onode
->ondisk
->count
; /*XXX*/
167 onode
->flags
|= HAMMER_NODE_MODIFIED
;
168 hammer_flush_node(onode
);
171 hammer_cluster_ondisk_t ondisk
;
173 hammer_modify_cluster(ncluster
);
174 ondisk
= ncluster
->ondisk
;
175 ondisk
->clu_btree_parent_vol_no
= ocluster
->volume
->vol_no
;
176 ondisk
->clu_btree_parent_clu_no
= ocluster
->clu_no
;
177 ondisk
->clu_btree_parent_offset
= spike
->parent
->node_offset
;
178 ondisk
->clu_btree_parent_clu_gen
= ocluster
->ondisk
->clu_gen
;
182 * Delete the records and data associated with the old leaf node,
183 * then free the old leaf node (nothing references it any more).
185 for (spike
->index
= 0; spike
->index
< onode
->ondisk
->count
;
187 hammer_btree_elm_t elm
;
190 elm
= &onode
->ondisk
->elms
[spike
->index
];
191 KKASSERT(elm
->leaf
.rec_offset
> 0);
192 hammer_free_record(ocluster
, elm
->leaf
.rec_offset
);
193 if (elm
->leaf
.data_offset
) {
194 roff
= elm
->leaf
.data_offset
- elm
->leaf
.rec_offset
;
195 if (roff
< 0 || roff
>= HAMMER_RECORD_SIZE
) {
196 hammer_free_data(ocluster
,
197 elm
->leaf
.data_offset
,
202 onode
->flags
|= HAMMER_NODE_DELETED
;
205 * XXX I/O dependancy - new cluster must be flushed before current
206 * cluster can be flushed.
208 /*Debugger("COPY COMPLETE");*/
209 hammer_done_cursor(&ncursor
);
216 hammer_done_cursor(&ncursor
);
218 hammer_free_cluster(ncluster
);
220 hammer_unlock(&ncluster
->io
.lock
);
221 hammer_rel_cluster(ncluster
, 0);
223 kprintf("UNLOAD SPIKE %p %d\n", spike
, error
);
224 hammer_unlock(&ocluster
->io
.lock
);
225 hammer_done_cursor(spike
);
226 --hammer_count_spikes
;
227 kfree(spike
, M_HAMMER
);