Beispiel #1
0
        ///<summary>DBから読み込んだハッシュをそのままファイルに書き出す</summary>
        ///<param name="SaveTime">保存するファイル名に付けるUNIX時刻</param>
        public async Task <long> AllMediaHash(long SaveTime)
        {
            try
            {
                long   TotalHashCount = 0;
                string HashFilePath   = HashFile.AllHashFilePathBase(SaveTime.ToString());
                using (var writer = new BufferedLongWriter(HashFile.TempFilePath(HashFilePath)))
                {
                    var LoadHashBlock = new TransformBlock <long, AddOnlyList <long> >(async(i) =>
                    {
                        var table = new AddOnlyList <long>(TableListSize);
                        while (true)
                        {
                            using var cmd = new MySqlCommand(@"SELECT DISTINCT dcthash
FROM media
WHERE dcthash BETWEEN @begin AND @end
GROUP BY dcthash;");
                            cmd.Parameters.Add("@begin", MySqlDbType.Int64).Value = i << HashUnitBits;
                            cmd.Parameters.Add("@end", MySqlDbType.Int64).Value   = ((i + 1) << HashUnitBits) - 1;
                            if (await ExecuteReader(cmd, (r) => table.Add(r.GetInt64(0)), IsolationLevel.ReadUncommitted).ConfigureAwait(false))
                            {
                                break;
                            }
                            else
                            {
                                table.Clear();
                            }
                        }
                        return(table);
                    }, new ExecutionDataflowBlockOptions()
                    {
                        MaxDegreeOfParallelism        = Environment.ProcessorCount,
                        BoundedCapacity               = Environment.ProcessorCount << 1,
                            SingleProducerConstrained = true
                    });
                    var WriterBlock = new ActionBlock <AddOnlyList <long> >(async(table) =>
                    {
                        await writer.Write(table.InnerArray, table.Count).ConfigureAwait(false);
                        TotalHashCount += table.Count;
                        table.Dispose();
                    }, new ExecutionDataflowBlockOptions()
                    {
                        MaxDegreeOfParallelism = 1
                    });
                    LoadHashBlock.LinkTo(WriterBlock, new DataflowLinkOptions()
                    {
                        PropagateCompletion = true
                    });


                    for (int i = 0; i < 1 << (64 - HashUnitBits); i++)
                    {
                        await LoadHashBlock.SendAsync(i).ConfigureAwait(false);
                    }
                    LoadHashBlock.Complete();
                    await WriterBlock.Completion.ConfigureAwait(false);
                }
                File.Move(HashFile.TempFilePath(HashFilePath), HashFilePath);
                return(TotalHashCount);
            }
            catch (Exception e) { Console.WriteLine(e); return(-1); }
        }
Beispiel #2
0
        ///<summary>ブロックソートで一致する範囲ごとに読み出す
        ///長さ2以上のやつは全部返す(NewHashが含まれてなくても返す)
        ///最後まで読み終わったらnull</summary>
        ///<returns>(要素数,実際の要素…)を繰り返し、要素数0で終わりを示すオレオレ配列</returns>
        public AddOnlyList <long> ReadBlocks()
        {
            var ReadBlockList = new AddOnlyList <long>(ReadBlockListSize);

            //ブロックソートで一致してる要素数
            int BlockCount = 0;
            //↑の値を入れるReadBlocks内の添字
            int BlockCountIndex = 0;
            //最初は絶対に一致させないように-1
            long MaskedKey = -1;
            //重複排除用
            //long PreviousValue = LastValue;

            int ValueIndex = LastIndex;

            while (0 < SortedMemory.Length)
            {
                //SortedMemoryはActualRead()毎に変わるのでここでSpanにする
                var SortedValues = SortedMemory.Span;

                for (; ValueIndex < SortedValues.Length; ValueIndex++)
                {
                    long Value = SortedValues[ValueIndex];

                    long MaskedValue = Value & SortMask;
                    if (MaskedKey == MaskedValue)
                    {
                        //Maskしたやつ同士が一致するなら普通に続きに加える
                        ReadBlockList.Add(Value);
                        BlockCount++;
                    }
                    else
                    {   //Maskしたやつが一致しない場合はオレオレ配列1サイクル分終了
                        MaskedKey = MaskedValue;
                        //2要素以上あれば確定して次のサイクルに進む
                        if (1 < BlockCount)
                        {
                            ReadBlockList.InnerArray[BlockCountIndex] = BlockCount;
                            BlockCountIndex = ReadBlockList.Count;
                            //とりあえず次のサイクルの要素数のダミーを入れる
                            ReadBlockList.Add(0);
                            //十分な要素数が入ってたらここで終了(↑のAdd(0)は終端を示す0になる)
                            if (BlockElementsMin < ReadBlockList.Count)
                            {
                                //SortedValues[ValueIndex]の値を使わなかったので次回に回す
                                LastIndex = ValueIndex;
                                return(ReadBlockList);
                            }
                            ReadBlockList.Add(Value);
                            BlockCount = 1;
                        }
                        //1要素しかないものは無意味なので除外→次の要素で上書き
                        else if (BlockCount == 1)
                        {
                            ReadBlockList.ReplaceTail(Value);
                        }
                        //最初だけ必ずここに入る
                        else
                        {
                            //先頭の要素数のダミーを入れる
                            ReadBlockList.Add(0);
                            ReadBlockList.Add(Value);
                            BlockCount = 1;
                        }
                    }
                    //PreviousValue = Value;
                }
                ActualRead();
                ValueIndex = 0;
            }
            //ここに来るのはファイルの読み込みが終わったときだけ
            //読み込み終了後の呼び出しならnullを返す必要がある
            if (ReadBlockList.Count == 0)
            {
                ReadBlockList.Dispose();
                return(null);
            }
            else
            {
                //終端に0をつけて完成
                ReadBlockList.Add(0);
                return(ReadBlockList);
            }
        }