forked from TrueCloudLab/frostfs-node
[#1149] writecache: Prevent corruption in Head
Also, remove optimization comments: 1. Having to maintain an execute the same logic for headers as for objects is quite inefficient, as it increases memory footprint. 2. Unmarshaling object is a cheap operation if data slice is in memory. 3. For unmarshaling header-only, I think we need SDK support. Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
ff1912aa2a
commit
48eb87d32c
1 changed files with 6 additions and 9 deletions
|
@ -16,9 +16,13 @@ func (c *cache) Get(addr *addressSDK.Address) (*objectSDK.Object, error) {
|
||||||
c.mtx.RLock()
|
c.mtx.RLock()
|
||||||
for i := range c.mem {
|
for i := range c.mem {
|
||||||
if saddr == c.mem[i].addr {
|
if saddr == c.mem[i].addr {
|
||||||
obj := c.mem[i].obj
|
data := c.mem[i].data
|
||||||
c.mtx.RUnlock()
|
c.mtx.RUnlock()
|
||||||
return obj, nil
|
// We unmarshal object instead of using cached value to avoid possibility
|
||||||
|
// of unintentional object corruption by caller.
|
||||||
|
// It is safe to unmarshal without mutex, as storage under `c.mem[i].data` slices is not reused.
|
||||||
|
obj := objectSDK.New()
|
||||||
|
return obj, obj.Unmarshal(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.mtx.RUnlock()
|
c.mtx.RUnlock()
|
||||||
|
@ -50,18 +54,11 @@ func (c *cache) Get(addr *addressSDK.Address) (*objectSDK.Object, error) {
|
||||||
//
|
//
|
||||||
// Returns an error of type apistatus.ObjectNotFound if requested object is missing in write-cache.
|
// Returns an error of type apistatus.ObjectNotFound if requested object is missing in write-cache.
|
||||||
func (c *cache) Head(addr *addressSDK.Address) (*objectSDK.Object, error) {
|
func (c *cache) Head(addr *addressSDK.Address) (*objectSDK.Object, error) {
|
||||||
// TODO: #1149 easiest to implement solution is presented here, consider more efficient way, e.g.:
|
|
||||||
// - provide header as common object.Object to Put, but marked to prevent correlation with full object
|
|
||||||
// (all write-cache logic will automatically spread to headers, except flushing)
|
|
||||||
// - cut header from in-memory objects directly and persist headers into particular bucket of DB
|
|
||||||
// (explicit sync with full objects is needed)
|
|
||||||
// - try to pull out binary header from binary full object (not sure if it is possible)
|
|
||||||
obj, err := c.Get(addr)
|
obj, err := c.Get(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: resetting the payload via the setter can lead to data corruption of in-memory objects, but ok for others
|
|
||||||
return obj.CutPayload(), nil
|
return obj.CutPayload(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue