func TestCacheMapSimple(t *testing.T) { mocklog := make(chan *message.Message) // This service will run in its own goroutine // and send to mocklog any messages pipeline := message.NewNullPipeline(mocklog) pipeline.Start() defer pipeline.Close() c := NewCacheMap(8, 4096, pipeline.In) tests.Assert(t, c != nil) here := make(chan *message.Message) buffer := make([]byte, 4096) m := message.NewMsgPut() m.RetChan = here io := m.IoPkt() io.Buffer = buffer io.Address = 1 m.Priv = c // First Put err := c.Put(m) tests.Assert(t, err == nil) logmsg := <-mocklog logio := logmsg.IoPkt() tests.Assert(t, m.Type == logmsg.Type) tests.Assert(t, logmsg.Priv.(*CacheMap) == c) tests.Assert(t, io.Blocks == logio.Blocks) tests.Assert(t, io.Address == logio.Address) tests.Assert(t, logio.LogBlock == 0) logmsg.Done() returnedmsg := <-here rio := returnedmsg.IoPkt() tests.Assert(t, m.Type == returnedmsg.Type) tests.Assert(t, returnedmsg.Priv.(*CacheMap) == c) tests.Assert(t, io.Blocks == rio.Blocks) tests.Assert(t, io.Address == rio.Address) tests.Assert(t, c.stats.insertions == 1) tests.Assert(t, returnedmsg.Err == nil) val, ok := c.addressmap[io.Address] tests.Assert(t, val == 0) tests.Assert(t, ok == true) // Check that we cannot resend this message err = c.Put(m) tests.Assert(t, err == message.ErrMessageUsed) // Insert again. Should allocate // next block m = message.NewMsgPut() m.RetChan = here io = m.IoPkt() io.Buffer = buffer io.Address = 1 m.Priv = c err = c.Put(m) tests.Assert(t, err == nil) logmsg = <-mocklog logio = logmsg.IoPkt() tests.Assert(t, logio.LogBlock == 1) logmsg.Done() returnedmsg = <-here rio = returnedmsg.IoPkt() tests.Assert(t, returnedmsg.Err == nil) tests.Assert(t, c.stats.insertions == 2) val, ok = c.addressmap[io.Address] tests.Assert(t, val == 1) tests.Assert(t, ok == true) // Send a Get mg := message.NewMsgGet() io = mg.IoPkt() io.Address = 1 io.Buffer = buffer mg.RetChan = here hitmap, err := c.Get(mg) tests.Assert(t, err == nil) tests.Assert(t, hitmap.Hits == 1) tests.Assert(t, hitmap.Hitmap[0] == true) tests.Assert(t, hitmap.Hits == io.Blocks) logmsg = <-mocklog logio = logmsg.IoPkt() tests.Assert(t, logio.LogBlock == 1) logmsg.Done() returnedmsg = <-here io = returnedmsg.IoPkt() tests.Assert(t, returnedmsg.Err == nil) tests.Assert(t, c.stats.insertions == 2) tests.Assert(t, c.stats.readhits == 1) tests.Assert(t, c.stats.reads == 1) // Test we cannot send the same message hitmap, err = c.Get(mg) tests.Assert(t, err == message.ErrMessageUsed) tests.Assert(t, hitmap == nil) // Send Invalidate iopkt := &message.IoPkt{} iopkt.Address = 1 iopkt.Blocks = 1 c.Invalidate(iopkt) tests.Assert(t, c.stats.insertions == 2) tests.Assert(t, c.stats.readhits == 1) tests.Assert(t, c.stats.reads == 1) tests.Assert(t, c.stats.invalidations == 1) tests.Assert(t, c.stats.invalidatehits == 1) // Send Invalidate iopkt = &message.IoPkt{} iopkt.Address = 1 iopkt.Blocks = 1 c.Invalidate(iopkt) tests.Assert(t, c.stats.insertions == 2) tests.Assert(t, c.stats.readhits == 1) tests.Assert(t, c.stats.reads == 1) tests.Assert(t, c.stats.invalidations == 2) tests.Assert(t, c.stats.invalidatehits == 1) // Send a Get again, but it should not be there mg = message.NewMsgGet() io = mg.IoPkt() io.Address = 1 io.Buffer = buffer mg.RetChan = here hitmap, err = c.Get(mg) tests.Assert(t, err == ErrNotFound) tests.Assert(t, hitmap == nil) tests.Assert(t, c.stats.insertions == 2) tests.Assert(t, c.stats.readhits == 1) tests.Assert(t, c.stats.reads == 2) tests.Assert(t, c.stats.invalidations == 2) tests.Assert(t, c.stats.invalidatehits == 1) // Check the stats stats := c.Stats() tests.Assert(t, stats.Readhits == c.stats.readhits) tests.Assert(t, stats.Invalidatehits == c.stats.invalidatehits) tests.Assert(t, stats.Reads == c.stats.reads) tests.Assert(t, stats.Evictions == c.stats.evictions) tests.Assert(t, stats.Invalidations == c.stats.invalidations) tests.Assert(t, stats.Insertions == c.stats.insertions) // Clear the stats c.StatsClear() tests.Assert(t, 0 == c.stats.readhits) tests.Assert(t, 0 == c.stats.invalidatehits) tests.Assert(t, 0 == c.stats.reads) tests.Assert(t, 0 == c.stats.evictions) tests.Assert(t, 0 == c.stats.invalidations) tests.Assert(t, 0 == c.stats.insertions) c.Close() }
// This test will check that the cache tries to place // as many contigous blocks as possible. We will initialize // the 8 slot cache with four slots, then remove slot 1 and 2 // to leave the following: [X__X____] // When we put a message with 6 blocks the cache should be // populated as follows: [X45X01234] // // At the end, check multiblock Get() // func TestCacheMapMultiblock(t *testing.T) { // This service will run in its own goroutine // and send to mocklog any messages mocklog := make(chan *message.Message) pipe := message.NewNullPipeline(mocklog) pipe.Start() defer pipe.Close() c := NewCacheMap(8, 4096, pipe.In) tests.Assert(t, c != nil) here := make(chan *message.Message) buffer := make([]byte, 4096) // Initialize data in cache for i := uint64(0); i < 4; i++ { m := message.NewMsgPut() m.RetChan = here io := m.IoPkt() io.Buffer = buffer io.Address = i // First Put err := c.Put(m) tests.Assert(t, err == nil) retmsg := <-mocklog retmsg.Done() <-here } c.Invalidate(&message.IoPkt{Address: 1, Blocks: 2}) tests.Assert(t, c.stats.insertions == 4) tests.Assert(t, c.stats.invalidatehits == 2) tests.Assert(t, c.bda.bds[0].used == true) tests.Assert(t, c.bda.bds[0].key == 0) tests.Assert(t, c.bda.bds[1].used == false) tests.Assert(t, c.bda.bds[2].used == false) tests.Assert(t, c.bda.bds[3].used == true) tests.Assert(t, c.bda.bds[3].key == 3) // Set the clock so they do not get erased c.bda.bds[0].clock_set = true c.bda.bds[3].clock_set = true // Insert multiblock largebuffer := make([]byte, 6*4096) m := message.NewMsgPut() m.RetChan = here io := m.IoPkt() io.Buffer = largebuffer io.Address = 10 io.Blocks = 6 // First Put err := c.Put(m) tests.Assert(t, err == nil) for i := uint32(0); i < io.Blocks; i++ { // Put send a message for each block retmsg := <-mocklog retmsg.Done() } <-here tests.Assert(t, c.stats.insertions == 10) tests.Assert(t, c.stats.invalidatehits == 2) // Check the two blocks left from before tests.Assert(t, c.bda.bds[0].used == true) tests.Assert(t, c.bda.bds[0].key == 0) tests.Assert(t, c.bda.bds[0].clock_set == false) tests.Assert(t, c.bda.bds[3].used == true) tests.Assert(t, c.bda.bds[3].key == 3) tests.Assert(t, c.bda.bds[3].clock_set == true) // Now check the blocks we inserted tests.Assert(t, c.bda.bds[4].used == true) tests.Assert(t, c.bda.bds[4].key == 10) tests.Assert(t, c.bda.bds[4].clock_set == false) tests.Assert(t, c.bda.bds[5].used == true) tests.Assert(t, c.bda.bds[5].key == 11) tests.Assert(t, c.bda.bds[5].clock_set == false) tests.Assert(t, c.bda.bds[6].used == true) tests.Assert(t, c.bda.bds[6].key == 12) tests.Assert(t, c.bda.bds[6].clock_set == false) tests.Assert(t, c.bda.bds[7].used == true) tests.Assert(t, c.bda.bds[7].key == 13) tests.Assert(t, c.bda.bds[7].clock_set == false) tests.Assert(t, c.bda.bds[1].used == true) tests.Assert(t, c.bda.bds[1].key == 14) tests.Assert(t, c.bda.bds[1].clock_set == false) tests.Assert(t, c.bda.bds[2].used == true) tests.Assert(t, c.bda.bds[2].key == 15) tests.Assert(t, c.bda.bds[2].clock_set == false) // Check for a block not in the cache m = message.NewMsgGet() m.RetChan = here io = m.IoPkt() io.Buffer = buffer io.Address = 20 io.Blocks = 1 hitmap, err := c.Get(m) tests.Assert(t, err == ErrNotFound) tests.Assert(t, hitmap == nil) tests.Assert(t, len(here) == 0) // Get offset 0, 4 blocks. It should return // a bit map of [1001] buffer4 := make([]byte, 4*4096) m = message.NewMsgGet() m.RetChan = here io = m.IoPkt() io.Buffer = buffer4 io.Address = 0 io.Blocks = 4 hitmap, err = c.Get(m) tests.Assert(t, err == nil) tests.Assert(t, hitmap.Hits == 2) tests.Assert(t, len(hitmap.Hitmap) == int(io.Blocks)) tests.Assert(t, hitmap.Hitmap[0] == true) tests.Assert(t, hitmap.Hitmap[1] == false) tests.Assert(t, hitmap.Hitmap[2] == false) tests.Assert(t, hitmap.Hitmap[3] == true) for i := 0; i < 2; i++ { // Get sends a get for each contiguous blocks retmsg := <-mocklog retmsg.Done() } <-here // Get the 6 blocks we inserted previously. This // should show that there are two sets of continguous // blocks m = message.NewMsgGet() m.RetChan = here io = m.IoPkt() io.Buffer = largebuffer io.Address = 10 io.Blocks = 6 hitmap, err = c.Get(m) tests.Assert(t, err == nil) tests.Assert(t, hitmap.Hits == 6) tests.Assert(t, len(hitmap.Hitmap) == int(io.Blocks)) tests.Assert(t, hitmap.Hitmap[0] == true) tests.Assert(t, hitmap.Hitmap[1] == true) tests.Assert(t, hitmap.Hitmap[2] == true) tests.Assert(t, hitmap.Hitmap[3] == true) tests.Assert(t, hitmap.Hitmap[4] == true) tests.Assert(t, hitmap.Hitmap[5] == true) // The first message to the log retmsg := <-mocklog retio := retmsg.IoPkt() tests.Assert(t, retmsg.RetChan == nil) tests.Assert(t, retio.Address == 10) tests.Assert(t, retio.LogBlock == 4) tests.Assert(t, retio.Blocks == 4) retmsg.Done() // Second message will have the rest of the contigous block retmsg = <-mocklog retio = retmsg.IoPkt() tests.Assert(t, retmsg.RetChan == nil) tests.Assert(t, retio.Address == 14) tests.Assert(t, retio.LogBlock == 1) tests.Assert(t, retio.Blocks == 2) retmsg.Done() <-here // Save the cache metadata save := tests.Tempfile() defer os.Remove(save) err = c.Save(save, nil) tests.Assert(t, err == nil) c.Close() c = NewCacheMap(8, 4096, pipe.In) tests.Assert(t, c != nil) err = c.Load(save, nil) tests.Assert(t, err == nil) // Get data again. m = message.NewMsgGet() m.RetChan = here io = m.IoPkt() io.Buffer = largebuffer io.Address = 10 io.Blocks = 6 hitmap, err = c.Get(m) tests.Assert(t, err == nil) tests.Assert(t, hitmap.Hits == 6) tests.Assert(t, len(hitmap.Hitmap) == int(io.Blocks)) tests.Assert(t, hitmap.Hitmap[0] == true) tests.Assert(t, hitmap.Hitmap[1] == true) tests.Assert(t, hitmap.Hitmap[2] == true) tests.Assert(t, hitmap.Hitmap[3] == true) tests.Assert(t, hitmap.Hitmap[4] == true) tests.Assert(t, hitmap.Hitmap[5] == true) // The first message to the log retmsg = <-mocklog retio = retmsg.IoPkt() tests.Assert(t, retmsg.RetChan == nil) tests.Assert(t, retio.Address == 10) tests.Assert(t, retio.LogBlock == 4) tests.Assert(t, retio.Blocks == 4) retmsg.Done() // Second message will have the rest of the contigous block retmsg = <-mocklog retio = retmsg.IoPkt() tests.Assert(t, retmsg.RetChan == nil) tests.Assert(t, retio.Address == 14) tests.Assert(t, retio.LogBlock == 1) tests.Assert(t, retio.Blocks == 2) retmsg.Done() <-here c.Close() }