HAMMER 39/Many: Parallel operations optimizations
[dragonfly.git] / sys / vfs / hammer / hammer_transaction.c
1 /*
2  * Copyright (c) 2007-2008 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
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
16  *    distribution.
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.
20  * 
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
32  * SUCH DAMAGE.
33  * 
34  * $DragonFly: src/sys/vfs/hammer/hammer_transaction.c,v 1.14 2008/04/29 01:10:37 dillon Exp $
35  */
36
37 #include "hammer.h"
38
39 static hammer_tid_t hammer_alloc_tid(hammer_transaction_t trans, int count);
40
41
42 /*
43  * Start a standard transaction.
44  */
45 void
46 hammer_start_transaction(struct hammer_transaction *trans,
47                          struct hammer_mount *hmp)
48 {
49         int error;
50
51         trans->type = HAMMER_TRANS_STD;
52         trans->hmp = hmp;
53         trans->rootvol = hammer_get_root_volume(hmp, &error);
54         KKASSERT(error == 0);
55         trans->tid = 0;
56         trans->time = hammer_alloc_tid(trans, 1);
57 }
58
59 /*
60  * Start a simple read-only transaction.  This will not stall.
61  */
62 void
63 hammer_simple_transaction(struct hammer_transaction *trans,
64                           struct hammer_mount *hmp)
65 {
66         int error;
67
68         trans->type = HAMMER_TRANS_RO;
69         trans->hmp = hmp;
70         trans->rootvol = hammer_get_root_volume(hmp, &error);
71         KKASSERT(error == 0);
72         trans->tid = 0;
73         trans->time = hammer_alloc_tid(trans, 1);
74 }
75
76 /*
77  * Start a transaction using a particular TID.  Used by the sync code.
78  * This does not stall.
79  */
80 void
81 hammer_start_transaction_fls(struct hammer_transaction *trans,
82                              struct hammer_mount *hmp)
83 {
84         int error;
85
86         trans->type = HAMMER_TRANS_FLS;
87         trans->hmp = hmp;
88         trans->rootvol = hammer_get_root_volume(hmp, &error);
89         KKASSERT(error == 0);
90         trans->tid = hammer_alloc_tid(trans, 1);
91         trans->time = trans->tid;
92 }
93
94 void
95 hammer_done_transaction(struct hammer_transaction *trans)
96 {
97         hammer_rel_volume(trans->rootvol, 0);
98         trans->rootvol = NULL;
99 }
100
101 /*
102  * Note: Successive transaction ids must be at least 2 apart so the
103  * B-Tree code can make a separator that does not match either the
104  * left or right hand sides.
105  */
106 static hammer_tid_t
107 hammer_alloc_tid(hammer_transaction_t trans, int count)
108 {
109         struct timespec ts;
110         hammer_tid_t tid;
111
112         getnanotime(&ts);
113         tid = ts.tv_sec * 1000000000LL + ts.tv_nsec;
114         if (tid < trans->hmp->next_tid)
115                 tid = trans->hmp->next_tid;
116         if (tid >= 0xFFFFFFFFFFFFF000ULL)
117                 panic("hammer_start_transaction: Ran out of TIDs!");
118         trans->hmp->next_tid = tid + count * 2;
119         if (hammer_debug_tid) {
120                 kprintf("alloc_tid %016llx (0x%08x)\n",
121                         tid, (int)(tid / 1000000000LL));
122         }
123         return(tid);
124 }
125
126 /*
127  * Allocate an object id
128  */
129 hammer_tid_t
130 hammer_alloc_objid(hammer_transaction_t trans, hammer_inode_t dip)
131 {
132         hammer_objid_cache_t ocp;
133         hammer_tid_t tid;
134
135         while ((ocp = dip->objid_cache) == NULL) {
136                 if (trans->hmp->objid_cache_count < OBJID_CACHE_SIZE) {
137                         ocp = kmalloc(sizeof(*ocp), M_HAMMER, M_WAITOK|M_ZERO);
138                         ocp->next_tid = hammer_alloc_tid(trans,
139                                                          OBJID_CACHE_BULK);
140                         ocp->count = OBJID_CACHE_BULK;
141                         TAILQ_INSERT_HEAD(&trans->hmp->objid_cache_list, ocp,
142                                           entry);
143                         ++trans->hmp->objid_cache_count;
144                         /* may have blocked, recheck */
145                         if (dip->objid_cache == NULL) {
146                                 dip->objid_cache = ocp;
147                                 ocp->dip = dip;
148                         }
149                 } else {
150                         ocp = TAILQ_FIRST(&trans->hmp->objid_cache_list);
151                         if (ocp->dip)
152                                 ocp->dip->objid_cache = NULL;
153                         dip->objid_cache = ocp;
154                         ocp->dip = dip;
155                 }
156         }
157         TAILQ_REMOVE(&trans->hmp->objid_cache_list, ocp, entry);
158         tid = ocp->next_tid;
159         ocp->next_tid += 2;
160         if (--ocp->count == 0) {
161                 dip->objid_cache = NULL;
162                 --trans->hmp->objid_cache_count;
163                 ocp->dip = NULL;
164                 kfree(ocp, M_HAMMER);
165         } else {
166                 TAILQ_INSERT_TAIL(&trans->hmp->objid_cache_list, ocp, entry);
167         }
168         return(tid);
169 }
170
171 void
172 hammer_clear_objid(hammer_inode_t dip)
173 {
174         hammer_objid_cache_t ocp;
175
176         if ((ocp = dip->objid_cache) != NULL) {
177                 dip->objid_cache = NULL;
178                 ocp->dip = NULL;
179                 TAILQ_REMOVE(&dip->hmp->objid_cache_list, ocp, entry);
180                 TAILQ_INSERT_HEAD(&dip->hmp->objid_cache_list, ocp, entry);
181         }
182 }
183
184 void
185 hammer_destroy_objid_cache(hammer_mount_t hmp)
186 {
187         hammer_objid_cache_t ocp;
188
189         while ((ocp = TAILQ_FIRST(&hmp->objid_cache_list)) != NULL) {
190                 TAILQ_REMOVE(&hmp->objid_cache_list, ocp, entry);
191                 kfree(ocp, M_HAMMER);
192         }
193 }
194