@@ -34,6 +34,8 @@ const (
3434 attrIDFixedLen = 1 + oid .Size + utf8DelimiterLen // prefix first
3535)
3636
37+ const binPropMarker = "1" // ROOT, PHY, etc.
38+
3739var (
3840 maxUint256 = new (big.Int ).SetBytes ([]byte {255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 ,
3941 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 })
@@ -45,10 +47,10 @@ func invalidMetaBucketKeyErr(key []byte, cause error) error {
4547}
4648
4749// TODO: fill on migration.
48- // TODO: ROOT and PHY props.
4950// TODO: cleaning on obj removal.
5051func putMetadata (tx * bbolt.Tx , cnr cid.ID , id oid.ID , ver version.Version , owner user.ID , typ object.Type , creationEpoch uint64 ,
51- payloadLen uint64 , pldHash , pldHmmHash , splitID []byte , parentID , firstID oid.ID , attrs []object.Attribute ) error {
52+ payloadLen uint64 , pldHash , pldHmmHash , splitID []byte , parentID , firstID oid.ID , attrs []object.Attribute ,
53+ root , phy bool ) error {
5254 metaBkt , err := tx .CreateBucketIfNotExists (metaBucketKey (cnr ))
5355 if err != nil {
5456 return fmt .Errorf ("create meta bucket for container: %w" , err )
@@ -96,6 +98,16 @@ func putMetadata(tx *bbolt.Tx, cnr cid.ID, id oid.ID, ver version.Version, owner
9698 return err
9799 }
98100 }
101+ if root {
102+ if err = putPlainAttribute (metaBkt , & keyBuf , id , object .FilterRoot , binPropMarker ); err != nil {
103+ return err
104+ }
105+ }
106+ if phy {
107+ if err = putPlainAttribute (metaBkt , & keyBuf , id , object .FilterPhysical , binPropMarker ); err != nil {
108+ return err
109+ }
110+ }
99111 for i := range attrs {
100112 ak , av := attrs [i ].Key (), attrs [i ].Value ()
101113 if n , isInt := parseInt (av ); isInt && n .Cmp (maxUint256Neg ) >= 0 && n .Cmp (maxUint256 ) <= 0 {
@@ -195,7 +207,7 @@ func (db *DB) search(cnr cid.ID, fs object.SearchFilters, attrs []string, cursor
195207func (db * DB ) searchInBucket (metaBkt * bbolt.Bucket , fs object.SearchFilters , attrs []string ,
196208 cursor * SearchCursor , count uint16 ) ([]client.SearchResultItem , * SearchCursor , error ) {
197209 // TODO: make as much as possible outside the Bolt tx
198- primMatcher := fs [0 ]. Operation ( )
210+ primMatcher , primVal := convertFilterValue ( fs [0 ])
199211 intPrimMatcher := isNumericOp (primMatcher )
200212 notPresentPrimMatcher := primMatcher == object .MatchNotPresent
201213 primAttr := fs [0 ].Header () // attribute emptiness already prevented
@@ -223,7 +235,7 @@ func (db *DB) searchInBucket(metaBkt *bbolt.Bucket, fs object.SearchFilters, att
223235 if primMatcher == object .MatchStringEqual || primMatcher == object .MatchCommonPrefix ||
224236 primMatcher == object .MatchNumGT || primMatcher == object .MatchNumGE {
225237 var err error
226- if primSeekKey , primSeekPrefix , err = seekKeyForAttribute (primAttr , fs [ 0 ]. Value () ); err != nil {
238+ if primSeekKey , primSeekPrefix , err = seekKeyForAttribute (primAttr , primVal ); err != nil {
227239 return nil , nil , fmt .Errorf ("invalid primary filter value: %w" , err )
228240 }
229241 } else {
@@ -279,11 +291,12 @@ nextPrimKey:
279291 if i > 0 && attr != primAttr {
280292 continue
281293 }
282- checkedDBVal , fltVal , err := combineValues (attr , dbVal , fs [i ].Value ()) // TODO: deduplicate DB value preparation
294+ mch , val := convertFilterValue (fs [i ])
295+ checkedDBVal , fltVal , err := combineValues (attr , dbVal , val ) // TODO: deduplicate DB value preparation
283296 if err != nil {
284297 return nil , nil , fmt .Errorf ("invalid key in meta bucket: invalid attribute %s value: %w" , attr , err )
285298 }
286- if ! matchValues (checkedDBVal , fs [ i ]. Operation () , fltVal ) {
299+ if ! matchValues (checkedDBVal , mch , fltVal ) {
287300 continue nextPrimKey
288301 }
289302 // TODO: attribute value can be requested, it can be collected here, or we can
@@ -311,7 +324,7 @@ nextPrimKey:
311324 if j > 0 && fs [j ].Header () != attr {
312325 continue
313326 }
314- m := fs [j ]. Operation ( )
327+ m , val := convertFilterValue ( fs [j ])
315328 if dbVal == nil {
316329 if m == object .MatchNotPresent {
317330 continue
@@ -347,7 +360,7 @@ nextPrimKey:
347360 } else {
348361 checkedDBVal = dbVal
349362 }
350- checkedDBVal , fltVal , err := combineValues (attr , checkedDBVal , fs [ j ]. Value () ) // TODO: deduplicate DB value preparation
363+ checkedDBVal , fltVal , err := combineValues (attr , checkedDBVal , val ) // TODO: deduplicate DB value preparation
351364 if err != nil {
352365 return nil , nil , invalidMetaBucketKeyErr (primKey , fmt .Errorf ("invalid attribute %s value: %w" , attr , err ))
353366 }
@@ -507,7 +520,7 @@ func seekKeyForAttribute(attr, fltVal string) ([]byte, []byte, error) {
507520 return nil , nil , fmt .Errorf ("decode %q UUID attribute: %w" , attr , err )
508521 }
509522 dbVal = uid [:]
510- case object .FilterVersion , object .FilterType :
523+ case object .FilterVersion , object .FilterType , object . FilterRoot , object . FilterPhysical :
511524 }
512525 key := make ([]byte , 1 + len (attr )+ utf8DelimiterLen + len (dbVal )) // prefix 1st
513526 key [0 ] = metaPrefixAttrIDPlain
@@ -794,3 +807,10 @@ func (x *metaAttributeSeeker) restoreVal(id []byte, attr string, stored []byte)
794807 }
795808 return string (stored ), nil
796809}
810+
811+ func convertFilterValue (f object.SearchFilter ) (object.SearchMatchType , string ) {
812+ if attr := f .Header (); attr == object .FilterRoot || attr == object .FilterPhysical {
813+ return object .MatchStringEqual , binPropMarker
814+ }
815+ return f .Operation (), f .Value ()
816+ }
0 commit comments