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.2 2007/12/29 09:01:27 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);
52 spike->parent = cursor->parent;
53 spike->parent_index = cursor->parent_index;
54 spike->node = cursor->node;
55 spike->index = cursor->index;
56 spike->left_bound = cursor->left_bound;
57 spike->right_bound = cursor->right_bound;
60 hammer_ref_node(spike->parent);
61 hammer_lock_ex(&spike->parent->lock);
63 hammer_ref_node(spike->node);
64 hammer_lock_ex(&spike->node->lock);
65 kprintf("LOAD SPIKE %p\n", spike);
69 * Spike code - make room in a cluster by spiking in a new cluster.
71 * The spike structure contains a locked and reference B-Tree leaf node.
72 * The spike at a minimum must replace the node with a cluster reference
73 * and then delete the contents of the node.
75 * Various optimizations are desireable, including merging the spike node
76 * with an adjacent node that has already been spiked, if its cluster is
77 * not full, or promoting the spike node to the parent cluster of the current
78 * cluster when it represents the right hand boundary leaf node in the
79 * cluster (to avoid append chains).
82 hammer_spike(struct hammer_cursor **spikep)
84 hammer_cursor_t spike;
85 struct hammer_cursor ncursor;
86 hammer_cluster_t ocluster;
87 hammer_cluster_t ncluster;
91 kprintf("hammer_spike: ENOSPC in cluster, spiking\n");
92 /*Debugger("ENOSPC");*/
95 * Lock and flush the cluster XXX
98 KKASSERT(spike != NULL);
99 KKASSERT(spike->parent &&
100 spike->parent->cluster == spike->node->cluster);
104 ocluster = onode->cluster;
105 hammer_lock_ex(&ocluster->io.lock);
110 * Allocate and lock a new cluster, initialize its bounds.
112 ncluster = hammer_alloc_cluster(ocluster->volume->hmp, ocluster,
114 if (ncluster == NULL)
116 hammer_init_cluster(ncluster, spike->left_bound, spike->right_bound);
119 * Get a cursor for the new cluster. Operations will be limited to
122 error = hammer_init_cursor_cluster(&ncursor, ncluster);
127 * Copy the elements in the leaf node.
129 for (spike->index = 0; spike->index < onode->ondisk->count;
131 error = hammer_btree_extract(spike, HAMMER_CURSOR_GET_RECORD |
132 HAMMER_CURSOR_GET_DATA);
135 kprintf("EXTRACT %04x %016llx %016llx\n",
136 spike->record->base.base.rec_type,
137 spike->record->base.base.obj_id,
138 spike->record->base.base.key);
139 error = hammer_write_record(&ncursor, spike->record,
140 spike->data, spike->flags);
141 if (error == ENOSPC) {
142 kprintf("impossible ENOSPC error on spike\n");
150 * Success! Replace the parent reference to the leaf node with a
151 * parent reference to the new cluster and fixup the new cluster's
152 * parent reference. This completes the spike operation.
155 hammer_node_ondisk_t ondisk;
156 hammer_btree_elm_t elm;
158 ondisk = spike->parent->ondisk;
159 elm = &ondisk->elms[spike->parent_index];
160 elm->internal.subtree_type = HAMMER_BTREE_TYPE_CLUSTER;
161 elm->internal.rec_offset = -1; /* XXX */
162 elm->internal.subtree_clu_no = ncluster->clu_no;
163 elm->internal.subtree_vol_no = ncluster->volume->vol_no;
164 elm->internal.subtree_count = onode->ondisk->count; /*XXX*/
165 hammer_modify_node(spike->parent);
166 hammer_flush_node(onode);
169 hammer_cluster_ondisk_t ondisk;
171 ondisk = ncluster->ondisk;
172 ondisk->clu_btree_parent_vol_no = ocluster->volume->vol_no;
173 ondisk->clu_btree_parent_clu_no = ocluster->clu_no;
174 ondisk->clu_btree_parent_offset = spike->parent->node_offset;
175 ondisk->clu_btree_parent_clu_gen = ocluster->ondisk->clu_gen;
176 hammer_modify_cluster(ncluster);
180 * Delete the records and data associated with the old leaf node,
181 * then free the old leaf node (nothing references it any more).
183 for (spike->index = 0; spike->index < onode->ondisk->count;
185 hammer_btree_elm_t elm;
188 elm = &onode->ondisk->elms[spike->index];
189 KKASSERT(elm->leaf.rec_offset > 0);
190 hammer_free_record(ocluster, elm->leaf.rec_offset);
191 if (elm->leaf.data_offset) {
192 roff = elm->leaf.data_offset - elm->leaf.rec_offset;
193 if (roff < 0 || roff >= HAMMER_RECORD_SIZE) {
194 hammer_free_data(ocluster,
195 elm->leaf.data_offset,
200 hammer_free_btree(ocluster, onode->node_offset);
203 * XXX I/O dependancy - new cluster must be flushed before current
204 * cluster can be flushed.
206 /*Debugger("COPY COMPLETE");*/
207 hammer_done_cursor(&ncursor);
214 hammer_done_cursor(&ncursor);
216 hammer_free_cluster(ncluster);
218 hammer_unlock(&ncluster->io.lock);
219 hammer_rel_cluster(ncluster, 0);
221 kprintf("UNLOAD SPIKE %p %d\n", spike, error);
222 hammer_unlock(&ocluster->io.lock);
223 hammer_done_cursor(spike);
224 kfree(spike, M_HAMMER);