@@ -45,6 +45,10 @@ import (
4545 "golang.org/x/net/trace"
4646)
4747
48+ // maxVlogFileSize is the maximum size of the vlog file which can be created. Vlog Offset is of
49+ // uint32, so limiting at max uint32.
50+ var maxVlogFileSize = math .MaxUint32
51+
4852// Values have their first byte being byteData or byteDelete. This helps us distinguish between
4953// a key that has never been seen and a key that has been explicitly deleted.
5054const (
@@ -1364,11 +1368,52 @@ func (vlog *valueLog) woffset() uint32 {
13641368 return atomic .LoadUint32 (& vlog .writableLogOffset )
13651369}
13661370
1371+ // validateWrites will check whether the given requests can fit into 4GB vlog file.
1372+ // NOTE: 4GB is the maximum size we can create for vlog because value pointer offset is of type
1373+ // uint32. If we create more than 4GB, it will overflow uint32. So, limiting the size to 4GB.
1374+ func (vlog * valueLog ) validateWrites (reqs []* request ) error {
1375+ vlogOffset := uint64 (vlog .woffset ())
1376+ for _ , req := range reqs {
1377+ // calculate size of the request.
1378+ size := estimateRequestSize (req )
1379+ estimatedVlogOffset := vlogOffset + size
1380+ if estimatedVlogOffset > uint64 (maxVlogFileSize ) {
1381+ return errors .Errorf ("Request size offset %d is bigger than maximum offset %d" ,
1382+ estimatedVlogOffset , maxVlogFileSize )
1383+ }
1384+
1385+ if estimatedVlogOffset >= uint64 (vlog .opt .ValueLogFileSize ) {
1386+ // We'll create a new vlog file if the estimated offset is greater or equal to
1387+ // max vlog size. So, resetting the vlogOffset.
1388+ vlogOffset = 0
1389+ continue
1390+ }
1391+ // Estimated vlog offset will become current vlog offset if the vlog is not rotated.
1392+ vlogOffset = estimatedVlogOffset
1393+ }
1394+ return nil
1395+ }
1396+
1397+ // estimateRequestSize returns the size that needed to be written for the given request.
1398+ func estimateRequestSize (req * request ) uint64 {
1399+ size := uint64 (0 )
1400+ for _ , e := range req .Entries {
1401+ size += uint64 (maxHeaderSize + len (e .Key ) + len (e .Value ) + crc32 .Size )
1402+ }
1403+ return size
1404+ }
1405+
13671406// write is thread-unsafe by design and should not be called concurrently.
13681407func (vlog * valueLog ) write (reqs []* request ) error {
13691408 if vlog .db .opt .InMemory {
13701409 return nil
13711410 }
1411+ // Validate writes before writing to vlog. Because, we don't want to partially write and return
1412+ // an error.
1413+ if err := vlog .validateWrites (reqs ); err != nil {
1414+ return err
1415+ }
1416+
13721417 vlog .filesLock .RLock ()
13731418 maxFid := vlog .maxFid
13741419 curlf := vlog .filesMap [maxFid ]
0 commit comments