You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							336 lines
						
					
					
						
							7.0 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							336 lines
						
					
					
						
							7.0 KiB
						
					
					
				
								package skiplist
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"bytes"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								type NameList struct {
							 | 
						|
									skipList  *SkipList
							 | 
						|
									batchSize int
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func newNameList(store ListStore, batchSize int) *NameList {
							 | 
						|
									return &NameList{
							 | 
						|
										skipList:  New(store),
							 | 
						|
										batchSize: batchSize,
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/*
							 | 
						|
								Be reluctant to create new nodes. Try to fit into either previous node or next node.
							 | 
						|
								Prefer to add to previous node.
							 | 
						|
								
							 | 
						|
								There are multiple cases after finding the name for greater or equal node
							 | 
						|
								
							 | 
						|
								 1. found and node.Key == name
							 | 
						|
								    The node contains a batch with leading key the same as the name
							 | 
						|
								    nothing to do
							 | 
						|
								
							 | 
						|
								 2. no such node found or node.Key > name
							 | 
						|
								
							 | 
						|
								    if no such node found
							 | 
						|
								    prevNode = list.LargestNode
							 | 
						|
								
							 | 
						|
								    // case 2.1
							 | 
						|
								    if previousNode contains name
							 | 
						|
								    nothing to do
							 | 
						|
								
							 | 
						|
								    // prefer to add to previous node
							 | 
						|
								    if prevNode != nil {
							 | 
						|
								    // case 2.2
							 | 
						|
								    if prevNode has capacity
							 | 
						|
								    prevNode.add name, and save
							 | 
						|
								    return
							 | 
						|
								    // case 2.3
							 | 
						|
								    split prevNode by name
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // case 2.4
							 | 
						|
								    // merge into next node. Avoid too many nodes if adding data in reverse order.
							 | 
						|
								    if nextNode is not nil and nextNode has capacity
							 | 
						|
								    delete nextNode.Key
							 | 
						|
								    nextNode.Key = name
							 | 
						|
								    nextNode.batch.add name
							 | 
						|
								    insert nodeNode.Key
							 | 
						|
								    return
							 | 
						|
								
							 | 
						|
								    // case 2.5
							 | 
						|
								    if prevNode is nil
							 | 
						|
								    insert new node with key = name, value = batch{name}
							 | 
						|
								    return
							 | 
						|
								*/
							 | 
						|
								func (nl *NameList) WriteName(name string) error {
							 | 
						|
								
							 | 
						|
									lookupKey := []byte(name)
							 | 
						|
									prevNode, nextNode, found, err := nl.skipList.FindGreaterOrEqual(lookupKey)
							 | 
						|
									if err != nil {
							 | 
						|
										return err
							 | 
						|
									}
							 | 
						|
									// case 1: the name already exists as one leading key in the batch
							 | 
						|
									if found && bytes.Compare(nextNode.Key, lookupKey) == 0 {
							 | 
						|
										return nil
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if !found {
							 | 
						|
										prevNode, err = nl.skipList.GetLargestNode()
							 | 
						|
										if err != nil {
							 | 
						|
											return err
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if nextNode != nil && prevNode == nil {
							 | 
						|
										prevNode, err = nl.skipList.LoadElement(nextNode.Prev)
							 | 
						|
										if err != nil {
							 | 
						|
											return err
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if prevNode != nil {
							 | 
						|
										prevNameBatch := LoadNameBatch(prevNode.Value)
							 | 
						|
										// case 2.1
							 | 
						|
										if prevNameBatch.ContainsName(name) {
							 | 
						|
											return nil
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// case 2.2
							 | 
						|
										if len(prevNameBatch.names) < nl.batchSize {
							 | 
						|
											prevNameBatch.WriteName(name)
							 | 
						|
											return nl.skipList.ChangeValue(prevNode, prevNameBatch.ToBytes())
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										// case 2.3
							 | 
						|
										x, y := prevNameBatch.SplitBy(name)
							 | 
						|
										addToX := len(x.names) <= len(y.names)
							 | 
						|
										if len(x.names) != len(prevNameBatch.names) {
							 | 
						|
											if addToX {
							 | 
						|
												x.WriteName(name)
							 | 
						|
											}
							 | 
						|
											if x.key == prevNameBatch.key {
							 | 
						|
												if err := nl.skipList.ChangeValue(prevNode, x.ToBytes()); err != nil {
							 | 
						|
													return err
							 | 
						|
												}
							 | 
						|
											} else {
							 | 
						|
												if _, err := nl.skipList.InsertByKey([]byte(x.key), 0, x.ToBytes()); err != nil {
							 | 
						|
													return err
							 | 
						|
												}
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
										if len(y.names) != len(prevNameBatch.names) {
							 | 
						|
											if !addToX {
							 | 
						|
												y.WriteName(name)
							 | 
						|
											}
							 | 
						|
											if y.key == prevNameBatch.key {
							 | 
						|
												if err := nl.skipList.ChangeValue(prevNode, y.ToBytes()); err != nil {
							 | 
						|
													return err
							 | 
						|
												}
							 | 
						|
											} else {
							 | 
						|
												if _, err := nl.skipList.InsertByKey([]byte(y.key), 0, y.ToBytes()); err != nil {
							 | 
						|
													return err
							 | 
						|
												}
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
										return nil
							 | 
						|
								
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// case 2.4
							 | 
						|
									if nextNode != nil {
							 | 
						|
										nextNameBatch := LoadNameBatch(nextNode.Value)
							 | 
						|
										if len(nextNameBatch.names) < nl.batchSize {
							 | 
						|
											if _, err := nl.skipList.DeleteByKey(nextNode.Key); err != nil {
							 | 
						|
												return err
							 | 
						|
											}
							 | 
						|
											nextNameBatch.WriteName(name)
							 | 
						|
											if _, err := nl.skipList.InsertByKey([]byte(nextNameBatch.key), 0, nextNameBatch.ToBytes()); err != nil {
							 | 
						|
												return err
							 | 
						|
											}
							 | 
						|
											return nil
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// case 2.5
							 | 
						|
									// now prevNode is nil
							 | 
						|
									newNameBatch := NewNameBatch()
							 | 
						|
									newNameBatch.WriteName(name)
							 | 
						|
									if _, err := nl.skipList.InsertByKey([]byte(newNameBatch.key), 0, newNameBatch.ToBytes()); err != nil {
							 | 
						|
										return err
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									return nil
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/*
							 | 
						|
								// case 1: exists in nextNode
							 | 
						|
								
							 | 
						|
									if nextNode != nil && nextNode.Key == name {
							 | 
						|
										remove from nextNode, update nextNode
							 | 
						|
										// TODO: merge with prevNode if possible?
							 | 
						|
										return
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
								if nextNode is nil
							 | 
						|
								
							 | 
						|
									prevNode = list.Largestnode
							 | 
						|
								
							 | 
						|
								if prevNode == nil and nextNode.Prev != nil
							 | 
						|
								
							 | 
						|
									prevNode = load(nextNode.Prev)
							 | 
						|
								
							 | 
						|
								// case 2: does not exist
							 | 
						|
								// case 2.1
							 | 
						|
								
							 | 
						|
									if prevNode == nil {
							 | 
						|
										return
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
								// case 2.2
							 | 
						|
								
							 | 
						|
									if prevNameBatch does not contain name {
							 | 
						|
										return
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
								// case 3
							 | 
						|
								delete from prevNameBatch
							 | 
						|
								if prevNameBatch + nextNode < capacityList
							 | 
						|
								
							 | 
						|
									// case 3.1
							 | 
						|
									merge
							 | 
						|
								
							 | 
						|
								else
							 | 
						|
								
							 | 
						|
									// case 3.2
							 | 
						|
									update prevNode
							 | 
						|
								*/
							 | 
						|
								func (nl *NameList) DeleteName(name string) error {
							 | 
						|
									lookupKey := []byte(name)
							 | 
						|
									prevNode, nextNode, found, err := nl.skipList.FindGreaterOrEqual(lookupKey)
							 | 
						|
									if err != nil {
							 | 
						|
										return err
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// case 1
							 | 
						|
									var nextNameBatch *NameBatch
							 | 
						|
									if nextNode != nil {
							 | 
						|
										nextNameBatch = LoadNameBatch(nextNode.Value)
							 | 
						|
									}
							 | 
						|
									if found && bytes.Compare(nextNode.Key, lookupKey) == 0 {
							 | 
						|
										if _, err := nl.skipList.DeleteByKey(nextNode.Key); err != nil {
							 | 
						|
											return err
							 | 
						|
										}
							 | 
						|
										nextNameBatch.DeleteName(name)
							 | 
						|
										if len(nextNameBatch.names) > 0 {
							 | 
						|
											if _, err := nl.skipList.InsertByKey([]byte(nextNameBatch.key), 0, nextNameBatch.ToBytes()); err != nil {
							 | 
						|
												return err
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
										return nil
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if !found {
							 | 
						|
										prevNode, err = nl.skipList.GetLargestNode()
							 | 
						|
										if err != nil {
							 | 
						|
											return err
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if nextNode != nil && prevNode == nil {
							 | 
						|
										prevNode, err = nl.skipList.LoadElement(nextNode.Prev)
							 | 
						|
										if err != nil {
							 | 
						|
											return err
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// case 2
							 | 
						|
									if prevNode == nil {
							 | 
						|
										// case 2.1
							 | 
						|
										return nil
							 | 
						|
									}
							 | 
						|
									prevNameBatch := LoadNameBatch(prevNode.Value)
							 | 
						|
									if !prevNameBatch.ContainsName(name) {
							 | 
						|
										// case 2.2
							 | 
						|
										return nil
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// case 3
							 | 
						|
									prevNameBatch.DeleteName(name)
							 | 
						|
									if len(prevNameBatch.names) == 0 {
							 | 
						|
										if _, err := nl.skipList.DeleteByKey(prevNode.Key); err != nil {
							 | 
						|
											return err
							 | 
						|
										}
							 | 
						|
										return nil
							 | 
						|
									}
							 | 
						|
									if nextNameBatch != nil && len(nextNameBatch.names)+len(prevNameBatch.names) < nl.batchSize {
							 | 
						|
										// case 3.1 merge nextNode and prevNode
							 | 
						|
										if _, err := nl.skipList.DeleteByKey(nextNode.Key); err != nil {
							 | 
						|
											return err
							 | 
						|
										}
							 | 
						|
										for nextName := range nextNameBatch.names {
							 | 
						|
											prevNameBatch.WriteName(nextName)
							 | 
						|
										}
							 | 
						|
										return nl.skipList.ChangeValue(prevNode, prevNameBatch.ToBytes())
							 | 
						|
									} else {
							 | 
						|
										// case 3.2 update prevNode
							 | 
						|
										return nl.skipList.ChangeValue(prevNode, prevNameBatch.ToBytes())
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									return nil
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func (nl *NameList) ListNames(startFrom string, visitNamesFn func(name string) bool) error {
							 | 
						|
									lookupKey := []byte(startFrom)
							 | 
						|
									prevNode, nextNode, found, err := nl.skipList.FindGreaterOrEqual(lookupKey)
							 | 
						|
									if err != nil {
							 | 
						|
										return err
							 | 
						|
									}
							 | 
						|
									if found && bytes.Compare(nextNode.Key, lookupKey) == 0 {
							 | 
						|
										prevNode = nil
							 | 
						|
									}
							 | 
						|
									if !found {
							 | 
						|
										prevNode, err = nl.skipList.GetLargestNode()
							 | 
						|
										if err != nil {
							 | 
						|
											return err
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if prevNode != nil {
							 | 
						|
										prevNameBatch := LoadNameBatch(prevNode.Value)
							 | 
						|
										if !prevNameBatch.ListNames(startFrom, visitNamesFn) {
							 | 
						|
											return nil
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									for nextNode != nil {
							 | 
						|
										nextNameBatch := LoadNameBatch(nextNode.Value)
							 | 
						|
										if !nextNameBatch.ListNames(startFrom, visitNamesFn) {
							 | 
						|
											return nil
							 | 
						|
										}
							 | 
						|
										nextNode, err = nl.skipList.LoadElement(nextNode.Next[0])
							 | 
						|
										if err != nil {
							 | 
						|
											return err
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									return nil
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func (nl *NameList) RemoteAllListElement() error {
							 | 
						|
								
							 | 
						|
									t := nl.skipList
							 | 
						|
								
							 | 
						|
									nodeRef := t.StartLevels[0]
							 | 
						|
									for nodeRef != nil {
							 | 
						|
										node, err := t.LoadElement(nodeRef)
							 | 
						|
										if err != nil {
							 | 
						|
											return err
							 | 
						|
										}
							 | 
						|
										if node == nil {
							 | 
						|
											return nil
							 | 
						|
										}
							 | 
						|
										if err := t.DeleteElement(node); err != nil {
							 | 
						|
											return err
							 | 
						|
										}
							 | 
						|
										nodeRef = node.Next[0]
							 | 
						|
									}
							 | 
						|
									return nil
							 | 
						|
								
							 | 
						|
								}
							 |