github.com/maynardminer/ethereumprogpow@v1.8.23/swarm/shed/schema.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package shed
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	"fmt"
    23  )
    24  
    25  var (
    26  	// LevelDB key value for storing the schema.
    27  	keySchema = []byte{0}
    28  	// LevelDB key prefix for all field type.
    29  	// LevelDB keys will be constructed by appending name values to this prefix.
    30  	keyPrefixFields byte = 1
    31  	// LevelDB key prefix from which indexing keys start.
    32  	// Every index has its own key prefix and this value defines the first one.
    33  	keyPrefixIndexStart byte = 2 // Q: or maybe a higher number like 7, to have more space for potential specific perfixes
    34  )
    35  
    36  // schema is used to serialize known database structure information.
    37  type schema struct {
    38  	Fields  map[string]fieldSpec `json:"fields"`  // keys are field names
    39  	Indexes map[byte]indexSpec   `json:"indexes"` // keys are index prefix bytes
    40  }
    41  
    42  // fieldSpec holds information about a particular field.
    43  // It does not need Name field as it is contained in the
    44  // schema.Field map key.
    45  type fieldSpec struct {
    46  	Type string `json:"type"`
    47  }
    48  
    49  // indxSpec holds information about a particular index.
    50  // It does not contain index type, as indexes do not have type.
    51  type indexSpec struct {
    52  	Name string `json:"name"`
    53  }
    54  
    55  // schemaFieldKey retrives the complete LevelDB key for
    56  // a particular field form the schema definition.
    57  func (db *DB) schemaFieldKey(name, fieldType string) (key []byte, err error) {
    58  	if name == "" {
    59  		return nil, errors.New("field name can not be blank")
    60  	}
    61  	if fieldType == "" {
    62  		return nil, errors.New("field type can not be blank")
    63  	}
    64  	s, err := db.getSchema()
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	var found bool
    69  	for n, f := range s.Fields {
    70  		if n == name {
    71  			if f.Type != fieldType {
    72  				return nil, fmt.Errorf("field %q of type %q stored as %q in db", name, fieldType, f.Type)
    73  			}
    74  			break
    75  		}
    76  	}
    77  	if !found {
    78  		s.Fields[name] = fieldSpec{
    79  			Type: fieldType,
    80  		}
    81  		err := db.putSchema(s)
    82  		if err != nil {
    83  			return nil, err
    84  		}
    85  	}
    86  	return append([]byte{keyPrefixFields}, []byte(name)...), nil
    87  }
    88  
    89  // schemaIndexID retrieves the complete LevelDB prefix for
    90  // a particular index.
    91  func (db *DB) schemaIndexPrefix(name string) (id byte, err error) {
    92  	if name == "" {
    93  		return 0, errors.New("index name can not be blank")
    94  	}
    95  	s, err := db.getSchema()
    96  	if err != nil {
    97  		return 0, err
    98  	}
    99  	nextID := keyPrefixIndexStart
   100  	for i, f := range s.Indexes {
   101  		if i >= nextID {
   102  			nextID = i + 1
   103  		}
   104  		if f.Name == name {
   105  			return i, nil
   106  		}
   107  	}
   108  	id = nextID
   109  	s.Indexes[id] = indexSpec{
   110  		Name: name,
   111  	}
   112  	return id, db.putSchema(s)
   113  }
   114  
   115  // getSchema retrieves the complete schema from
   116  // the database.
   117  func (db *DB) getSchema() (s schema, err error) {
   118  	b, err := db.Get(keySchema)
   119  	if err != nil {
   120  		return s, err
   121  	}
   122  	err = json.Unmarshal(b, &s)
   123  	return s, err
   124  }
   125  
   126  // putSchema stores the complete schema to
   127  // the database.
   128  func (db *DB) putSchema(s schema) (err error) {
   129  	b, err := json.Marshal(s)
   130  	if err != nil {
   131  		return err
   132  	}
   133  	return db.Put(keySchema, b)
   134  }