// Inserts a key into the database. func simulatePutHandler(tx *bolt.Tx, qdb *QuickDB) { var err error keys, value := randKeys(), randValue() // Retrieve root bucket. b := tx.Bucket(keys[0]) if b == nil { b, err = tx.CreateBucket(keys[0]) if err != nil { panic("create bucket: " + err.Error()) } } // Create nested buckets, if necessary. for _, key := range keys[1 : len(keys)-1] { child := b.Bucket(key) if child != nil { b = child } else { b, err = b.CreateBucket(key) if err != nil { panic("create bucket: " + err.Error()) } } } // Insert into database. if err := b.Put(keys[len(keys)-1], value); err != nil { panic("put: " + err.Error()) } // Insert into in-memory database. qdb.Put(keys, value) }
// Retrieves a key from the database and verifies that it is what is expected. func simulateGetHandler(tx *bolt.Tx, qdb *QuickDB) { // Randomly retrieve an existing exist. keys := qdb.Rand() if len(keys) == 0 { return } // Retrieve root bucket. b := tx.Bucket(keys[0]) if b == nil { panic(fmt.Sprintf("bucket[0] expected: %08x\n", trunc(keys[0], 4))) } // Drill into nested buckets. for _, key := range keys[1 : len(keys)-1] { b = b.Bucket(key) if b == nil { panic(fmt.Sprintf("bucket[n] expected: %v -> %v\n", keys, key)) } } // Verify key/value on the final bucket. expected := qdb.Get(keys) actual := b.Get(keys[len(keys)-1]) if !bytes.Equal(actual, expected) { fmt.Println("=== EXPECTED ===") fmt.Println(expected) fmt.Println("=== ACTUAL ===") fmt.Println(actual) fmt.Println("=== END ===") panic("value mismatch") } }
func (m *Manager) persistProvider(tx *bolt.Tx, id string) error { // Note: This method does *not* include re-serializing per-volume state, // because we assume that hasn't changed unless the change request // for the volume came through us and was handled elsewhere already. provider, ok := m.providers[id] if !ok { return tx.Bucket([]byte("providers")).DeleteBucket([]byte(id)) } providersBucket, err := m.getProviderBucket(tx, id) if err != nil { return fmt.Errorf("could not persist provider info to boltdb: %s", err) } pspec := &volume.ProviderSpec{} pspec.Kind = provider.Kind() b, err := provider.MarshalGlobalState() if err != nil { return fmt.Errorf("failed to serialize provider info: %s", err) } pspec.Config = b b, err = json.Marshal(pspec) if err != nil { return fmt.Errorf("failed to serialize provider info: %s", err) } err = providersBucket.Put([]byte("global"), b) if err != nil { return fmt.Errorf("could not persist provider info to boltdb: %s", err) } return nil }
func (m *Manager) getProviderBucket(tx *bolt.Tx, providerID string) (*bolt.Bucket, error) { // Schema is roughly `"providers" -> "$provID" -> { "global" -> literal, "volumes" -> "$volID" -> literals }`. // ... This is getting complicated enough it might make sense to split the whole bolt thing out into its own structure. providerKey := []byte(providerID) providerBucket, err := tx.Bucket([]byte("providers")).CreateBucketIfNotExists(providerKey) if err != nil { return nil, err } _, err = providerBucket.CreateBucketIfNotExists([]byte("volumes")) return providerBucket, err }
// Called to sync changes to disk when a volume is updated func (m *Manager) persistVolume(tx *bolt.Tx, vol volume.Volume) error { // Save the general volume info volumesBucket := tx.Bucket([]byte("volumes")) id := vol.Info().ID k := []byte(id) _, volExists := m.volumes[id] if !volExists { volumesBucket.Delete(k) } else { b, err := json.Marshal(vol.Info()) if err != nil { return fmt.Errorf("failed to serialize volume info: %s", err) } err = volumesBucket.Put(k, b) if err != nil { return fmt.Errorf("could not persist volume info to boltdb: %s", err) } } // Save any provider-specific metadata associated with the volume. // These are saved per-provider since the deserialization is also only defined per-provider implementation. providerBucket, err := m.getProviderBucket(tx, m.providerIDs[vol.Provider()]) if err != nil { return fmt.Errorf("could not persist provider volume info to boltdb: %s", err) } providerVolumesBucket := providerBucket.Bucket([]byte("volumes")) if !volExists { providerVolumesBucket.Delete(k) } else { b, err := vol.Provider().MarshalVolumeState(id) if err != nil { return fmt.Errorf("failed to serialize provider volume info: %s", err) } err = providerVolumesBucket.Put(k, b) if err != nil { return fmt.Errorf("could not persist provider volume info to boltdb: %s", err) } } return nil }