CreateBucketIfNotExists creates a new bucket if it doesn't already exist and returns a reference to it. Returns an error if the bucket name is blank, or if the bucket name is too long. The bucket instance is only valid for the lifetime of the transaction.
(key []byte)
| 203 | // Returns an error if the bucket name is blank, or if the bucket name is too long. |
| 204 | // The bucket instance is only valid for the lifetime of the transaction. |
| 205 | func (b *Bucket) CreateBucketIfNotExists(key []byte) (rb *Bucket, err error) { |
| 206 | if lg := b.tx.db.Logger(); lg != discardLogger { |
| 207 | lg.Debugf("Creating bucket if not exist %q", key) |
| 208 | defer func() { |
| 209 | if err != nil { |
| 210 | lg.Errorf("Creating bucket if not exist %q failed: %v", key, err) |
| 211 | } else { |
| 212 | lg.Debugf("Creating bucket if not exist %q successfully", key) |
| 213 | } |
| 214 | }() |
| 215 | } |
| 216 | |
| 217 | if b.tx.db == nil { |
| 218 | return nil, errors.ErrTxClosed |
| 219 | } else if !b.tx.writable { |
| 220 | return nil, errors.ErrTxNotWritable |
| 221 | } else if len(key) == 0 { |
| 222 | return nil, errors.ErrBucketNameRequired |
| 223 | } |
| 224 | |
| 225 | // Insert into node. |
| 226 | // Tip: Use a new variable `newKey` instead of reusing the existing `key` to prevent |
| 227 | // it from being marked as leaking, and accordingly cannot be allocated on stack. |
| 228 | newKey := cloneBytes(key) |
| 229 | |
| 230 | if b.buckets != nil { |
| 231 | if child := b.buckets[string(newKey)]; child != nil { |
| 232 | return child, nil |
| 233 | } |
| 234 | } |
| 235 | |
| 236 | // Move cursor to correct position. |
| 237 | c := b.Cursor() |
| 238 | k, v, flags := c.seek(newKey) |
| 239 | |
| 240 | // Return an error if there is an existing non-bucket key. |
| 241 | if bytes.Equal(newKey, k) { |
| 242 | if (flags & common.BucketLeafFlag) != 0 { |
| 243 | var child = b.openBucket(v) |
| 244 | if b.buckets != nil { |
| 245 | b.buckets[string(newKey)] = child |
| 246 | } |
| 247 | |
| 248 | return child, nil |
| 249 | } |
| 250 | return nil, errors.ErrIncompatibleValue |
| 251 | } |
| 252 | |
| 253 | // Create empty, inline bucket. |
| 254 | var bucket = Bucket{ |
| 255 | InBucket: &common.InBucket{}, |
| 256 | rootNode: &node{isLeaf: true}, |
| 257 | FillPercent: DefaultFillPercent, |
| 258 | } |
| 259 | var value = bucket.write() |
| 260 | |
| 261 | c.node().put(newKey, newKey, value, 0, common.BucketLeafFlag) |
| 262 |