diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index f1331fa4..17e77943 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,3 +1,10 @@ +# v0.9.14 + +- add versioning to indexes +- option to clear revisions array in node +- fix duplicate additions to revision array +- explicit check for bson document max size upon save, return meaningful error + # v0.9.13 - added option to copy attributes when doing node copy diff --git a/VERSION b/VERSION index 62ea2590..6d44d227 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.9.13 +0.9.14 diff --git a/shock-server/node/db.go b/shock-server/node/db.go index 01f62087..fe1f28cb 100644 --- a/shock-server/node/db.go +++ b/shock-server/node/db.go @@ -11,6 +11,9 @@ import ( "strings" ) +// mongodb has hard limit of 16 MB docuemnt size +var DocumentMaxByte = 16777216 + // Initialize creates a copy of the mongodb connection and then uses that connection to // create the Nodes collection in mongodb. Then, it ensures that there is a unique index // on the id key in this collection, creating the index if necessary. diff --git a/shock-server/node/node.go b/shock-server/node/node.go index 62812c77..4973d17c 100644 --- a/shock-server/node/node.go +++ b/shock-server/node/node.go @@ -376,6 +376,13 @@ func (node *Node) RemoveExpiration() (err error) { return } +func (node *Node) ClearRevisions() (err error) { + // empty the revisions array + node.Revisions = nil + err = node.Save() + return +} + func (node *Node) SetAttributes(attr FormFile) (err error) { defer attr.Remove() attributes, err := ioutil.ReadFile(attr.Path) diff --git a/shock-server/node/update.go b/shock-server/node/update.go index e2f9dd2c..ec900f03 100644 --- a/shock-server/node/update.go +++ b/shock-server/node/update.go @@ -394,6 +394,13 @@ func (node *Node) Update(params map[string]string, files FormFiles) (err error) } } + // clear node revisions + if _, hasClearRevisions := params["clear_revisions"]; hasClearRevisions { + if err = node.ClearRevisions(); err != nil { + return err + } + } + // handle part file / we do a node level lock here if hasPartsFile { if node.HasFile() { @@ -438,8 +445,11 @@ func (node *Node) Update(params map[string]string, files FormFiles) (err error) } func (node *Node) Save() (err error) { + // update versions + previousVersion := node.Version node.UpdateVersion() - if len(node.Revisions) == 0 || node.Revisions[len(node.Revisions)-1].Version != node.Version { + // only add to revisions if not new and has changed + if previousVersion != "" && previousVersion != node.Version { n := Node{node.Id, node.Version, node.File, node.Attributes, node.Indexes, node.Acl, node.VersionParts, node.Tags, nil, node.Linkages, node.CreatedOn, node.LastModified, node.Expiration, node.Type, node.Subset, node.Parts} node.Revisions = append(node.Revisions, n) } @@ -448,17 +458,21 @@ func (node *Node) Save() (err error) { } else { node.LastModified = time.Now() } - - bsonPath := fmt.Sprintf("%s/%s.bson", node.Path(), node.Id) - os.Remove(bsonPath) + // get bson, test size and print nbson, err := bson.Marshal(node) if err != nil { return } + if len(nbson) >= DocumentMaxByte { + return errors.New(fmt.Sprintf("bson document size is greater than limit of %d bytes", DocumentMaxByte)) + } + bsonPath := fmt.Sprintf("%s/%s.bson", node.Path(), node.Id) + os.Remove(bsonPath) err = ioutil.WriteFile(bsonPath, nbson, 0644) if err != nil { return } + // save node to mongodb err = dbUpsert(node) if err != nil { return @@ -470,7 +484,7 @@ func (node *Node) UpdateVersion() (err error) { parts := make(map[string]string) h := md5.New() version := node.Id - for name, value := range map[string]interface{}{"file_ver": node.File, "attributes_ver": node.Attributes, "acl_ver": node.Acl} { + for name, value := range map[string]interface{}{"file_ver": node.File, "indexes_ver": node.Indexes, "attributes_ver": node.Attributes, "acl_ver": node.Acl} { m, er := json.Marshal(value) if er != nil { return diff --git a/shock-server/util/util.go b/shock-server/util/util.go index 623983b9..24286901 100644 --- a/shock-server/util/util.go +++ b/shock-server/util/util.go @@ -15,7 +15,7 @@ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890" // Arrays to check for valid param and file form names for node creation and updating, and also acl modification. // Note: indexing and querying do not use functions that use these arrays and thus we don't have to include those field names. -var validParams = []string{"action", "all", "archive_format", "attributes_str", "copy_attributes", "copy_data", "copy_indexes", "compression", "delete", "expiration", "file_name", "format", "ids", "index_name", "linkage", "operation", "owner", "parent_index", "parent_node", "parts", "path", "preserve_acls", "read", "remove_expiration", "source", "tags", "type", "unpack_node", "users", "write"} +var validParams = []string{"action", "all", "archive_format", "attributes_str", "clear_revisions", "copy_attributes", "copy_data", "copy_indexes", "compression", "delete", "expiration", "file_name", "format", "ids", "index_name", "linkage", "operation", "owner", "parent_index", "parent_node", "parts", "path", "preserve_acls", "read", "remove_expiration", "source", "tags", "type", "unpack_node", "users", "write"} var validFiles = []string{"attributes", "subset_indices", "upload", "gzip", "bzip2"} var ValidUpload = []string{"upload", "gzip", "bzip2"}